logging

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: AGPL-3.0 Imports: 6 Imported by: 0

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

View Source
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

View Source
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.

View Source
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).

View Source
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).

View Source
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).

View Source
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).

View Source
var (
	TracingEnabled        = newEvent("tracing.enabled")
	TracingShutdownFailed = newEvent("tracing.shutdown_failed")
)

Distributed traces (ADR-0142 slice 8b).

View Source
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 Error

func Error(e Event, msg string, attrs ...slog.Attr)

Error records something that failed and is not being retried.

func Events

func Events() []string

Events returns every registered event name, sorted.

func Info

func Info(e Event, msg string, attrs ...slog.Attr)

Info records routine progress: work that got done.

func Setup

func Setup(w io.Writer, f Format) error

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.

func Warn

func Warn(e Event, msg string, attrs ...slog.Attr)

Warn records something an operator should look at that the server is handling on its own — a tick that failed and will be retried, a configuration that will not do what it looks like it does.

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.

func (Event) Attr

func (e Event) Attr() slog.Attr

Attr returns the event as the attribute it is logged under.

func (Event) String

func (e Event) String() string

String returns the event name.

type Format

type Format string

Format is how records are rendered.

const (
	// FormatText is logfmt-style key=value output: what a person reads in a terminal.
	FormatText Format = "text"
	// FormatJSON is one JSON object per line: what a log shipper ingests without a
	// parsing rule of its own.
	FormatJSON Format = "json"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL