logs

package
v0.5.0 Latest Latest
Warning

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

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

Documentation

Overview

Package logs is the schema of ariesd's log (design §16.4): the names of a line's fields, the stable name of each event a line reports, the id of a request, and the handler that puts a request's id and its trace's ids on every line logged for it.

The names are a contract with whoever alerts on the log or reads it with a program: a field or an event is added here, with a row in docs/server.md, and never renamed. Tests hold every log call of the daemon's packages to these lists.

The package is the standard library alone, so that the store may import it.

Index

Constants

View Source
const (
	// KeyEvent is the stable name of what the line reports: one of the
	// [Event] values. Every line has it, as the first of the fields the
	// line's own call gives; the fields of the logger it was logged
	// through (a connection's project, principal and session) come
	// before it.
	KeyEvent = "event"
	// KeyProject is a project's id.
	KeyProject = "project"
	// KeyPrincipal and KeySession say whose connection or request the
	// line is about, and on an audit line who made the change.
	KeyPrincipal = "principal"
	KeySession   = "session"
	// KeyOp is a request's op, and on an audit line the event's.
	KeyOp = "op"
	// KeyCode is a refusal's code.
	KeyCode = "code"
	// KeyDurMS is how long a request took, in milliseconds.
	KeyDurMS = "dur_ms"
	// KeyReq is the request's id ([NewReq]): on every line logged for
	// the request, and in the refusal the client is sent.
	KeyReq = "req"
	// KeyTraceID and KeySpanID are the ids of the span the line was
	// logged under.
	KeyTraceID = "trace_id"
	KeySpanID  = "span_id"
	// KeyAudit is true on a line of the audit stream, and absent from
	// every other line.
	KeyAudit = "audit"

	// KeyErr is an error's text.
	KeyErr = "err"
	// KeySeq and KeyAt are, on an audit line, the event's number in the
	// control store's log and its time there.
	KeySeq = "seq"
	KeyAt  = "at"
	// KeyTarget is what an audit line's event changed, as the event log
	// names it. KeySubject is the principal it changed, KeyFingerprint a
	// key's fingerprint, and KeyRole a membership's role.
	KeyTarget      = "target"
	KeySubject     = "subject"
	KeyFingerprint = "fingerprint"
	KeyRole        = "role"
	// KeyBy is the principal whose change caused what the line reports.
	KeyBy = "by"
	// KeyIssue is an issue's id, and KeyEpoch a claim's.
	KeyIssue = "issue"
	KeyEpoch = "epoch"
	// KeyReason is a fixed word for why.
	KeyReason = "reason"
	// KeyDetail is text that is not the daemon's own: what the database
	// driver or the SDK said.
	KeyDetail = "detail"
	// KeyCause and KeyFix are why something is wrong and what to do
	// about it, and KeyEffect what follows from it meanwhile.
	KeyCause  = "cause"
	KeyFix    = "fix"
	KeyEffect = "effect"
)

The fields a line may have beside slog's own time, level and msg. The first group is the schema of design §16.4, which every line shares; the rest say what one event or a few are about.

Variables

This section is empty.

Functions

func IsEvent

func IsEvent(name string) bool

IsEvent reports whether name is an event's.

func IsKey

func IsKey(key string) bool

IsKey reports whether key is a field a line may have.

func Keys

func Keys() []string

Keys returns every field a line may have, sorted.

func NewReq

func NewReq() string

NewReq returns an id for a request: 16 hex digits, chosen at random. It only has to tell one request's lines from another's in a log, so it is not made with crypto/rand.

func Req

func Req(ctx context.Context) string

Req returns the id of the request ctx belongs to, or "" outside one.

func WithReq

func WithReq(ctx context.Context, req string) context.Context

WithReq returns ctx carrying req, a request's id: every line logged with that context through a Handler has it.

Types

type Event

type Event string

Event is the stable name of what a log line reports, the value of its event field. An alert matches the name, not the line's message, which may be reworded (design §16.4). A name is never changed once it has shipped; a new event is added to the list below, to Events and to the table in docs/server.md, which tests hold together.

