Documentation
¶
Overview ¶
Package logkit is an opinionated, extensible layer on top of the standard library's log/slog, built around three ideas:
- Context propagation. Request/correlation/trace ids and ad-hoc business fields travel on context.Context (see the logctx sub-package) so any logkit.Logger call anywhere in the call graph picks them up automatically -- no need to thread a *Logger through every function signature.
- Wide events / canonical log lines. Instead of many scattered, low-context log statements per request, the event sub-package lets you accumulate one rich event and emit it once (see https://loggingsucks.com/ for the rationale).
- Secure by construction. The secure sub-package gives you SafeError (public/internal message separation) and Secret[T] (type-level redaction), following the JetBrains guide to secure Go error handling.
Every extension point is a plain interface from the standard library or from this package: slog.Handler for output destinations, slog.LogValuer for redaction/custom formatting, sampler.Decider for sampling policy. Nothing here is closed for extension.
Index ¶
- Constants
- func LevelString(lvl slog.Level) string
- func ParseLevel(s string) (slog.Level, bool)
- type Config
- type Format
- type Logger
- func (l *Logger) Debug(ctx context.Context, msg string, args ...any)
- func (l *Logger) Error(ctx context.Context, msg string, args ...any)
- func (l *Logger) Fatal(ctx context.Context, msg string, args ...any)
- func (l *Logger) Info(ctx context.Context, msg string, args ...any)
- func (l *Logger) Leveler() *slog.LevelVar
- func (l *Logger) SetLevel(level slog.Level)
- func (l *Logger) Slog() *slog.Logger
- func (l *Logger) Sync() error
- func (l *Logger) Trace(ctx context.Context, msg string, args ...any)
- func (l *Logger) Warn(ctx context.Context, msg string, args ...any)
- func (l *Logger) With(args ...any) *Logger
- func (l *Logger) WithCallerSkip(n int) *Logger
- func (l *Logger) WithError(err error) *Logger
- func (l *Logger) WithGroup(name string) *Logger
- type RedactConfig
Constants ¶
const ( // LevelTrace is for extremely verbose, per-iteration detail that is // normally too noisy even for Debug (e.g. raw wire bytes, tight loop // state). Sits below Debug. LevelTrace slog.Level = slog.LevelDebug - 4 // -8 // LevelFatal is for errors that are about to terminate the process. // Logging at this level does NOT call os.Exit by itself -- that // decision belongs to the caller (see Logger.Fatal), so that the // logger stays testable and side-effect free. LevelFatal slog.Level = slog.LevelError + 4 // 12 )
Custom levels that extend the four built-in slog levels (Debug=-4, Info=0, Warn=4, Error=8).
slog.Level is just an int, so adding new levels is a matter of picking values that sort correctly relative to the built-ins. This is the officially recommended way to extend slog's leveling (see log/slog package docs, "Levels").
Variables ¶
This section is empty.
Functions ¶
func LevelString ¶
LevelString renders lvl using the extended name table, falling back to slog's default String() for anything it doesn't recognize (including levels offset from the named ones, e.g. "INFO+2").
func ParseLevel ¶
ParseLevel parses a case-insensitive level name ("trace", "debug", "info", "warn"/"warning", "error", "fatal") into a slog.Level. This is the counterpart to LevelString and is handy for reading the level out of an env var or config file.
Types ¶
type Config ¶
type Config struct {
// Format picks a built-in handler. Ignored if Handler is set.
Format Format
// Writer is where the built-in handler writes to. Defaults to
// os.Stderr. Ignored if Handler is set.
Writer io.Writer
// Level sets the initial minimum level. Defaults to slog.LevelInfo.
// You can change it later at runtime via Logger.SetLevel --
// New always wraps this in an internal *slog.LevelVar regardless of
// what's passed here.
Level slog.Level
// AddSource includes file:line on every record. Ignored if Handler
// is set (configure it directly on your handler instead).
AddSource bool
// SensitiveKeys is a defense-in-depth redaction list forwarded to
// the built-in handler (see slogx.HandlerOptions.SensitiveKeys).
// Ignored if Handler is set.
SensitiveKeys []string
// Redact configures advanced, Pino-like redaction behavior. If set,
// it takes precedence over SensitiveKeys. Ignored if Handler is set.
Redact *RedactConfig
// ServiceName, Version, Environment, if non-empty, are attached as
// base attributes to every log line -- the minimum "which process
// emitted this" context a wide event / canonical log line needs.
ServiceName string
Version string
Environment string
// Handler, if set, is used as-is instead of building one from
// Format/Writer/AddSource/SensitiveKeys. This is the escape hatch:
// wrap your own slog.Handler (e.g. one that also ships to OTel, or a
// third-party handler) and logkit's context-aware methods,
// SafeError, Secret[T], and event/sampler machinery all keep
// working on top of it unchanged.
Handler slog.Handler
}
Config configures a Logger built with New. All fields are optional; the zero value produces a reasonable development-friendly logger (console format, info level, stderr).
type Format ¶
type Format int
Format selects one of the built-in output formats for New. Use Config.Handler instead if you need something these don't cover -- Format/Writer is a convenience, not the only way in.
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger wraps a slog.Handler with context-aware logging methods and a runtime-adjustable level. It is cheap to copy and safe for concurrent use (same guarantees as *slog.Logger, which it wraps).
func NewDefault ¶
func NewDefault() *Logger
NewDefault returns a ready-to-use development Logger: colorized console output on stderr, info level. Equivalent to New(Config{Format: FormatConsole}).
func NewNop ¶
func NewNop() *Logger
NewNop returns a Logger that discards everything. Useful as a default in code that takes a *Logger but shouldn't panic if the caller (e.g. a test) doesn't provide one.
func (*Logger) Debug ¶
Debug logs at slog.LevelDebug: development/diagnostic detail not normally enabled in production.
func (*Logger) Error ¶
Error logs at slog.LevelError. If args contains an error under the key "error" whose value implements slog.LogValuer (e.g. *secure.SafeError), it's expanded/redacted automatically -- no special handling needed at the call site beyond secure.Wrap/secure.New producing that kind of error in the first place.
func (*Logger) Fatal ¶
Fatal logs at LevelFatal and then terminates the process via os.Exit(1). Use sparingly and only at the outermost level (e.g. main(), or a supervisor goroutine deciding the process can't continue) -- never in library code, since it removes the caller's ability to handle the failure. Prefer returning an error everywhere else.
func (*Logger) Info ¶
Info logs at slog.LevelInfo: normal operational messages and wide events / canonical log lines.
func (*Logger) Leveler ¶
Leveler returns the *slog.LevelVar backing this logger, so callers can wire it up to, say, an admin HTTP endpoint or a SIGHUP handler to change verbosity without restarting the process.
func (*Logger) SetLevel ¶
SetLevel changes the minimum level for this logger (and everything derived from it via With/WithGroup, since they share the same *slog.LevelVar) at runtime.
func (*Logger) Slog ¶
Slog returns the underlying *slog.Logger, for interoperability with libraries that expect one directly (e.g. http.Server.ErrorLog via slog.NewLogLogger, or third-party packages that accept a *slog.Logger for their own logging).
func (*Logger) Sync ¶
Sync flushes any buffered log entries. Call this before the program exits (for example, via defer logger.Sync()) to ensure all logs are written.
func (*Logger) Trace ¶
Trace logs at LevelTrace: the most verbose level, for detail too noisy even for Debug.
func (*Logger) Warn ¶
Warn logs at slog.LevelWarn: recoverable problems worth a human's attention but not an immediate page.
func (*Logger) With ¶
With returns a new Logger with args attached to every subsequent log call, exactly like slog.Logger.With. Cheap; does not affect l.
func (*Logger) WithCallerSkip ¶
WithCallerSkip returns a new Logger that skips an additional n frames when resolving the file:line of a log call. This is useful when writing helper functions or logging middleware wrappers.
type RedactConfig ¶
type RedactConfig = slogx.RedactConfig
RedactConfig configures advanced, path-based log redaction.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package event implements the "wide event" / "canonical log line" pattern from https://loggingsucks.com/: instead of scattering 15 vague log statements across a request's lifecycle, accumulate a single, rich, structured event as the request flows through your code, then emit it exactly once when the request finishes.
|
Package event implements the "wide event" / "canonical log line" pattern from https://loggingsucks.com/: instead of scattering 15 vague log statements across a request's lifecycle, accumulate a single, rich, structured event as the request flows through your code, then emit it exactly once when the request finishes. |
|
examples
|
|
|
basicapp
command
Example: basic usage of logkit outside of any HTTP/gRPC framework -- levels, context propagation, secret redaction, and safe errors.
|
Example: basic usage of logkit outside of any HTTP/gRPC framework -- levels, context propagation, secret redaction, and safe errors. |
|
httpapp
command
Example: an HTTP server using httpmw to get one canonical log line per request, automatic request-id propagation, panic recovery, and secure error responses -- all pluggable via a plain func(http.Handler) http.Handler, so this drops straight into chi (r.Use(mw)) with no adapter.
|
Example: an HTTP server using httpmw to get one canonical log line per request, automatic request-id propagation, panic recovery, and secure error responses -- all pluggable via a plain func(http.Handler) http.Handler, so this drops straight into chi (r.Use(mw)) with no adapter. |
|
Package logctx carries per-request identifiers (request id, correlation id, trace/span id, tenant/user id, ...) through context.Context so that any logger call deep in the stack can pick them up automatically, without every function signature needing to grow a *Logger parameter.
|
Package logctx carries per-request identifiers (request id, correlation id, trace/span id, tenant/user id, ...) through context.Context so that any logger call deep in the stack can pick them up automatically, without every function signature needing to grow a *Logger parameter. |
|
middleware
|
|
|
httpmw
Package httpmw wires logkit into an HTTP server: it generates/propagates a request id, builds a wide event (see the event package) for the request, recovers panics into a safe 500 response, and emits exactly one canonical log line per request when it completes.
|
Package httpmw wires logkit into an HTTP server: it generates/propagates a request id, builds a wide event (see the event package) for the request, recovers panics into a safe 500 response, and emits exactly one canonical log line per request when it completes. |
|
Package sampler implements the tail-sampling pattern described in https://loggingsucks.com/: make the "keep or drop this event" decision *after* the request completes, based on its outcome, instead of randomly sampling up front and risking dropping the exact request that would have explained an outage.
|
Package sampler implements the tail-sampling pattern described in https://loggingsucks.com/: make the "keep or drop this event" decision *after* the request completes, based on its outcome, instead of randomly sampling up front and risking dropping the exact request that would have explained an outage. |
|
Package secure provides the building blocks recommended by secure Go error-handling guidance (see the JetBrains "Secure Error Handling in Go" guide) on top of log/slog:
|
Package secure provides the building blocks recommended by secure Go error-handling guidance (see the JetBrains "Secure Error Handling in Go" guide) on top of log/slog: |
|
Package slogx contains ready-to-use slog.Handler implementations (JSON for production, colorized console for local dev, and a fan-out multi-handler) plus the small pieces of handler-level plumbing -- key-based redaction and dynamic level -- that most services end up needing.
|
Package slogx contains ready-to-use slog.Handler implementations (JSON for production, colorized console for local dev, and a fan-out multi-handler) plus the small pieces of handler-level plumbing -- key-based redaction and dynamic level -- that most services end up needing. |