Help us shape the future of Go! Take the 2026 Go Developer Survey

logging

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 23 Imported by: 0

README

Logging

New(writer, Options) creates a standard slog logger over a borrowed writer. WithLogger and FromContext carry execution-scoped fields without changing the global logger.

Tint output uses full DEBUG, INFO, WARN and ERROR severity names, matching JSON output. When adopting this fix, port the Tint formatter in logger.go and the log viewer parser in internal/platform/logviewer/store.go together. The viewer also recognizes older Tint files containing DBG, INF, WRN and ERR; existing files need no conversion.

For named outputs, Open(Config) creates a manager. Default() uses the configured default channel list; Logger(names...) selects exact outputs. Select(logger, names...) and Channels(ctx, names...) preserve fields and groups when switching outputs. Unknown or repeated names return errors. Channels require the manager's handler; wrapping it in an unrelated handler prevents selection.

Built-in drivers: stdout, stderr, append-only file and asynchronous otlp. Each channel has its own format and minimum level. Custom drivers are explicit functions in Config.Drivers, not global registrations. They return a concurrency-safe slog handler and an optional owned closer. Standard streams are borrowed and never closed.

Config.WrapHandler optionally decorates each channel's handler once when it opens, including channels selected later. The decorator must return a non-nil, concurrency-safe handler that preserves Enabled, WithAttrs, and WithGroup; it borrows the output and does not close it. This is the app's hook for bounded local log capture without changing output selection or replacing the manager's public handler.

Open validates the complete configuration and opens only default outputs, closing acquired resources if construction fails. Other outputs open on first explicit selection. Concurrent selections share one output per channel. Failed opens may be retried; outputs already acquired remain owned until Close. Field/group derivation never opens unselected channels. Selection after Close returns an error. Stop logger users before closing the manager. Close is idempotent and preserves closer errors. Derived loggers share those resources and must not outlive them.

Fanout invokes each enabled output in selection order. Console/file writes are synchronous; OTLP queues records for asynchronous export. Returned handler errors do not stop other outputs. Config.OnError reports them; the default reports directly to stderr. Callbacks must be concurrency-safe and avoid recursive logging. Logging is best-effort, not durable transactional audit storage.

Open fixes relative file paths against the working directory with filepath.Abs, including channels selected later. It never searches for a project root or uses the executable location. File output creates missing directories (0750) and files (0600), subject to umask. Existing permissions are unchanged. Single-file output does not rotate or reopen after external rotation; daily mode rotates by UTC date. Neither mode fsyncs each record. Prefer container standard streams and a collector where possible.

Application definitions live in internal/app/config/observability.go; the reusable package never reads environment variables or imports app configuration. See the application guide for runnable usage and extension examples.

Trace correlation

Context-aware calls add trace_id, span_id, and trace_sampled from the current OpenTelemetry span. This applies to New, built-in channels and custom channel drivers. No valid span means no added fields. Deriving or switching loggers does not capture a span; child operations use their own context. Correlation follows the active WithGroup scope. Reserve these field names and use InfoContext and similar methods. Plain slog loggers outside this package are unchanged.

Daily file output

Set file options on a named channel:

logging.Channel{
    Driver:   "file",
    Path:     "storage/logs/app.log",
    FileMode: logging.FileDaily,
    KeepDays: 7,
}

The default FileSingle (or empty mode) appends to app.log and requires KeepDays: 0. Daily mode appends to app-YYYY-MM-DD.log in UTC; seven retention days means today plus the previous six calendar dates. Zero keeps all daily files. Cleanup runs on opening and daily rotation, not in a background worker. It only removes matching regular dated files. Give each channel/process its own path. Rotation failures reach Config.OnError and retry on the next write. Neither mode provides size limits or per-record fsync. If a collector tails the daily channel, configure its file target to match the dated filenames.

OTLP log delivery

logging.Channel{
    Driver: "otlp",
    Options: logging.Options{Level: slog.LevelInfo},
    OTLP: logging.OTLPOptions{
        Endpoint: "http://localhost:4318/v1/logs",
        ServiceName: "orders",
    },
}

The native OpenTelemetry slog bridge preserves attributes/groups, severity and trace context, without global providers or filesystem output. OTLP format is structured protocol data; tint is rejected. Empty service names use unknown_service for standalone callers; app configuration requires a name when exporting logs.

A bounded nonblocking queue holds 2,048 records, with batches of up to 512 every second. Oldest records drop on overflow; failed batches are discarded. Export failures use rate-limited, payload-free stderr diagnostics; queue drops use SDK stderr diagnostics. OnError only covers synchronous handler failures.

Manager.Shutdown(ctx) flushes within the smaller of the caller deadline and OTLPOptions.ShutdownTimeout (default 3s). Close() uses the configured budget. ExportTimeout defaults to 5s; zero selects these defaults. Application work never waits for the collector on the logging call, and collector outages do not block construction. Stop producers before shutdown. Queues are not durable, and shutdown success is not proof that every prior batch was delivered.

Documentation

Overview

