Documentation
¶
Overview ¶
Package logging builds bentoo's diagnostics logger on log/slog.
One logger is built per invocation by the root command and handed to every component that emits diagnostics — through the command's context (NewContext/FromContext) or a component's constructor options — never through package-level state. It writes key=value lines to stderr and JSON lines to $XDG_STATE_HOME/bentoo/logs/bentoo.log, and every value secrets.Lookup resolved is scrubbed from both by NewRedactingHandler.
Index ¶
- Constants
- func DefaultLogDir() (string, error)
- func FileLevel(terminal slog.Level) slog.Level
- func FromContext(ctx context.Context) *slog.Logger
- func Hold(l *slog.Logger) (held *slog.Logger, release func())
- func New(opts Options) (*slog.Logger, func() error, error)
- func NewContext(ctx context.Context, l *slog.Logger) context.Context
- func NewRedactingHandler(next slog.Handler, resolved func() []string) slog.Handler
- func OrDiscard(l *slog.Logger) *slog.Logger
- func ResolveLevel(verbose, quiet bool, env string) (slog.Level, error)
- type Options
Constants ¶
const FileName = "bentoo.log"
FileName is the log file's name inside the log directory.
Variables ¶
This section is empty.
Functions ¶
func DefaultLogDir ¶
DefaultLogDir returns $XDG_STATE_HOME/bentoo/logs, or ~/.local/state/bentoo/logs when XDG_STATE_HOME is unset or empty.
func FileLevel ¶
FileLevel returns the log file's level for a terminal level: info, or debug when the terminal is debug, so --quiet and a raised BENTOO_LOG_LEVEL never remove info diagnostics from the file.
func FromContext ¶
FromContext returns the logger NewContext stored in ctx, or a logger that discards everything when none was stored.
func Hold ¶ added in v0.36.0
Hold returns a logger that keeps back the terminal copy of every record it receives, and a release func that hands the kept records, in the order they were logged, to the terminal sink and makes the logger write through from then on.
A caller holds the invocation logger while something else draws on the terminal the logger writes to: a line written under bubbletea's inline frame moves the cursor without the renderer knowing, so its next redraw lands on the wrong rows and leaves the old frame behind.
Only the terminal is held: on a logger New built with a log file, the file still gets each record at once, redacted as an unheld logger redacts it. A logger of any other shape is held whole. The queue keeps the newest maxHeldRecords records, and the release first writes one WARN line counting any it dropped.
Loggers derived from the held one with With or WithGroup share its hold. A record the terminal sink would drop is not kept. release may be called more than once; only the first call replays.
func New ¶
New builds the invocation logger: a text handler on opts.Stderr at opts.Level without the top-level time attribute and, when opts.LogDir is not empty, a JSON handler appending to LogDir/bentoo.log at FileLevel(Level), both behind one redacting handler. The returned func closes the log file; it may be called more than once.
When the directory or file cannot be created or opened, New still returns a usable stderr-only logger and a no-op close func, together with an error naming the path and the cause; the caller reports it.
func NewContext ¶
NewContext returns a copy of ctx carrying l.
func NewRedactingHandler ¶
NewRedactingHandler wraps next so that every value resolved returns is replaced with "***" in the message and in every attribute value — string, error, any other kind rendered as text, at any group depth, including attributes bound with With/WithGroup — and the value of every credential-named key is written as "***". resolved is called once per record, so a secret resolved after the handler was built is still redacted. A nil resolved means no resolved values.
func ResolveLevel ¶
ResolveLevel returns the terminal level: error under quiet, debug under verbose, else the level env names (BENTOO_LOG_LEVEL's value), else info. The flags are checked first, so an invalid env next to a flag is no error. An env value other than the four accepted words returns info and an error naming it; ResolveLevel itself never writes anything — the caller reports it.
Types ¶
type Options ¶
type Options struct {
// Stderr receives the key=value lines at Level and above.
Stderr io.Writer
// LogDir is the directory holding FileName; "" writes no file.
LogDir string
// Level is the terminal level; the file level is FileLevel(Level).
Level slog.Level
// Resolved returns the secret values to scrub; nil means none.
Resolved func() []string
}
Options configures New.