logging

package
v0.33.9 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package logging provides a unified slog + Sentry logging interface.

Every log call automatically includes a component tag for structured monitoring. Error-level calls auto-capture to Sentry via the sentry-go/slog handler. Use NoCapture in the context to suppress capture for expected errors.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BeforeSend

func BeforeSend(event *sentry.Event, hint *sentry.EventHint) *sentry.Event

BeforeSend is a sentry.EventProcessor that normalises event messages by replacing UUIDs and bare numbers with placeholders. Install on sentry.Init to prevent dynamic values from fragmenting issue grouping.

func NoCapture

func NoCapture(ctx context.Context) context.Context

NoCapture returns a derived context that suppresses Sentry capture for any ErrorContext call made with it. The suppression persists for the lifetime of the derived context — construct it inline so the scope is limited to one call:

log.ErrorContext(logging.NoCapture(ctx), "expected 404", "url", url, "error", err)

Do not store the derived context and reuse it, or all subsequent error log calls on that context will also be silently dropped from Sentry.

func ParseLevel

func ParseLevel(s string) slog.Level

ParseLevel converts a string level name to slog.Level. Supports zerolog-compatible names for backwards compatibility.

func Setup

func Setup(level slog.Level, env string)

Setup configures the global slog default with both stdout output and Sentry capture. Call this after sentry.Init() during application startup.

In development, logs are human-readable text written synchronously to stdout (so test output is deterministic).

In production, logs are JSON written through an AsyncWriter: every slog.Write enqueues into a bounded channel and returns immediately, so no goroutine can wedge inside slog.Handler.Handle waiting on the OS stdout pipe. When the platform log shipper backpressures the pipe, log lines are dropped (with a counter) rather than blocking caller goroutines that may hold DB transactions or other resources.

Error-level logs are auto-captured to Sentry with component tags and static fingerprints.

Types

type AsyncWriter added in v0.33.8

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

AsyncWriter is a non-blocking io.Writer wrapper. Each Write copies the payload into a bounded channel and returns immediately; a single background goroutine drains the channel and writes to the underlying writer in order.

When the channel is full (i.e. the underlying writer can't keep up — typical cause: the platform log shipper has backpressured the stdout pipe), Write drops the payload and increments a counter rather than blocking the caller.

This protects every goroutine in the process from logging-induced wedges: a goroutine that holds a DB transaction or a mutex can no longer get stuck inside slog.Handler.Handle waiting on the OS pipe.

Trade-off: under sustained backpressure some log lines are lost. The alternative — blocking — has been observed in production to wedge goroutines that hold DB connections, leaving Postgres sessions in `idle in transaction (aborted)` for tens of minutes (HOVER-K* class of incidents).

func NewAsyncWriter added in v0.33.8

func NewAsyncWriter(underlying io.Writer, bufferSize int) *AsyncWriter

NewAsyncWriter wraps underlying with a bounded async writer. bufferSize is the max number of pending log lines; choose generously enough to absorb burst spikes (the common case) but bounded enough to bound memory under sustained backpressure. 8192 is a reasonable default.

func StdoutAsync added in v0.33.8

func StdoutAsync() *AsyncWriter

StdoutAsync returns the AsyncWriter wrapping os.Stdout, or nil if Setup has not been called or async logging is disabled (development).

func (*AsyncWriter) Close added in v0.33.8

func (a *AsyncWriter) Close()

Close stops accepting new writes, drains any already-queued lines to the underlying writer, and waits for the drain goroutine to exit. Idempotent and safe to call concurrently with Write.

func (*AsyncWriter) Dropped added in v0.33.8

func (a *AsyncWriter) Dropped() uint64

Dropped returns the cumulative number of log lines dropped due to a full buffer or a closed writer. Exposed for metrics surface.

func (*AsyncWriter) Write added in v0.33.8

func (a *AsyncWriter) Write(p []byte) (int, error)

Write copies p into the channel and returns. It never blocks: when the channel is full or Close has been called, the payload is dropped and the dropped counter is incremented. The returned n is always len(p) so that slog handlers don't treat a drop as a partial write.

Concurrency-safe with Close: instead of closing the data channel (which would race with concurrent Writes), Close signals via the stop channel and Write checks stop before attempting to send. Even if a Write observes stop as not-yet-closed and Close completes during the select, the data channel is never closed, so the send either succeeds (drained later by drain on stop) or hits the default branch (drop).

func (*AsyncWriter) Written added in v0.33.8

func (a *AsyncWriter) Written() uint64

Written returns the cumulative number of log lines successfully written to the underlying writer.

type Logger

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

Logger is a component-scoped structured logger. It rebuilds the underlying slog.Logger at emit time so it always picks up the current slog.Default() (i.e., the fanout handler installed by Setup after sentry.Init).

func Component

func Component(name string) *Logger

Component creates a component-scoped logger. The component name appears as a structured field, a Sentry tag, and a human-readable prefix.

func (*Logger) Debug

func (l *Logger) Debug(msg string, args ...any)

Debug logs at debug level (no Sentry capture).

func (*Logger) DebugContext

func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any)

DebugContext logs at debug level with a context.

func (*Logger) Error

func (l *Logger) Error(msg string, args ...any)

Error logs at error level. Auto-captured to Sentry via the handler. Tags and fingerprint are injected automatically.

func (*Logger) ErrorContext

func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any)

ErrorContext logs at error level with a context. Use NoCapture(ctx) to suppress Sentry capture for expected errors.

func (*Logger) Fatal

func (l *Logger) Fatal(msg string, args ...any)

Fatal logs at error level, captures to Sentry, flushes, and exits.

func (*Logger) Info

func (l *Logger) Info(msg string, args ...any)

Info logs at info level (no Sentry capture).

func (*Logger) InfoContext

func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any)

InfoContext logs at info level with a context.

func (*Logger) Warn

func (l *Logger) Warn(msg string, args ...any)

Warn logs at warn level (no Sentry capture by default).

func (*Logger) WarnContext

func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any)

WarnContext logs at warn level with a context.

func (*Logger) With

func (l *Logger) With(args ...any) *Logger

With returns a new Logger that includes the given attributes on every subsequent log call. Useful for adding request-scoped fields.

Jump to

Keyboard shortcuts

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