Documentation
¶
Overview ¶
Package logging gives Atlas's operational logs a stable contract (ADR-0142).
Every line Atlas wrote used to be a prose sentence with values interpolated into it:
log.Printf("checkpoint: published at log position %d (recovery replays only past it)", pos)
An operator can read that. Nothing can *alert* on it, except by matching a regular expression against wording that changes the moment someone rewords the sentence, and nothing can chart the position without parsing it back out of English.
The fix is not to delete the prose. "will retry next tick" is real guidance that a bare event name loses, and the console is a first-class audience — an operator watching `atlas serve` should not be handed JSON. So each line now carries three things:
- an **event name**, the stable identifier an alert matches on;
- the **sentence**, unchanged in spirit, as the human explanation;
- the **values**, moved out of the sentence into typed attributes.
Two properties are structural rather than conventional. Event is a struct with an unexported field, so a caller outside this package cannot invent a name — only the constants declared here exist, and a duplicate or malformed one panics at init rather than reaching production. And the standard logger ends up pointed at the same handler, so a line from a dependency arrives in one stream and one format instead of alongside it — see Setup for why that costs no code.
It is built on log/slog, which is to say on nothing: no dependency is added (ADR-0010), and the engine still does not log at all, so the single writer's hot path is untouched (invariants I1 and I3).
Index ¶
Constants ¶
const DefaultFormat = FormatText
DefaultFormat is text. The console audience is the one Atlas has always had, and a default that turns their terminal into JSON would be a regression dressed as progress; JSON is one flag away for the deployment that wants it.
Variables ¶
var ( // ServerListening is emitted once the HTTP listener is up. It comes *after* // recovery — the port stays closed until the log has been replayed (slice 7) — so // it doubles as the "this instance finished starting" signal. ServerListening = newEvent("server.listening") ServerShuttingDown = newEvent("server.shutting_down") ServerDocsEnabled = newEvent("server.docs_enabled") ServerMetrics = newEvent("server.metrics_enabled") DataDirOpened = newEvent("server.data_dir_opened") // CommandFailed is a top-level command exiting non-zero. CommandFailed = newEvent("command.failed") MCPProxying = newEvent("mcp.proxying") // WorkerStarting is the out-of-process job worker announcing what it will serve // and for which server (ADR-0157). WorkerStarting = newEvent("worker.starting") // WorkerPollFailed is a worker reporting that a poll failed and will be retried. WorkerPollFailed = newEvent("worker.poll_failed") // WorkerSupervisorStarted and WorkerSupervisorFailed report the lifecycle of a // worker process Atlas launched itself (ADR-0157 step 7). WorkerSupervisorStarted = newEvent("worker.supervised_started") WorkerSupervisorFailed = newEvent("worker.supervise_failed") // ADMockEnabled is an AD worker announcing that it serves the Active Directory // connector against a directory in its own memory rather than a real one // (ADR-0181). It is a warning rather than an info because // a mock worker is indistinguishable from a working one everywhere else: it // completes every job it leases. ADMockEnabled = newEvent("ad_mock.enabled") // ADMockPerformed is one operation that mock directory simulated. It is what a // mockup run leaves behind for the person who ran it, in the worker's log where // the Workers console shows it. ADMockPerformed = newEvent("ad_mock.performed") // WorkerHistoryFailed is the job-history exporter reporting that an append did not // reach its clio connector, or that its buffer is dropping entries. Both are // warnings rather than errors on purpose: the history is telemetry, and the engine // deliberately does not wait for it, so a gap costs a run nothing. WorkerHistoryFailed = newEvent("worker.history_failed") )
Process lifecycle.
var ( CheckpointEnabled = newEvent("checkpoint.enabled") CheckpointPublished = newEvent("checkpoint.published") CheckpointFailed = newEvent("checkpoint.failed") CheckpointPruneFailed = newEvent("checkpoint.prune_failed") WALCompactionEnabled = newEvent("wal_compaction.enabled") // WALCompactionInert is compaction configured *without* checkpointing, which does // nothing at all: the cut is derived from a checkpoint. It warrants a warning // precisely because the flag makes it look enabled. WALCompactionInert = newEvent("wal_compaction.inert") WALCompactionFailed = newEvent("wal_compaction.failed") WALCompactionWatermarkFailed = newEvent("wal_compaction.watermark_unavailable") WALCompactionSegmentsDeleted = newEvent("wal_compaction.segments_deleted") )
Recovery checkpoints and WAL compaction (ADR-0131).
var ( RestoreApplied = newEvent("restore.applied") BackupStreamFailed = newEvent("backup.stream_failed") FullBackupStreamFailed = newEvent("full_backup.stream_failed") ApplicationSourceStreamFailed = newEvent("application_source.stream_failed") )
Backup, restore, and streaming exports (ADR-0107/0108/0109).
var ( RetentionEnabled = newEvent("retention.enabled") RetentionPurged = newEvent("retention.purged") ExporterEnabled = newEvent("exporter.enabled") ExporterIndexed = newEvent("exporter.indexed") ExporterTickFailed = newEvent("exporter.tick_failed") )
History retention (ADR-0115/0144) and the OpenSearch exporter (ADR-0114).
var ( VaultKeyGenerated = newEvent("vault.key_generated") // JobTypeIndexCollision reports a stored job-type assignment whose index the // reserved range has since grown over. Warned at startup rather than swallowed: // jobs already on disk carry the old index, so the drop is not cosmetic. JobTypeIndexCollision = newEvent("jobtype.index_collision") AuthAdminSeeded = newEvent("auth.admin_seeded") AuthPasswordReset = newEvent("auth.password_reset") UserProvisioningUserCreated = newEvent("user_provisioning.user_created") UserProvisioningPasswordSet = newEvent("user_provisioning.password_set") UserProvisioningUserDisabled = newEvent("user_provisioning.user_disabled") )
Identity, secrets, and provisioning (ADR-0044/0070/0123).
var ( TracingEnabled = newEvent("tracing.enabled") TracingShutdownFailed = newEvent("tracing.shutdown_failed") )
Distributed traces (ADR-0142 slice 8b).
var ( // DeploymentReloadedWithProblems reports a stored definition — or a DMN model // bundled with one, told apart by the artifact attribute — that today's // deploy-time checks would refuse, brought back anyway because it passed the gate // of the day it was deployed and its instances are running under it // (ADR-0177). Warned rather than swallowed: the // model is drifting from what the compiler now asks for, and the next deploy of // it will be refused with the author watching. DeploymentReloadedWithProblems = newEvent("deployment.reloaded_with_problems") ScriptWorkerEnabled = newEvent("script_worker.enabled") ScriptWorkerMissing = newEvent("script_worker.binary_missing") CallOverrideSkipped = newEvent("call_override.skipped") CollabParticipantsReaped = newEvent("collab.participants_reaped") )
Everything else the running server reports about itself.
Functions ¶
func Setup ¶
Setup points the default logger at w in the given format. Everything the process emits — including lines from dependencies that log through the standard library — then arrives as one stream in one shape.
w is the caller's to compose: the server tees stderr into the bounded buffer behind GET /api/v1/logs, and that keeps working because this writes to the same place.
Types ¶
type Event ¶
type Event struct {
// contains filtered or unexported fields
}
Event is a registered log event name.
It is a struct with an unexported field on purpose. A caller outside this package cannot write Event{name: "made.up"}, so the catalogue below is the complete set of names that can ever be logged — the contract is enforced by the compiler rather than by a review comment (invariant I5, compile don't interpret). The one value an outside caller can forge is the zero Event, and that logs as "unregistered" rather than as an empty field.