const (
	// The daemon.
	DaemonServing Event = "daemon.serving"
	AdminCheck    Event = "admin.check_failed"
	AdminWarning  Event = "admin.unvouched"
	SystemdNotify Event = "systemd.notify_failed"
	LogSuppressed Event = "log.suppressed"

	// Connections and the handshake.
	ConnAccept      Event = "conn.accept_failed"
	ConnCapRefused  Event = "conn.cap_refused"
	ConnPeerRefused Event = "conn.peer_refused"
	ConnOpened      Event = "conn.opened"
	ConnIdleClosed  Event = "conn.idle_closed"
	ConnReadFailed  Event = "conn.read_failed"
	ConnWriteFailed Event = "conn.write_failed"
	ConnAccessEnded Event = "conn.access_ended"
	ConnDropped     Event = "conn.dropped"
	ConnKeyLookup   Event = "conn.key_lookup_ignored"
	HandshakeFailed Event = "handshake.failed"
	AgentHarness    Event = "agent.harness_ignored"
	AgentRegister   Event = "agent.register_failed"

	// Requests.
	RequestDone    Event = "request.done"
	RequestRefused Event = "request.refused"
	RequestFailed  Event = "request.failed"
	RequestPart    Event = "request.part_failed"
	// RequestUnknown: a write's COMMIT was sent and its answer lost, so
	// it may stand; its connection is closed unanswered.
	RequestUnknown Event = "request.commit_unknown"

	// Projects and their stores.
	ProjectAdded       Event = "project.added"
	ProjectOpened      Event = "project.opened"
	ProjectOpenFailed  Event = "project.open_failed"
	ProjectNotOpened   Event = "project.not_opened"
	ProjectClosed      Event = "project.closed"
	ProjectCloseFailed Event = "project.close_failed"
	StoreSchemaTooNew  Event = "store.schema_too_new"
	StoreUnsafeAccount Event = "store.unsafe_account"
	ControlReload      Event = "control.reload_failed"
	ControlIndexStale  Event = "control.index_stale"

	// Claims, the reaper and the access sweep.
	ClaimExpired  Event = "claim.expired"
	ClaimReleased Event = "claim.released"
	// LockExpired is a hold or a place in a lock's queue the reaper ended
	// for its lease, and LockReleased one that ended for lost access.
	LockExpired  Event = "lock.expired"
	LockReleased Event = "lock.released"
	// The gate events are a gate's changes: added, passed (by a person or
	// a CI job's report), failed (a CI job's report), waived and
	// rearmed (design §20.9).
	GateAdded         Event = "gate.added"
	GatePassed        Event = "gate.passed"
	GateFailed        Event = "gate.failed"
	GateWaived        Event = "gate.waived"
	GateRearmed       Event = "gate.rearmed"
	ReaperFailed      Event = "reaper.failed"
	ReaperPruneFailed Event = "reaper.prune_failed"
	ReaperPruned      Event = "reaper.pruned"
	SweepFailed       Event = "access.sweep_failed"

	// The keys file.
	KeysFileWritten     Event = "keys_file.written"
	KeysFileWriteFailed Event = "keys_file.write_failed"
	KeysFileHeldBack    Event = "keys_file.key_held_back"
	KeysFileLeftOut     Event = "keys_file.key_left_out"
	// KeysFileRemoved is the keys file ariesd wrote, removed because SSH
	// is off.
	KeysFileRemoved Event = "keys_file.removed"
	// KeyExpired is a key of the control store that reached its end: its
	// line is gone from the keys file, and the connections it signed in
	// were closed.
	KeyExpired Event = "key.expired"

	// The HTTPS listener (transport.md §4): listening, stopped by an
	// error, and a connection refused before its hello (the key proof,
	// a browser's origin, the limits), sampled per address. A TLS
	// certificate from files is read again when its files change.
	HTTPSListening      Event = "https.listening"
	HTTPSStopped        Event = "https.listener_stopped"
	HTTPSRefused        Event = "https.refused"
	TLSCertReloaded     Event = "tls.cert_reloaded"
	TLSCertReloadFailed Event = "tls.cert_reload_failed"

	// Sign-in (transport.md §6): a sign-in granted, a step of one refused
	// (sampled per address before the provider, by code after it), a
	// sign-in ended with the connections it closed, a provider that could
	// not be reached or read, and a project whose inbox could not be told
	// of a sign-in. None holds a token, a code or an address.
	SignInGranted        Event = "signin.granted"
	SignInRefused        Event = "signin.refused"
	SignInEnded          Event = "signin.ended"
	SignInProviderFailed Event = "signin.provider_failed"
	SignInAnnounceFailed Event = "signin.announce_failed"

	// The clock.
	ClockBehind       Event = "clock.behind"
	ClockCaughtUp     Event = "clock.caught_up"
	ClockStepped      Event = "clock.stepped"
	ClockStepSettled  Event = "clock.step_settled"
	ClockSettleFailed Event = "clock.settle_failed"

	// The database.
	DatabaseCheckFailed Event = "database.check_failed"

	// Telemetry.
	TelemetryOn              Event = "telemetry.on"
	TelemetryOff             Event = "telemetry.off"
	TelemetryStopFailed      Event = "telemetry.stop_failed"
	TelemetryExportFailed    Event = "telemetry.export_failed"
	TelemetryExportRecovered Event = "telemetry.export_recovered"
	TelemetrySDKError        Event = "telemetry.sdk_error"
	TelemetryScrapeFailed    Event = "telemetry.scrape_failed"
	TelemetryListening       Event = "telemetry.listening"
	TelemetryListenerError   Event = "telemetry.listener_error"
	TelemetryListenerStopped Event = "telemetry.listener_stopped"
	TelemetryKeyMade         Event = "telemetry.key_made"
	TelemetryKeyFound        Event = "telemetry.key_found"
	TelemetryKeyUnavailable  Event = "telemetry.key_unavailable"

	// The audit stream (decision 30): one line for each event of the
	// control store's log that changes who has access to what, named
	// for the event's op. AuditReadFailed is the stream's own failure:
	// the lines are late, and the event log has lost nothing.
	AuditProjectAdd       Event = "audit.project.add"
	AuditProjectArchive   Event = "audit.project.archive"
	AuditProjectActivate  Event = "audit.project.activate"
	AuditPrincipalAdd     Event = "audit.principal.add"
	AuditPrincipalDisable Event = "audit.principal.disable"
	AuditPrincipalEnable  Event = "audit.principal.enable"
	AuditPrincipalSet     Event = "audit.principal.set"
	AuditKeyAdd           Event = "audit.key.add"
	AuditKeyRemove        Event = "audit.key.remove"
	AuditMemberSet        Event = "audit.member.set"
	AuditMemberRemove     Event = "audit.member.remove"
	AuditIdentityInvite   Event = "audit.identity.invite"
	AuditIdentityRemove   Event = "audit.identity.remove"
	AuditIdentityBind     Event = "audit.identity.bind"
	AuditSignInGrant      Event = "audit.signin.grant"
	AuditSignInEnd        Event = "audit.signin.end"
	AuditTrustAdd         Event = "audit.trust.add"
	AuditTrustSet         Event = "audit.trust.set"
	AuditTrustRemove      Event = "audit.trust.remove"
	AuditReadFailed       Event = "audit.read_failed"
)

