Skip to content

Audit Log ​

The Audit Log (/audit-log) is the system-wide record of every operator action that mutated state in a monitored service. Pause a listener, replay a DLQ batch, hard-delete a tenant — it lands here, signed with the operator's identity and the parameters of the action.

This is the page you open when production is acting weird and you need to know who did what, when.

Filters ​

The filter row at the top of the page narrows the table to a subset of entries.

FilterEffect
All Actions dropdownRestrict to one action type (e.g. HardDeleteTenant)
Global service selector (header)Restrict to actions targeting one service

The Action filter re-fetches from the server. Filters do not persist across reloads.

Table ​

ColumnMeaning
TimestampRelative time (e.g. 12m ago) — tooltip shows the absolute timestamp
ActionAction type, rendered as a colored badge (see badge-colour mapping below)
ServiceThe service the action targeted
TargetOptional target URI (endpoint URI, projection shard, tenant id, etc.)
DetailsFree-form description
Parameters"Show (N)" button if the action carried structured parameters; click to expand a key=value list under the row
UserInitiated-by identity

Action Categories ​

Every action belongs to one of six categories, used for badge colouring and quick filtering by intent:

CategoryActions in this categoryBadge colour
dlqReplayDlq, DiscardDlqOrange
listenerPauseListener, RestartListenerBlue
projectionRebuildProjection, RewindSubscriptionPurple
alertClearAlertGreen
tenantAddTenant, RemoveTenant, HardDeleteTenant, DisableTenant, EnableTenantTeal
configEditScheduledMessage, UpdateEndpointConfig, PushAgentThresholds, othersGrey

The mapping lives in src/FrontEnd/src/composables/useAuditLog.ts (actionCategory() and actionBadgeColor()).

SQL Query Entries ​

A SQL statement run from the Event Store Explorer's SQL view or the query_sql MCP tool is the one audited read, and it is recorded twice: a RequestSqlQuery row when the statement is dispatched, and a SqlQueryCompleted row when the monitored service answers, both carrying the same queryId. The page pairs them and shows one line per statement, at the time the operator acted, with the outcome as a badge: Ran (with the row count and elapsed time), Refused (with the guard's reason), or Failed (a timeout or engine error). The statement's first line sits under the outcome; "Show" expands the full statement beside the outcome's numbers.

A request with no answer is kept as its own line, badged No outcome recorded — a statement that was dispatched and never answered (service down, a lost reply) is exactly what an audit log has to show, so the attempt row is never collapsed away and never reads as a success. A completion whose request has scrolled out of the fetched window shows on its own, as the outcome it is.

Choosing RequestSqlQuery in the Action filter shows every statement this way; the filter is applied after pairing, so it cannot render answered statements as unanswered.

HardDeleteTenant Entries ​

The new HardDeleteTenant action type is logged with extra parameters captured at the moment of confirmation:

ParameterMeaning
tenantIdThe exact tenant id the operator typed
databaseUriThe database that was dropped
confirmedAtWall-clock time of the typed-id confirmation

Click "Show (3)" on a HardDeleteTenant row to expand these. Audit entries for hard deletes are intentionally verbose because the action is irreversible; the parameters block lets you reconstruct the exact state at the moment of click.

Pagination ​

Bottom of the page. Page sizes 25 / 50 / 100. The page asks for 500 entries per fetch — that cap is a client-side choice, not a server limit: GET /api/critterwatch/audit-log defaults to 100 and honours whatever ?limit= a caller passes.

Audit entries are not pruned

There is no retention setting for the audit log and no pruner for AuditLogEntry — entries are kept indefinitely. Earlier revisions of this page pointed at an AuditLogRetentionDays setting; it has never existed. Timeline entries are pruned (30 days by default); the audit log is not.

Auto-Refresh ​

The "Auto-Refresh Off" / "Auto-Refresh On" toggle in the header polls every 10 seconds when enabled. Auto-refresh is off by default — the audit log doesn't change frequently and the display would jitter on every poll. Turn it on if you're following a coordinated incident in real time.

Refresh ​

Manual refresh button next to the auto-refresh toggle. Re-fetches with the current filters applied.

API ​

The audit table is backed by GET /api/critterwatch/audit-log with optional ?service=, ?action= and ?targetUri= query parameters. Operators with shell access can query the same data directly with curl for offline analysis or scripted exports. The endpoint's default limit is 100 rows; the page asks for more.

There is no CSV export — the JSON from this endpoint is the export.

Free for read-only monitoring. A commercial license is required for administrative actions and the MCP server.