Audit Logs
How to configure REFRACT PDF's audit system. Covers the basic (SharePoint JSONL) and blob (Azure Blob AppendBlob) audit tiers, the AuditEvent schema, file naming, and setup steps for each tier. The enterprise tier is withdrawn.
Overview
REFRACT PDF writes two distinct records for every render request:
| Record | Where | Purpose |
|---|---|---|
| JSONL audit trail | SharePoint Audit Logs library or Azure Blob | Comprehensive lifecycle log for compliance and troubleshooting |
| REFRACT_Activity item | SharePoint list | Human-readable render history browsable directly in SharePoint |
This page covers the JSONL audit trail. The Activity list is written automatically based on your SharePoint configuration -- no separate setup is required.
Choose an Audit Tier
Select your audit tier by setting auditLogs in storage-config.json. If you omit this setting, REFRACT PDF defaults to basic.
| Tier | Config value | Recommended for |
|---|---|---|
| Basic | 'basic' | Low-to-medium volume deployments already using SharePoint for output |
| Blob | 'blob' | Medium-to-high volume deployments, and audit logs in your audit-logs storage container |
Both tiers produce the same event schema and the same JSONL file format. The difference is where the files land.
The enterprise tier is withdrawn; see Enterprise Tier.
Tier comparison
| Feature | Basic | Blob |
|---|---|---|
| Where the files are written | SharePoint Audit Logs library | Azure Blob Storage (deployed on every install) |
| Concurrent render safety | Every write is conditional and a lost race is retried up to 5 times; an event is lost only if all 5 attempts lose, and that failure is logged | Safe |
| Suitable for high volume | No | Yes |
| Additional cost | None | Low (storage) |
Basic Tier (auditLogs: 'basic')
Audit events are appended to a JSONL file in the SharePoint Audit Logs library. No additional Azure infrastructure is required.
When to use
- Your deployment already routes all output to SharePoint
- Render volume is moderate (under ~50,000 events per month)
- You do not have strict compliance requirements for zero event loss
Setup
- Ensure the Audit Logs library exists in your SharePoint site and its drive ID is set in
sp-config.json:
{
"driveIds": {
"Audit Logs": "<drive-id>"
},
"features": {
"auditLogs": true
}
}- In
storage-config.json, either omitauditLogs(basic is the default) or set it explicitly:
{
"libraryRoutes": {
"auditLogs": "basic"
}
}Blob Tier (auditLogs: 'blob')
Audit events are written directly to an Azure Blob AppendBlob. This gives lower latency and safe concurrent writes from multiple render instances.
When to use
- You are already routing generated documents to Azure Blob
- You want audit logs in an Azure Storage container rather than a SharePoint library
- You want the audit files under your storage account's own retention and immutability settings (see Retention Policy)
Setup
- Create an
audit-logscontainer in your Azure Storage account. - Ensure the REFRACT PDF app's Managed Identity has Storage Blob Data Contributor on the storage account.
- Update
storage-config.json:
{
"libraryRoutes": {
"auditLogs": "blob"
},
"accountName": "your-storage-account",
"blobContainers": {
"auditLogs": "audit-logs"
}
}Enterprise Tier (auditLogs: 'enterprise'): withdrawn
This tier has been withdrawn and there is nothing to set up. Use the Blob Tier instead.
The enterprise audit tier (auditLogs: 'enterprise') is withdrawn. It was never available: no REFRACT installer deploys its Service Bus queue or its Audit Worker, and with this value audit events were written to the SharePoint Audit Logs library instead, with no immutability policy. Do not configure it. Starting with the release that withdraws it, a storage-config.json that names enterprise is refused: renders with audit logging fail with 503 and code AUDIT_TIER_WITHDRAWN until auditLogs is set to blob or basic. If you configured it, change it to blob. Events already written to the SharePoint library stay there; they are not moved.
AuditEvent Schema
All three tiers write events in the same format. Each line in a JSONL file is one event with no trailing comma.
Core fields (always present)
| Field | Type | Description |
|---|---|---|
correlationId | string | Unique ID for the render request |
action | string | Lifecycle step (see table below) |
status | string | 'Success', 'Failure', or 'Warning' |
timestamp | string | ISO 8601 timestamp |
Additional fields
| Field | Type | Description |
|---|---|---|
tenantId | string | null | SharePoint tenant identifier |
userId | string | null | Entra ID of the user who triggered the render |
templatePath | string | null | Relative path of the template used |
payloadPath | string | null | Relative path of the payload document |
outputPath | string | null | Destination path of the generated PDF |
fileSizeBytes | number | null | Size of the generated PDF in bytes |
durationMs | number | null | Render duration in milliseconds |
errorMessage | string | null | Error detail on status: 'Failure' |
templateVersion | string | null | Content hash or version label of the template |
extra | object | null | Arbitrary extension fields from the render payload |
Action values
| Value | Description |
|---|---|
'PayloadReceived' | Render request accepted and validated |
'PDFGenerated' | PDF created successfully |
'PDFGenerationFailed' | PDF generation failed |
'UploadStarted' | Upload to storage provider initiated |
'UploadCompleted' | Upload finished successfully |
'UploadFailed' | Upload failed |
'AuditWriteStarted' | Audit record write initiated |
'AuditWriteCompleted' | Audit record written and confirmed |
'AuditWriteFailed' | Audit record write failed |
'ActivityPosted' | REFRACT_Activity item created or updated |
Example event
{
"correlationId": "BC-INV-2026-03-31",
"action": "UploadCompleted",
"status": "Success",
"timestamp": "2026-03-31T14:22:03.451Z",
"userId": "user@contoso.onmicrosoft.com",
"templatePath": "/Templates/Invoice.rpkg",
"payloadPath": "/Payloads/BC-INV-2026-03-31.json",
"outputPath": "Invoice/2026/03/BC-INV-2026-03-31_Invoice_2026-03-31.pdf",
"blobSasUrl": "https://contosorefractstorage.blob.core.windows.net/generated-documents/Invoice/2026/03/...",
"fileSizeBytes": 84210,
"durationMs": 1203,
"errorMessage": null
}File Naming & Rotation
Audit files are scoped to calendar month and split into numbered parts when size thresholds are exceeded.
Naming pattern
audit-{YYYY}-{MM}-part{N}.jsonlExamples:
audit-2026-03-part1.jsonl
audit-2026-03-part2.jsonl
audit-2026-04-part1.jsonlWhere the files are written:
- Basic tier: the SharePoint Audit Logs library, in a folder per month:
{YYYY}/{MM}/audit-{YYYY}-{MM}-part{N}.jsonl. The first file of every month ispart1. - Blob tier: the
audit-logscontainer, at the container root:audit-{YYYY}-{MM}-part{N}.jsonl.
To read a month back, take every part and order them by N as a number: part10 comes after part9, while an alphabetical sort puts it after part1.
Rotation thresholds
A new part file is created before an event would pass any threshold:
| Threshold | Basic tier (SharePoint) | Blob tier |
|---|---|---|
| File size | 3.5 MB, so every write stays under the 4 MB SharePoint simple-upload limit | 50 MB |
| Events (one block each) | Unlimited | 45,000 committed blocks, below Azure's 50,000-block limit for an append blob. An append that still reaches the limit rolls to the next part and retries |
None of these thresholds can be configured.
At each month boundary, part numbering resets to 1 regardless of the current file size.
Related Pages
- Storage Providers -- configure SharePoint and Azure Blob output routing
- System Architecture -- how REFRACT PDF fits into your tenant
Storage Providers
How to configure REFRACT PDF's storage system. Covers SharePoint setup, Azure Blob Storage setup, output routing via storage-config.json, required environment variables, and the response headers returned on each render.
Dispatcher Deployment and Link Lifecycle
How your Dispatcher deployment relates to the signing, workflow, and delivery links your recipients receive, and what happens to outstanding links when you redeploy or move your Dispatcher.