The events of ariesd's log.

func Audit

func Audit(op string) (Event, bool)

Audit returns the audit stream's event for op, an op of the control store's event log, and false for an op that changes nobody's access.

func Events

func Events() []Event

Events returns every event's name, in the order the guide lists them.

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler is ariesd's log handler. It writes each record to the handler it wraps, which is the journal's, with what the record's context says of it: the request's id (WithReq) and the ids of its span. So a call site passes its context and names neither.

The schema is flat: a group opened with WithGroup qualifies the keys that follow as GROUP.KEY and nests nothing.

A record is also given to the handler set with Handler.Tap, whole: with the attributes of With, of the call and of the context, in that order. Stopping the tap never stops the journal.

func NewHandler

func NewHandler(next slog.Handler, ids IDs) *Handler

NewHandler returns a Handler over next. ids may be nil.

func (*Handler) Enabled

func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool

Enabled reports whether the journal takes records at level.

func (*Handler) Handle

func (h *Handler) Handle(ctx context.Context, r slog.Record) error

Handle writes r, with the ids ctx carries.

func (*Handler) Tap

func (h *Handler) Tap(tap slog.Handler)

Tap has every record that is logged from now on given to h as well, through this Handler and every one derived from it; nil stops that. h must not block: it is called on the goroutine that logged.

func (*Handler) WithAttrs

func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a Handler whose records also have attrs.

func (*Handler) WithGroup

func (h *Handler) WithGroup(name string) slog.Handler

WithGroup returns a Handler that qualifies the keys that follow with name.

type IDs

type IDs func(ctx context.Context) (traceID, spanID string, ok bool)

IDs reads the ids of the span a context carries, and reports false when it carries none.

type Kind

type Kind int

Kind is what a field holds, which decides whether it may leave the machine in a log record exported over OTLP. The journal has every field as it was logged.

const (
	// KindLocal is anything else: an error's text, a path, a name. It stays
	// in the journal and is never exported, since nothing vets what it
	// quotes.
	KindLocal Kind = iota
	// KindWord is a word or a few from a fixed list in the code, or a
	// number, a boolean, a time or a duration: never text a client
	// chose.
	KindWord
	// KindPrincipal is a principal's name, and KindSession a session's id. They
	// are exported as telemetry: principals: allows.
	KindPrincipal
	KindSession
	// The rest are ids, each exported only in its own shape: a project's
	// UUID, an op the server knows, a refusal's code, a request's id, an
	// issue's id, a key's fingerprint.
	KindProject
	KindOp
	KindCode
	KindReq
	KindIssue
	KindFingerprint
	// KindTrace is the ids of a span. An exported record has them from the
	// span itself, so the fields are not repeated on it.
	KindTrace
)

The kinds of field.

func KindOf

func KindOf(key string) Kind

KindOf returns the kind of the field named key, and KindLocal for a name that is no field's: what is not known to be safe stays in the journal.

Jump to

Keyboard shortcuts

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