Documentation
¶
Overview ¶
Package logger provides structured logging for cloop, backed by Go's standard library log/slog package.
The Logger interface keeps cloop's existing event-oriented call sites (Info/Warn/Error/Log with an Event tag, optional task_id, message, and a free-form data map) source-compatible while letting the underlying slog.Handler decide how each entry is rendered:
- JSON mode (--log-json) → slog.NewJSONHandler writes one NDJSON line per entry to stdout with stable keys (time, level, msg, event, task_id, …) plus any structured attrs supplied by the caller or bound via With.
- text mode (default) → slog.NewTextHandler writes one logfmt-style line per entry to stdout. The orchestrator and other callers additionally print decorative color/banner output to the same stdout; both streams interleave cleanly because slog uses a single synchronised writer.
The previous TextLogger was a no-op so that printf-style output owned the terminal. To preserve that behaviour for terminals where ANSI banners are the primary UX, callers can still gate decorative output on IsJSON() (true means "machine-parseable stream — suppress decoration"). Text mode now also emits one slog line per event so that downstream tooling can scrape it without enabling JSON.
Logger is an interface so tests and integrators can capture entries without going through slog. The default constructor (`New`) returns the slog-backed implementation; tests can substitute their own captureLogger.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Entry ¶
type Entry struct {
Time string `json:"time"`
Level Level `json:"level"`
Event Event `json:"event"`
TaskID int `json:"task_id,omitempty"`
TraceID string `json:"trace_id,omitempty"`
Message string `json:"message"`
Data map[string]interface{} `json:"data,omitempty"`
}
Entry is the legacy JSON schema for a log line. Kept for callers that want to assert against the historical shape (it is no longer the wire format — slog.JSONHandler emits its own representation), but tests in pkg/logger validate the slog output directly.
type Event ¶
type Event string
Event is the structured event name embedded in every log line.
const ( EventSessionStart Event = "session_start" EventSessionDone Event = "session_done" EventTaskStart Event = "task_start" EventTaskDone Event = "task_done" EventTaskFailed Event = "task_failed" EventTaskSkipped Event = "task_skipped" // EventTaskAborted tags a run that produced no work at all — a provider // limit, a rejected credential, or a harness that refused to start. It is // distinct from EventTaskFailed so that dashboards counting failures do // not count runs that never happened (Task 20211). EventTaskAborted Event = "task_aborted" EventStep Event = "step" EventHeal Event = "heal" EventEvolve Event = "evolve" EventHealthCheck Event = "health_check" EventOptimize Event = "optimize" EventVerify Event = "verify" EventCheckpoint Event = "checkpoint" // EventAuthz tags access-control decisions and failures of the // authorization machinery itself (Task 20164). Decisions are also // written to the tamper-evident audit log; these entries exist so an // operator tailing logs sees them without querying the database. EventAuthz Event = "authz" )
type Level ¶
type Level string
Level represents the severity of a log entry. The string values are the historical cloop level names; they are mapped to slog.Level by the implementation. They are still comparable for tests and external code.
type Logger ¶
type Logger interface {
// Log emits a structured entry. taskID of 0 means no associated task.
Log(level Level, event Event, taskID int, message string, data map[string]interface{})
// Debug, Info, Warn, Error are convenience wrappers for Log.
Debug(event Event, taskID int, message string, data map[string]interface{})
Info(event Event, taskID int, message string, data map[string]interface{})
Warn(event Event, taskID int, message string, data map[string]interface{})
Error(event Event, taskID int, message string, data map[string]interface{})
// With returns a new Logger that prepends the given key/value pair to
// every emitted entry. Chained calls compose; the parent is unaffected.
// Typical use: log.With("project", workdir).With("provider", name).
With(key string, value any) Logger
// WithContext returns a Logger that automatically attaches a
// request_id attribute (sourced from pkg/reqid) to every entry, when
// such an ID is bound to ctx. When ctx carries no request ID the
// returned Logger is equivalent to the receiver. Use this at the
// boundary of a request-scoped goroutine so deeply nested call sites
// don't have to thread the ID through their data maps manually.
WithContext(ctx context.Context) Logger
// IsJSON reports whether this logger emits machine-parseable JSON
// output. Callers use this to suppress decorative color/banner text
// that would otherwise corrupt a JSON stream.
IsJSON() bool
}
Logger is the structured event logger used throughout cloop.
Implementations MUST be safe for concurrent use from multiple goroutines. All methods are non-blocking; failures inside the handler are surfaced to stderr but never returned to the caller.
func New ¶
New returns a Logger writing to os.Stdout. When jsonMode is true the handler is slog.JSONHandler; otherwise it is slog.TextHandler.
Both handlers use slog.LevelDebug as the floor so callers control the effective level via their choice of Debug/Info/Warn/Error. cloop does not currently expose a runtime-configurable level filter — every entry is recorded, and downstream tools filter by the `level` field.
func NewJSONLogger ¶
NewJSONLogger preserves the v1 constructor name for callers that import pkg/logger directly (it remains used by some integrators / forks). Internally it now goes through slog.JSONHandler.