logger

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 8 Imported by: 0

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.

const (
	LevelDebug Level = "debug"
	LevelInfo  Level = "info"
	LevelWarn  Level = "warn"
	LevelError Level = "error"
)

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

func New(jsonMode bool) Logger

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

func NewJSONLogger(w io.Writer) Logger

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.

func NewWithWriter

func NewWithWriter(w io.Writer, jsonMode bool) Logger

NewWithWriter is like New but writes to w. Tests use this to capture output into a bytes.Buffer.

Jump to

Keyboard shortcuts

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