---
title: "AuditLogger"
description: "Public methods on AuditLogger, including fire, query, maintenance, and stats."
---

> Documentation Index
> Fetch the complete documentation index at: https://logbun-docs.abshahin.workers.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# AuditLogger

Root import: `import { AuditLogger } from 'logbun'`.

Generic: `AuditLogger<TActions extends string = string>`.

## Constructor

```ts
new AuditLogger<TActions>(config: LogbunConfig<TActions>)
```

Synchronous throws:

- Durable mode without `reliability`, or with `persistent: false`
- `tenancy.mode === 'database_per_tenant'` without `adapterFactory`
- Invalid `retention.days`

See [Configuration](/reference/configuration).

## Members

| Member | Contract |
|---|---|
| `ready` | Bootstrap promise. **Never rejects.** Bootstrap failure sets `degraded` and emits `bootstrap_fail` / `degraded`. |
| `degraded` | `true` after bootstrap failure. `fire` drops; `fireAsync` / `query` / DLQ / flush / maintenance throw. |

## `fire(action, input, context?)`

Returns `void`, never throws. If provided, `context.waitUntil` receives the admission task, including pre-ready draining. `DurableAdmissionSchedulingError` is rethrown *into that task* (and emitted as `flush_fail` / `durable_admission_scheduling`) so Workers keep the isolate awake; `fire()` itself still does not throw.

After `shutdown()`, emits `drop` / `shutdown` and returns.

## `fireAsync(action, input, context?)`

Resolves after admission; in durable mode, journal commit occurs first. Rejects on hard admission failure, degraded/uninitialized, missing tenant when required, or oversize `tenantId`. Cloudflare alarm scheduling can also reject after commit with `DurableAdmissionSchedulingError`.

Messages:

| Condition | Error |
|-----------|-------|
| `degraded` before ready wait | `AuditLogger is degraded — fireAsync unavailable` |
| Degraded / no engine after ready | `AuditLogger is not initialized — fireAsync unavailable` |
| Missing tenant, DPT | `tenantId is required when tenancy.mode is "database_per_tenant"` |
| Missing tenant, `requireTenantId` | `tenantId is required when requireTenantId is true` |
| Oversize tenant | `tenantId exceeds maxTenantIdBytes (N)` |
| Hard fail / backpressure | `Failed to enqueue audit log (durable hard fail / backpressure)` |

`resolveTenantId` on context fills `tenantId` only when the caller omitted it. Thrown resolver errors: `fire` emits `drop` / `get_tenant_id` and never throws; `fireAsync` rejects.

## `query({ tenantId, filters, pagination })`

Newest-first page from the destination. Default `pagination.limit` is 50, clamped to `[1, maxQueryLimit]` (default cap 500). Throws `AuditLogger is not initialized — query unavailable` when degraded or shut down. Empty/`requireTenantId` tenant rules match `fireAsync`.

```ts
await audit.query({
  tenantId: 't1',
  filters: { action, actorId, entityId, startDate, endDate },
  pagination: { cursor, limit },
});
// → { logs, nextCursor }  // nextCursor is the last row's id, or null
```

`tenantId` omitted/`undefined` queries the base adapter with `null` (unscoped) unless `requireTenantId` is on. In `database_per_tenant`, a missing tenant throws; a present tenant pins the pooled adapter. Adapter `query` failures after a successful pin are not wrapped. Pin/resolve failures throw `Failed to resolve tenant adapter for tenantId "…": …`.

## `flush()`

Drains current RAM queues and compacts the journal when durable. Throws `AuditLogger is not initialized` when degraded or shut down.

Prefer for request-end volatile delivery: `await fireAsync(...); await flush()`.

## `runMaintenance()`

Single-flight: flushes, recovers DLQ orphans, scans the DLQ once, and prunes configured retention. A caller during a pass queues one extra pass after. See [Maintenance](/guides/maintenance).

## `retryDlqNow()`

Recover orphans + one DLQ scan without flush or retention.

## `listDlq(opts?)`

Lists opaque `DLQEntry` values. Pending is included by default; processing and dead are opt-in.

```ts
listDlq(opts?: {
  includePending?: boolean;
  includeProcessing?: boolean;
  includeDead?: boolean;
}): Promise<DLQEntry[]>
```

## `requeueDead(id)` / `deleteDead(id)`

`requeueDead` moves a dead entry to pending, resets attempts, and preserves its ID. `deleteDead` permanently deletes a dead entry. Both throw `AuditLogger is not initialized` when degraded.

## `getStats()`

Sync RAM snapshot. Always includes `queued`, `tenants`, `degraded`, `recoveryBacklog`, `inflightFlushes`. Does not hit disk. Before ready, `queued` is the pre-ready buffer length (`tenants` is `1` when that buffer is non-empty). When degraded: zeros with `degraded: true`. After shutdown with no engine: zeros with `degraded: false`.

## `getStatsDetailed()`

`getStats()` plus `walApproxBytes` / `dlqPending` / `dlqProcessing` / `dlqDead`. When degraded or not ready those disk fields are `0`. When `reliability.getStats()` throws they are **omitted** (not zeroed) and a `stats` / `reliability_get_stats` event is emitted.

## `verifyIntegrity(logs, opts?)`

Verifies an oldest-first integrity chain. Optional `opts.genesis` (default `INTEGRITY_GENESIS`, 64 zero hex). Returns `{ ok, failedAt, error? }`.

## `shutdown()`

Best-effort drain then closes destination and reliability resources. Subsequent `fire` emits `drop` / `shutdown`. Idempotent. Waits for in-flight maintenance before closing. Flush honors `flushTimeoutMs`; leftover `inflightFlushes` emit `limit` / `shutdown_deadline`.

## `AuditLoggerStats`

```ts
interface AuditLoggerStats {
  queued: number;
  tenants: number;
  degraded: boolean;
  recoveryBacklog: number;
  inflightFlushes: number;
  walApproxBytes?: number; // getStatsDetailed only
  dlqPending?: number;
  dlqProcessing?: number;
  dlqDead?: number;
}
```

Source: https://logbun-docs.abshahin.workers.dev/reference/audit-logger/index.mdx
