Skip to content

Audit & logs

Every platform has to answer three questions: who changed the setup?, what changed on this record?, and what happened inside this transaction? Salesforce answers them with five disconnected tools — Setup Audit Trail, Field History Tracking, debug logs, Event Monitoring, and Field Audit Trail — several of them paid (Event Monitoring and Field Audit Trail require Shield, priced at roughly 10% of total spend), one of them off by default (debug logs), and each with its own retention and its own access path. CAOS answers all three with one model, three always-on streams, correlated by a single id, and nothing behind a paywall.

Every log entry, in every stream, shares one envelope — actor, correlationId, timestamp, tenant — so the three streams are one dataset seen three ways, not three products. The streams differ only by subject:

Stream Answers Subject Salesforce equivalent(s)
Metadata audit Who changed the platform’s configuration, and to what A metadata component change Setup Audit Trail
Data history What changed on a record, field by field A field value change Field History Tracking + Field Audit Trail (paid)
Execution trace What a transaction did — queries, effects, budgets, timing A save/read/deploy execution Debug logs + Event Monitoring (paid)

Because all three carry the same correlationId, a single failure can be walked end to end: an error → the execution trace of the transaction that raised it → the field changes that transaction wrote → the metadata change that made it behave that way. Salesforce’s five tools cannot be joined like this; each is its own silo.

Metadata audit — every change to a canonical component, whatever the source: a deploy, a click-made change captured by reverse-integration, or an API edit. Because components are content-addressed and diffable, an audit entry is the before → after diff, not a one-line string.

  • Component key, change type (create / update / retire / purge), and the structural diff of its body.
  • Actor, source (deploy / ui / api), and the deploy’s generation id.
  • Permission and root events are first-class and flagged — a platform.root assignment, a permission-set grant, an FLS change: this is what backs “every root action is logged.”

Data history — every field change on every record, written to the separate append-only history table (so it never consumes an object’s column budget). No 20-field cap, no paid tier.

  • Record id, field key, old value → new value, actor, correlationId.
  • Create and delete are entries too (null → value, value → null / tombstone).

Execution trace — captured at two levels so that “always on” and “affordable” can both be true:

  • A summary for every transaction, always: actor, correlationId, object, operation, the save-order phases entered, budgets consumed (queries, writes, CPU, time), and outcome. You are never blind the way a Salesforce org is with debug logs off.

    The stream’s shape reserves room for non-save login / API / export events too (event_type), but as of 23 August 2026 only the save path actually writes one — a sign-in does not (yet) land here; wiring it in is tracked separately (CAOS-1666). A sign-in is captured today on its own table (caos.login_event), not this stream — see the next section.

  • A verbose per-statement trace — every query, effect, calc call, and budget line — sampled by default and targetable on demand (by user, object, or correlationId), because verbose capture is genuinely expensive. Raising a verbose trace never disables anything; it widens sampling for a scope and a window.

Nothing here is off by default, and nothing is a paid add-on. The only thing metered is the volume of the verbose execution trace, and it is metered by sampling, never by silently dropping the always-on streams.

Stream Always on? Default retention Salesforce, for contrast
Metadata audit Yes, cannot be disabled 2 years hot, then archived (never hard-deleted) 180 days, then permanently deleted; UI shows only the latest 20
Data history Yes, every field 7 years hot + archive, configurable per plan 18 months / 20 fields free; 10 years / 60 fields only on Shield
Execution summary Yes, every transaction 90 days hot + archive (aligned with the error-trace store) debug logs are off until a trace flag is set
Execution verbose Sampled / on-demand 30 days (bulky; sampled) each log ≤ 20 MB, purged in 24 h; trace flags auto-disable at 1000 MB / 15 min
Sign-in history Yes, every attempt 1 year hot, then archived (never hard-deleted) —

Retention is a per-tenant / per-plan policy, and expired data is archived, not destroyed — the opposite of Salesforce’s hard 180-day and 24-hour cliffs. There is no equivalent of Salesforce’s silent “we turned your logging off because you produced too much” footgun: the always-on streams are bounded by retention windows and archival tiering, and only the verbose trace is sampled.

The Logs surface is a package-delivered surface — it lives in the Setup app, which a package provides and the shell renders. The three streams themselves are kernel data, equally reachable from the CLI and SQL paths below; what follows is how one such package presents them. A single Logs area (in Setup) with three tabs, plus the same data surfaced in context:

  • Setup audit — a filterable feed of configuration changes; each row expands to the before → after diff. Filter by actor, component, type, and time. No 20-row ceiling.
  • Data history — searchable field changes, and the same timeline rendered as a History panel on each record page and per-field in Object Manager.
  • Execution — per-transaction traces: the save-order phase timeline, budgets consumed, the queries and effects run, and the correlationId — deep-linked from an error’s reference id on the Errors surface, so “what went wrong” jumps straight to “what happened.”

Every entry cross-links by correlationId to the related entries in the other tabs, so any row is a pivot point into the full story of one transaction.

All three streams are first-class in the CLI — they are queryable tables, so the commands are thin views over them:

Terminal window
caos audit list --since 2026-08-01T00:00:00Z # metadata changes since a time bound
caos audit --follow # tail config changes live
caos history list --object invoice --record-id 8f3a… # a record's field timeline
caos logs list --correlation-id 5f3c… # one transaction, by correlationId
caos logs --follow # tail executions live
caos trace show 5f3c… # the verbose per-statement trace for one transaction

Every command takes --since / --until, --format json, and pipes cleanly; because the streams are tables, anything the CLI shows is also a plain SQL query for ad-hoc analysis or export.

Reading logs is gated by system permissions: execution traces and health by diagnostics.view, a sensitive raw trace by diagnostics.decode, and configuration/audit history by the security-admin surface. One rule matters most: the logs honor field-level security. A user viewing data history sees the change record of a field only if they can read that field — the history stream is not an FLS bypass. The sole exception is platform.root, which sees everything — and whose every access is itself an audit entry.

The record matters as well as the field. A record’s history is readable only by someone who can read the record itself, through the same object permission and sharing that decide whether they can open it; the permission to view logs does not widen that. A deleted record in the Recycle Bin keeps its history: whoever could read the record before it was deleted can still read every entry for it, including the deletion, with who deleted it and when, and nobody else can. A purged record has no row left to read, so its history follows the rule for a record the reader cannot see.

Five mechanisms, three of them constrained by cost or default-off:

  • Setup Audit Trail — always on and undisableable, but retained only 180 days then permanently deleted, and the UI shows just the 20 most recent entries; the rest require a CSV export (Gearset audit-trail guide).
  • Debug logs — off by default (require a trace flag); each log ≤ 20 MB; system logs purged in 24 hours, monitoring logs in 7 days; generating > 1000 MB in 15 minutes disables your trace flags (Debug Logs — Salesforce Help).
  • Field History Tracking — free, but 18 months and 20 fields per object.
  • Field Audit Trail — 10 years and 60 fields, but only with a Shield license (Field Audit Trail — Salesforce Help).
  • Event Monitoring — 50+ event types, but the full set and extended retention require the paid Event Monitoring add-on / Shield (~10% of total spend); the free tier is a few event types at ~1 day retention (Shield pricing).

(The specific figures above are drawn from Salesforce Help plus widely-corroborated secondary guides; the Shield percentage is a commonly-cited commercial figure, not a fixed published list price, and should be confirmed with Salesforce for an exact price.)

Where CAOS is better:

  • Nothing is paywalled or off. The capabilities Salesforce charges Shield for — long field-history retention and rich execution/event logging — are always-on defaults here. Cost: CAOS owns that storage and its retention economics, which Salesforce offloads to a Shield SKU.
  • One correlated dataset, not five silos. A single correlationId joins config, data, and execution, so root-cause analysis is a pivot, not a cross-tool reconstruction. Cost: the id must be threaded through every surface — a standing discipline the whole platform already depends on.
  • Structured and SQL-queryable. Every stream is a table; the UI and CLI are views over it, versus Salesforce’s 20-rows-then-CSV audit trail and download-and-grep text debug logs. Cost: schema and index design for high-volume append-only logs is real work.
  • Diff-based metadata audit. An audit entry is the component’s before → after diff, not a one-line summary, because components are content-addressed. Cost: storing diffs is heavier than storing a line of text.
  • No silent loss. Retention windows + archival replace Salesforce’s 24-hour purge, 180-day cliff, and auto-disabling trace flags; the always-on streams are never dropped, only the verbose trace is sampled. Cost: always-on capture at scale needs tiering and archival that must be built and operated.

Parity (table stakes): an undisableable configuration audit trail, per-field data history, transaction-level execution logging, and login/API event capture. Salesforce has all of these somewhere; matching them is the floor. The win is that CAOS makes them one always-on, unpaywalled, correlated model rather than five tools with five retention rules and three price tags.