Logging guide
CONA sends operational logs to Axiom. Logging helpers do not write to Postgres. Business audit records, product workflow state, product analytics, metrics, and traces use separate paths. The repository decision Telemetry classification and persistence boundaries is the source of truth for ownership, storage, retention, and access.Choose the record type first
One business action may need both an operational log and an audit record. Call
the logger and the domain audit writer explicitly. Do not make either one a
side effect of the other.
Use the shared operational envelope
Use@cona/observability for new shared logging code. It emits a bounded,
redacted envelope with stable event names, runtime context, retry semantics,
and these classification fields:
Log at meaningful boundaries
- Emit one terminal error when an operation has stopped.
- Emit a warning when an operation will retry or continue in degraded mode.
- Emit an informational recovery event when useful for an incident timeline.
- Use stable
domain.actionevent names and low-cardinality fingerprints. - Include
operation,outcome,durationMs, and retry state when relevant. - Preserve structured errors instead of logging only their message.
- Avoid per-record success logs in batch operations. Prefer bounded summaries.
@temporalio/activity logging so the Worker adapter
can add Workflow, run, Activity, attempt, task-queue, heartbeat, process, and
capacity context.
Keep sensitive data out
Never log credentials, access tokens, session tokens, cookies, raw bank data, complete third-party payloads, or document contents. Prefer stable internal identifiers and bounded reason codes. Avoid raw URLs and query strings when they can contain customer or attacker-controlled data. The shared serializer redacts common secret fields, but redaction is a safety net, not permission to pass sensitive payloads to a logger. Governed event families usedefineEventRegistry(registry, schema). Every
event must declare an owner and description, while the registry declares a
positive schema version, required envelope fields, and—where practical—an
allowlist of attribute keys. CI also rejects new raw console.warn /
console.error calls and error-message-only logging. Existing exceptions are
owned and tracked in the
logging governance baseline.
Current datasets
Dataset names come from deployment configuration. The current topology is:- Webapp and portal application logs: the configured application dataset.
- Webapp security events: the configured restricted security dataset.
- Temporal Worker and SDK lifecycle logs:
cona_temporal-workersin production, with the staging equivalent in staging. - Temporal Activity logs:
cona_temporal-activityin production, with the staging equivalent in staging.
Retention and access
Axiom retention and access are dataset-level controls. Do not assume that an error level changes retention.- Application logs: 90 days in production and 30 days outside production.
- Security telemetry: 365 days, with access restricted to Security and approved incident responders.
- Log-derived metric rollups: migration bridge only. OpenTelemetry metrics keep raw series for 30 days and aggregates for 13 months.
- Traces: 30 days in production and 14 days outside production.
Business audit is not logging
UselogActivity for activity_logs and keep it in the same transaction as
the business mutation it describes. Use the copilot audit writers for agent
runs, actions, and approvals. Keep background_activities limited to mutable,
user-visible workflow state.
Never call those writers from an observability transport or adapter. Never use
Postgres for log delivery, logger buffering, metrics, or traces.