log

package
v1.2.9 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package log is the one structured event line every part writes BESIDE the one human line it already writes. SPEC-LOGS.md Part 2 fixes the shape: one JSON object per state change, one line, through Go's own log/slog with slog.NewJSONHandler. The stdout line stays the SPEC.md event, unchanged; this line is the same event with the fields a LogQL query needs, so a person can ask "why is this card hung" without an ssh and a grep.

The fields are fixed, all fifteen of them, and every object carries all fifteen: an id that is not this event's scope is the empty string or zero rather than an omitted key, so `| json` never guesses and a query on `card=""` means exactly "not this scope". ts, level, source, event and msg are never absent; the rest are "" or 0 when they do not apply.

The two fields that come from outside the event are injected: the clock that fills ts (never time.Now() read directly, so a test is deterministic) and the source of the run's guid (never /proc read directly in a test).

Nothing here is a second logging system. The handler is slog's, the escape is internal's oneline, and the line is additive: a reader that only knows the stdout event still works.

Index

Constants

View Source
const Redacted = "[redacted]"

Redacted is what replaces a secret value. It is a fixed string so a query can find the lines where something was redacted, and a test can assert the mark is there.

Variables

This section is empty.

Functions

func ProcessGUID

func ProcessGUID() string

ProcessGUID is the production guid: the kernel's boot id, this process's pid and the process's start time. A process keeps the same guid for its whole run, so its lines group, and two runs that share a pid after a reboot still differ by the boot id. A test never calls this; it injects a fixed GUIDSource instead.

func Redact

func Redact(s string) string

Redact returns s with every secret-shaped value replaced by Redacted. It is safe to call on any string, including one already redacted: the mark itself matches no rule.

Types

type Clock

type Clock func() time.Time

Clock is the writer's clock. Production passes time.Now; a test passes a fixed func so ts is deterministic.

type GUIDSource

type GUIDSource func() string

GUIDSource is the source of this process run's guid. Production passes ProcessGUID; a test passes a fixed func so it never reads /proc.

type Line

type Line struct {
	TS     string // ts: UTC RFC3339Nano from the writer's clock
	Level  string // level: DEBUG, INFO, WARN or ERROR
	Source string // source: the tool that wrote the event
	Bench  string // bench: the machine, by its fleet name
	Verb   string // verb: the verb within the tool
	Job    string // job: the work item's job id
	Card   string // card: the work item's card id
	PR     int    // pr: the work item's pull request number
	Run    string // run: the work item's run id
	Slot   string // slot: the work item's slot
	GUID   string // guid: one per process run
	Event  string // event: start, refuse, retry, done, or the part's own noun
	Msg    string // msg: one human sentence, escaped through oneline by Write
	DurMS  int64  // dur_ms: milliseconds from start to this event
	Err    string // err: the error's text, escaped through oneline by Write
}

Line is one structured event: the fixed field list of SPEC-LOGS.md Part 2. It is a value, built by New and filled by the verb, and Write renders it as one JSON line.

func New

func New(clock Clock, guid GUIDSource, source string) Line

New fills the two fields that come from outside the event -- ts from the injected clock and guid from the injected source -- and defaults the level to INFO, the level of a state change that is not a warning or an error. The verb fills the rest.

func (Line) Write

func (l Line) Write(w io.Writer) error

Write emits the event as exactly one JSON object with the spec's fifteen fields. The message and the error go through pkg/oneline first, so a newline in either cannot add a second line and the object is one line whatever the sentence holds. The writer is injected: stderr in production (a unit's stderr is the systemd journal), a buffer in a test. The handler is slog's JSON handler; the handler's own time, level and msg keys are replaced by the spec's ts, level and msg fields so the object is the spec's object and not slog's.

Every field whose content comes from outside this program -- the ids, the message and the error -- passes through Redact on the way out, so SPEC-LOGS.md Part 2's one hard rule ("a secret VALUE is never logged") is enforced by the emitter and not by review. The fixed vocabulary the program writes itself -- ts, level, source, event, guid -- is never touched, so a redaction can never rename an event out from under a query.

Jump to

Keyboard shortcuts

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