Skip to content

Querying & retention

Logs in CAOS are ordinary objects, and that single decision determines how they are read, secured, reported, retained, and purged: the same way every other object is. There is no bespoke log console with its own permission model, its own query language, or its own retention rules. This page describes what “logs are just objects” buys and where logging-specific policy still applies.

A Log or Log Entry is read through the platform query surface, the same entry point used for any record. That means log reads are automatically narrowed by the caller’s access, with no post-filtering and no bypass:

  • Field-level security narrows the columns a reader sees. A Log Entry field a user cannot read is absent from their result, not blanked — the same FLS-at-read guarantee the audit streams make. A structured field carrying data the reader may not see does not leak through the log.
  • Record-level access narrows the rows. A reader sees the Logs their access permits; an unreadable Log is absent, which (per the error taxonomy’s not-found-beats-forbidden rule) does not disclose its existence.
  • Elevated reads are declared and audited. A diagnostics tool that must read across all Logs uses the query surface’s elevated mode, which requires a declared capability and emits its own audit entry — reading logs broadly is itself a logged, governed act.

Access to logs is gated by the same diagnostics permissions as the execution trace, so the developer-log stream sits inside the existing catalog rather than inventing new grants:

Capability Grants
diagnostics.view Read Logs and Log Entries (own scope, then widening by grant) — the everyday “open the log for this transaction”
diagnostics.decode Read the sensitive raw detail attached to a failure entry — the same grant that decodes an internal error’s raw text
diagnostics.trace Raise verbose capture for a scope + window (see capture)

Because these are the existing diagnostics grants, an org does not administer a separate logging permission surface.

Since Logs are objects, a standard package delivers the whole read stack over them without bespoke logging tooling:

  • List views with saved filters — “my ERROR logs today”, “rolled-back saves in invoice-recalc this week”.
  • Record pages — open a Log to see its entries in execution order, its budget snapshot, its phase runs, and its correlation id as a pivot to the audit streams.
  • Reports and dashboards — error rate by scenario, budget consumption trends, top participants by WARN count — built with the normal report builder, not a logging-specific analytics tool.
  • The query surface / CLI — anything the UI shows is a query, so ad-hoc analysis and export are plain reads. The caos logs --correlation-id <correlationId> command is a thin view over the Log object.

This is the concrete payoff of building logging into the object model instead of beside it: Nebula must ship a “Logger Console” app, custom list views, a “Related Log Entries” component, and quick actions because Log__c is an app object that does not come with those. On CAOS a standard package delivers those same surfaces over the log objects — and because the objects are ordinary metadata, that package is thin; the capture, correlation, and retention engine underneath stays in the kernel.

A Log’s correlationId is the join key across the three audit streams. From an open Log a reader pivots to: the execution trace of the same transaction, the data history it wrote, and the metadata audit of any config change that governed it — and back from an error to the Log via the same id. This is the “walk one failure end to end” promise made navigable, and it is only possible because the correlation id is now threaded end to end.

Log volume is real, so retention is a per-tenant / per-plan policy, aligned with the retention model the audit surface already defines. The governing rules:

  • A retention date per Log. Each Log carries a retentionDate, defaulted from the tenant policy (and overridable per scenario — a noisy sync path can retain for days while an error log retains for months). This is Nebula’s LogRetentionDate__c idea, kept.
  • Hot, then archived — never a silent cliff. Within the hot window Logs are fully queryable; past it they are rolled to archive storage, not hard-deleted. Reaching past the hot window is reported as out-of-window with the archived range offered, never as “no results” — the same honesty rule the audit surface applies.
  • Purge is a scheduled job with a floor. A retention job deletes Logs whose retentionDate has passed, on a schedule, using the platform background-work framework — the CAOS equivalent of Nebula’s LogBatchPurger + LogBatchPurgeScheduler. Setting a Log’s retentionDate to null pins it indefinitely (kept from Nebula).
  • Level drives default retention. An ERROR Log outlives a TRACE Log by default, so the expensive-to-keep, low-value entries age out first and the diagnostically valuable ones persist — retention is level- and scenario-aware, not one flat number.

Almost everything is inherited, but a few rules are logging’s own:

  • Retention defaults by level and scenario, above.
  • A self-logging cap. The logging path must not itself become an unbounded producer — a runaway loop emitting millions of entries is bounded by the same budget envelope as any effect, so a save cannot log itself out of its resource budget. Logging counts against the transaction’s budget like any other effect work.
  • Masking at write time — sensitive structured fields are redacted before persistence, so archived logs never hold data that later access-narrowing would have hidden.