Documentation
¶
Overview ¶
Package logger provides GTB's logging boundary.
The Logger interface mirrors the standard library's *slog.Logger method set exactly, so a *slog.Logger satisfies logger.Logger directly and can be passed anywhere a Logger is expected (for example props.Props.Logger). Consumers remain free to supply their own implementation with the same method set.
Runtime level and format control are deliberately NOT part of the Logger interface — a plain *slog.Logger owns its level via its handler. They are exposed as optional capabilities through the Leveller and Reformatter interfaces and two package helpers that no-op when the logger does not implement them:
logger.SetLevel(log, slog.LevelDebug) // true if log implements Leveller logger.SetFormatter(log, logger.JSONFormatter) // true if log implements Reformatter
To branch on whether a level is active, use the interface method directly:
if log.Enabled(ctx, slog.LevelDebug) { /* expensive diagnostics */ }
Constructors ¶
- NewCharm(w, opts...): GTB's default, backed by charmbracelet/log for coloured, styled terminal output. The returned Logger also implements Leveller and Reformatter, so --debug, log.level, and log.format take effect on it. Use this for props.Props.Logger.
- NewCharmSlog(w, opts...) / NewCharmHandler(w, opts...): slog-native construction over the same Charm output — a *slog.Logger and an slog.Handler respectively.
- NewSlog(handler): slog.New(handler) for ecosystem handlers (zap, zerolog, OpenTelemetry, custom). Wrap the handler with NewLevelGate for runtime level control via a shared *slog.LevelVar.
- NewNoop(): a discarding *slog.Logger for tests where output is irrelevant.
- NewBuffer() / NewCaptureHandler(): capture records in memory for test assertions.
Index ¶
- Variables
- func NewBuffer() *bufferLogger
- func NewCharmHandler(w io.Writer, opts ...CharmOption) slog.Handler
- func NewCharmSlog(w io.Writer, opts ...CharmOption) *slog.Logger
- func NewLevelGate(inner slog.Handler, level *slog.LevelVar) slog.Handler
- func SetFormatter(log Logger, f Formatter) bool
- func SetLevel(log Logger, level slog.Level) bool
- func ToSlog(log Logger) *slog.Logger
- type CaptureHandler
- func (h *CaptureHandler) Contains(substr string) bool
- func (h *CaptureHandler) Enabled(_ context.Context, level slog.Level) bool
- func (h *CaptureHandler) Handle(_ context.Context, record slog.Record) error
- func (h *CaptureHandler) Messages() []string
- func (h *CaptureHandler) Records() []slog.Record
- func (h *CaptureHandler) Reset()
- func (h *CaptureHandler) SetLevel(level slog.Level)
- func (h *CaptureHandler) WithAttrs(attrs []slog.Attr) slog.Handler
- func (h *CaptureHandler) WithGroup(name string) slog.Handler
- type CharmOption
- type Config
- type Entry
- type Formatter
- type Level
- type Leveller
- type Logger
- type Reformatter
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidFormat = errors.New("invalid format")
ErrInvalidFormat is returned when parsing an unrecognised formatter string.
var ErrInvalidLevel = errors.New("invalid level")
ErrInvalidLevel is returned when parsing an unrecognised level string.
Functions ¶
func NewBuffer ¶
func NewBuffer() *bufferLogger
NewBuffer returns a bufferLogger that captures all log messages in memory. Use Entries(), Messages(), and Contains() to assert on captured output.
Example:
buf := logger.NewBuffer()
myFunc(buf)
if !buf.Contains("expected message") {
t.Error("missing expected log message")
}
Example ¶
package main
import (
"gitlab.com/phpboyscout/go-tool-base/pkg/logger"
)
func main() {
// Create a buffer logger for testing log output.
buf := logger.NewBuffer()
buf.Info("test message", "key", "value")
if buf.Contains("test message") {
// Message was logged
}
}
Output:
func NewCharmHandler ¶ added in v0.30.0
func NewCharmHandler(w io.Writer, opts ...CharmOption) slog.Handler
NewCharmHandler builds a Charm-backed slog.Handler from the given options. It is the slog-first construction entry point: wrap it in slog.New (or use NewCharmSlog) to obtain a *slog.Logger with GTB's default human-friendly terminal output.
func NewCharmSlog ¶ added in v0.30.0
func NewCharmSlog(w io.Writer, opts ...CharmOption) *slog.Logger
NewCharmSlog builds a *slog.Logger backed by a Charm slog.Handler. This is the preferred way to construct GTB's default application logger under the slog-first design; the returned *slog.Logger satisfies the Logger interface.
func NewLevelGate ¶ added in v0.30.0
NewLevelGate wraps an slog.Handler so its effective level is controlled at runtime by level. Records below level.Level() are dropped before reaching inner. This is how the application logger honours --debug and log.level after construction: build the base handler at its most permissive level and gate it with a shared *slog.LevelVar that the command layer mutates.
func SetFormatter ¶ added in v0.30.0
SetFormatter changes log's output format when it implements Reformatter, reporting whether the change was applied.
func SetLevel ¶ added in v0.30.0
SetLevel changes log's minimum level when it implements Leveller, reporting whether the change was applied. A plain *slog.Logger does not implement Leveller, so SetLevel is a no-op for it (it owns its own level via its handler).
func ToSlog ¶ added in v0.30.0
ToSlog adapts a Logger to a *slog.Logger for packages that accept the standard library type directly. A nil logger yields a discarding logger; a value that is already a *slog.Logger is returned unchanged; otherwise a *slog.Logger is built over the logger's Handler.
This is a GTB adapter-boundary helper: framework code converts props.Logger here before handing it to a package that has adopted *slog.Logger. Extracted packages accept *slog.Logger directly and never need this package.
Types ¶
type CaptureHandler ¶ added in v0.30.0
type CaptureHandler struct {
// contains filtered or unexported fields
}
CaptureHandler is an slog.Handler that records emitted records in memory for test assertions. It is the slog-first counterpart to the buffer logger: pass slog.New(logger.NewCaptureHandler()) into a package under test and assert on Records / Messages. Handlers derived via WithAttrs and WithGroup share the same underlying record store, so records land in one place regardless of which derived logger emitted them. It is safe for concurrent use.
func NewCaptureHandler ¶ added in v0.30.0
func NewCaptureHandler() *CaptureHandler
NewCaptureHandler returns a CaptureHandler that records everything at DebugLevel and above. Use SetLevel to raise the threshold (e.g. to exercise level-gated code paths in tests).
func (*CaptureHandler) Contains ¶ added in v0.30.0
func (h *CaptureHandler) Contains(substr string) bool
Contains reports whether any captured record's message contains substr.
func (*CaptureHandler) Enabled ¶ added in v0.30.0
Enabled reports whether level is at or above the handler's minimum level.
func (*CaptureHandler) Handle ¶ added in v0.30.0
Handle records a clone of r, decorated with any attributes accumulated through WithAttrs so assertions see the full attribute set.
func (*CaptureHandler) Messages ¶ added in v0.30.0
func (h *CaptureHandler) Messages() []string
Messages returns the message of every captured record, in order.
func (*CaptureHandler) Records ¶ added in v0.30.0
func (h *CaptureHandler) Records() []slog.Record
Records returns a snapshot of every captured record.
func (*CaptureHandler) Reset ¶ added in v0.30.0
func (h *CaptureHandler) Reset()
Reset clears every captured record from the shared store.
func (*CaptureHandler) SetLevel ¶ added in v0.30.0
func (h *CaptureHandler) SetLevel(level slog.Level)
SetLevel raises or lowers the minimum level at which records are captured. The level is shared with handlers derived via WithAttrs/WithGroup.
type CharmOption ¶
CharmOption configures the charmbracelet backend.
func WithCaller ¶
func WithCaller(enabled bool) CharmOption
WithCaller enables or disables caller location in log output.
func WithFormatter ¶ added in v0.30.0
func WithFormatter(f Formatter) CharmOption
WithFormatter sets the initial output formatter.
func WithPrefix ¶
func WithPrefix(prefix string) CharmOption
WithPrefix sets an initial prefix on the logger.
func WithTimestamp ¶
func WithTimestamp(enabled bool) CharmOption
WithTimestamp enables or disables timestamps in log output.
type Config ¶ added in v0.30.0
type Config struct {
Level string `mapstructure:"level" json:"level" yaml:"level"`
Format string `mapstructure:"format" json:"format" yaml:"format"`
Timestamp bool `mapstructure:"timestamp" json:"timestamp" yaml:"timestamp"`
Caller bool `mapstructure:"caller" json:"caller" yaml:"caller"`
}
Config is the typed, config-system-agnostic construction configuration for a logger. A host application (GTB or any other) unmarshals its config section into this struct and passes it to the package; the package never imports a config system to obtain it.
Level and Format are applied both at construction (via CharmOptions) and at runtime (via SetLevel / SetFormatter). Timestamp and Caller are construction-time only — the Logger interface exposes no runtime setter for them — so a host that wants them config-driven must build its logger from this Config (e.g. logger.NewCharm(w, cfg.CharmOptions()...)).
func DefaultConfig ¶ added in v0.30.0
func DefaultConfig() Config
DefaultConfig returns the package defaults: info level, human-readable text format, no timestamp, no caller — matching a freshly constructed NewCharm logger.
func Merge ¶ added in v0.30.0
Merge overlays a decoded Config onto a base (usually DefaultConfig). Empty string fields in the overlay preserve the base value; boolean fields take the overlay value directly (the package defaults are false, so an unset overlay boolean is indistinguishable from an explicit false and both keep the default).
func (Config) CharmOptions ¶ added in v0.30.0
func (c Config) CharmOptions() []CharmOption
CharmOptions renders the Config as options for NewCharm. An unparseable Level is skipped so the charm default (InfoLevel) survives rather than being reset to an arbitrary value.
type Formatter ¶
type Formatter int
Formatter represents a log output format.
func ParseFormatter ¶ added in v0.30.0
ParseFormatter converts a formatter string ("text", "json", "logfmt") to a Formatter value. The comparison is case-insensitive.
type Level ¶
type Level int
Level represents a logging severity level.
const ( // DebugLevel is the most verbose level. DebugLevel Level = iota // InfoLevel is the default level. InfoLevel // WarnLevel is for potentially harmful situations. WarnLevel // ErrorLevel is for error conditions. ErrorLevel // FatalLevel is for fatal conditions that terminate the process. FatalLevel )
func ParseLevel ¶
ParseLevel converts a level string ("debug", "info", "warn", "error", "fatal") to a Level value.
type Leveller ¶ added in v0.30.0
Leveller is optionally implemented by a Logger whose minimum level can be changed at runtime. GTB's default (Charm-backed) logger implements it; a plain *slog.Logger does not.
type Logger ¶
type Logger interface {
Debug(msg string, args ...any)
Info(msg string, args ...any)
Warn(msg string, args ...any)
Error(msg string, args ...any)
DebugContext(ctx context.Context, msg string, args ...any)
InfoContext(ctx context.Context, msg string, args ...any)
WarnContext(ctx context.Context, msg string, args ...any)
ErrorContext(ctx context.Context, msg string, args ...any)
Log(ctx context.Context, level slog.Level, msg string, args ...any)
LogAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr)
With(args ...any) *slog.Logger
WithGroup(name string) *slog.Logger
Enabled(ctx context.Context, level slog.Level) bool
Handler() slog.Handler
}
Logger is the unified logging interface for GTB. All packages accept this interface instead of a concrete logger type.
Logger is NOT safe for concurrent use unless the underlying backend documents otherwise. The charmbracelet and slog backends provided by this package are both safe for concurrent use. Logger is GTB's logging boundary. Its method set mirrors *slog.Logger exactly, so a *slog.Logger satisfies it directly and can be passed anywhere a Logger is expected — while consumers remain free to supply their own implementation.
Runtime level/format control (SetLevel/SetFormatter) is deliberately NOT part of this interface: those are application concerns, exposed via the optional Leveller and Reformatter interfaces and the SetLevel/SetFormatter helpers, so only the command layer adjusts them. Process termination (Fatal) belongs to command/errorhandling layers, and direct user output (Print) to pkg/output or Cobra writers — neither belongs on the logging boundary.
func NewCharm ¶
func NewCharm(w io.Writer, opts ...CharmOption) Logger
NewCharm returns a Logger backed by charmbracelet/log. This is the default backend for CLI applications, providing coloured, styled terminal output.
Example ¶
package main
import (
"os"
"gitlab.com/phpboyscout/go-tool-base/pkg/logger"
)
func main() {
// Create a charmbracelet-based logger for CLI output.
l := logger.NewCharm(os.Stderr,
logger.WithTimestamp(true),
logger.WithLevel(logger.InfoLevel),
)
l.Info("Application started", "version", "1.0.0")
l.Debug("This won't appear at InfoLevel")
}
Output:
func NewNoop ¶
func NewNoop() Logger
NewNoop returns a Logger that discards all output. Useful for tests where log output is irrelevant. It is a *slog.Logger over a discard handler, so it satisfies the Logger interface directly.
Example ¶
package main
import (
"gitlab.com/phpboyscout/go-tool-base/pkg/logger"
)
func main() {
// Create a silent logger for tests.
l := logger.NewNoop()
// All calls are no-ops — no output produced.
l.Info("This produces no output")
l.Error("Neither does this")
}
Output:
func NewSlog ¶
NewSlog returns a Logger backed by an slog.Handler. Under the slog-first design this is simply slog.New(handler); it exists as a named constructor for ecosystem integration (OpenTelemetry, Datadog, custom handlers).
Any library that implements or bridges to slog.Handler works here:
Zap: logger.NewSlog(zapslog.NewHandler(zapCore))
Zerolog: logger.NewSlog(slogzerolog.Option{Logger: &zl}.NewHandler())
OTEL: logger.NewSlog(otelslog.NewHandler(exporter))
For runtime level control, wrap the handler with NewLevelGate before passing it here (or use NewCharmSlog for GTB's default output).
type Reformatter ¶ added in v0.30.0
type Reformatter interface {
SetFormatter(f Formatter)
}
Reformatter is optionally implemented by a Logger whose output format can be changed at runtime.