Package logging provides execution-scoped structured logging.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Channels

func Channels(ctx context.Context, names ...string) (*slog.Logger, error)

Channels selects outputs from the context logger, preserving With/WithGroup fields. A logger created with New or an unrelated handler has no named channels.

func ErrorCategory

func ErrorCategory(err error) string

ErrorCategory returns a bounded diagnostic category without exposing error text. It recognizes wrapped causes. It is for reporting, not retry or business policy.

func FromContext

func FromContext(ctx context.Context) *slog.Logger

func New

func New(output io.Writer, options Options) (*slog.Logger, error)

New creates an independent logger; it does not replace slog.Default or own the writer. Tint is intended for development; JSON remains the default.

func Select

func Select(logger *slog.Logger, names ...string) (*slog.Logger, error)

Select derives a logger with different outputs and the same attached fields.

func WithLogger

func WithLogger(ctx context.Context, logger *slog.Logger) context.Context

WithLogger attaches a request/job logger, not a dependency container.

Types

type Channel

type Channel struct {
	Driver  string
	Path    string
	Options Options
	// FileMode selects single-file (default) or daily output for the file driver.
	FileMode FileMode
	// KeepDays retains this many UTC calendar days, including today, in daily
	// mode. Zero keeps all files. Single-file mode requires zero.
	KeepDays int
	// OTLP configures the otlp driver. Other drivers do not use it.
	OTLP OTLPOptions
}

Channel configures one output. Open resolves relative file paths against the working directory once, including channels selected later.

type Config

type Config struct {
	Default  []string
	Channels map[string]Channel
	Drivers  map[string]Driver
	// WrapHandler optionally decorates each opened channel once, before deriving
	// scoped loggers. It must preserve Enabled, support concurrent use and return
	// a non-nil handler. The decorator borrows the output; Manager owns its lifetime.
	WrapHandler func(name string, handler slog.Handler) slog.Handler
	// OnError reports synchronous output failures, which slog.Logger otherwise discards.
	// Asynchronous OTLP export failures use independent stderr diagnostics.
	// It must be concurrency-safe and must not log back through these channels.
	// Nil reports failures directly to stderr.
	OnError func(context.Context, string, error)
}

Config defines named channels and the default fanout. Drivers adds custom drivers without global registration. Channels and Drivers are borrowed during Open.

func (Config) Validate

func (c Config) Validate() error

type Driver

type Driver func(Channel) (slog.Handler, io.Closer, error)

Driver opens a concurrency-safe handler and optionally an owned resource. On failure it must clean up its partial initialization. Borrowed resources must return a nil closer. Handlers must obey the slog.Handler ownership contract. A closer implementing Shutdown(context.Context) error receives the manager's shutdown context; otherwise the manager calls Close.

type FileMode

type FileMode string

FileMode selects how the file driver names and rotates its output.

const (
	FileSingle FileMode = "single"
	FileDaily  FileMode = "daily"
)

type Format

type Format string

Format selects a slog handler while preserving its environment/JSON spelling.

const (
	// FormatDefault uses JSON, preserving the zero-value behavior.
	FormatDefault Format = ""
	FormatJSON    Format = "json"
	FormatTint    Format = "tint"
)

func (Format) Validate

func (f Format) Validate() error

type Manager

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

Manager owns opened channel resources. Loggers support concurrent use; Close must run after their users finish. It never changes slog.Default.

func Open

func Open(cfg Config) (_ *Manager, err error)

Open validates all definitions and opens only default channels. Other channels open when explicitly selected. A failed selection can be retried. It closes acquired resources on failure. File output appends, creates directories with mode 0750 and new files with mode 0600. Daily files optionally expire by date; neither mode fsyncs each record.

func (*Manager) Close

func (m *Manager) Close() error

func (*Manager) Default

func (m *Manager) Default() *slog.Logger

Default returns the logger for the configured default channels.

func (*Manager) Logger

func (m *Manager) Logger(names ...string) (*slog.Logger, error)

Logger selects only the named channels; it does not append default channels.

func (*Manager) Shutdown

func (m *Manager) Shutdown(ctx context.Context) error

Shutdown closes outputs once, flushing OTLP within the caller's deadline and the channel's shutdown budget. Stop producers first. Close uses channel budgets.

type OTLPOptions

type OTLPOptions struct {
	Endpoint        string
	ServiceName     string
	Environment     string
	ExportTimeout   time.Duration
	ShutdownTimeout time.Duration
}

OTLPOptions configures asynchronous OTLP/HTTP log delivery. Endpoint is the full URL including /v1/logs. Put backend credentials in a collector, not this URL. Zero timeouts use five seconds for export and three seconds for shutdown. An empty ServiceName uses unknown_service for standalone callers.

func (OTLPOptions) Validate

func (o OTLPOptions) Validate() error

type Options

type Options struct {
	Format  Format
	Level   slog.Level
	NoColor bool
}

Options selects the output handler without changing application logging calls. The zero value uses JSON at INFO level.

Jump to

Keyboard shortcuts

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