logkit

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2026 License: MIT Imports: 14 Imported by: 0

README

go-logkit

CI Go Reference Go Report Card

Structured logging interface backed by zerolog.

Install

go get github.com/takuya-go-kit/go-logkit
import "github.com/takuya-go-kit/go-logkit"

Features

  • Logger interface: Debug, Info, Warn, Error, Fatal; WithFields, WithError
  • Output: console, file, or both (lumberjack rotation for file)
  • Context: IntoContext / FromContext to pass logger in request context
  • Fields: TraceID, RequestID, UserID, Error, Duration, Component for consistent keys
  • Options: WithLevel, WithOutput, WithFileOptions, WithServiceName
  • Noop(): silent logger for tests

Example

l, err := logkit.New(
    logkit.WithLevel(logkit.InfoLevel),
    logkit.WithOutput(logkit.ConsoleOutput),
    logkit.WithServiceName("api"),
)
if err != nil {
    log.Fatal(err)
}
l.Info("started", logkit.RequestID("req-1"), logkit.Duration(time.Second))

ctx := logkit.IntoContext(r.Context(), l)
lFromCtx := logkit.FromContext(ctx)

API

Symbol Description
Logger Interface: Debug, Info, Warn, Error, Fatal(msg, fields...); WithFields, WithError
Level DebugLevel, InfoLevel, WarnLevel, ErrorLevel, FatalLevel
OutputType ConsoleOutput, FileOutput, BothOutput
Fields map[string]any for log event key-value data
New(opts...) Build Logger; returns ErrEmptyFilename if file output without Filename
Noop() Logger that discards all output
IntoContext, FromContext Store/retrieve Logger in context
WithLevel, WithOutput, WithFileOptions, WithServiceName, WithExitFunc Options (WithExitFunc overrides exit on Fatal)
TraceID, RequestID, UserID, Error, Duration, DurationMs, Component Field helpers
SlogHandler Returns slog.Handler for use with log/slog
DebugContext, InfoContext, WarnContext, ErrorContext, FatalContext Context-aware log methods (ctx reserved for future tracing)

Resource cleanup

When using FileOutput or BothOutput, call Close() to flush and release the log file:

l, err := logkit.New(
    logkit.WithOutput(logkit.FileOutput),
    logkit.WithFileOptions(logkit.FileOptions{Filename: "/var/log/app.log"}),
)
if err != nil {
    log.Fatal(err)
}
defer l.Close()

Close() is safe to call multiple times. Only the first call has effect.

Documentation

Overview

Package logkit provides a minimal structured logging interface backed by zerolog. It exposes a Logger interface, optional file rotation via lumberjack, context propagation, and a slog.Handler adapter for use with the standard log/slog package.

Building a logger

New builds a Logger from options. Defaults are InfoLevel and ConsoleOutput. Nil options are ignored. Use WithLevel, WithOutput, WithFileOptions, WithServiceName, and WithExitFunc to configure. New returns ErrEmptyFilename when Output is FileOutput or BothOutput and FileOptions.Filename is empty. Unknown Level values are mapped to InfoLevel.

Output

ConsoleOutput writes to stdout in human-readable format (zerolog console writer). FileOutput uses lumberjack for rotation: set FileOptions with Filename required; MaxSize, MaxBackups, MaxAge use defaults (100 MB, 5 backups, 30 days) when zero. BothOutput writes to stdout and to the file. Child loggers from WithFields or WithError share the root's output and closer; Close on any of them closes the underlying file for all—call Close only on the root logger, typically via defer.

Levels and methods

Logger provides Debug, Info, Warn, Error, and Fatal. Each accepts a message and optional variadic Fields; multiple Fields are merged (later keys override). DebugContext, InfoContext, and similar methods accept context.Context for future use (e.g. trace IDs); the context is not yet used. Fatal writes the event, calls Close, then calls the configured exit function (default os.Exit(1)); deferred functions in the caller are not run. For graceful shutdown use Error and an explicit exit path. Noop returns a logger that discards all output; Fatal on the noop logger does not exit (for tests).

Context

IntoContext stores a logger in the request context; FromContext retrieves it, or Noop() if absent or ctx is nil. IntoContext panics if ctx is nil. Use in middleware to set the request-scoped logger and in handlers to retrieve it.

Field helpers

TraceID, RequestID, UserID, Error, Duration, DurationMs, and Component return Fields with conventional keys (trace_id, request_id, user_id, error, duration, component). Use them for consistent structured logs. Duration formats as a string (e.g. "1.5s"); DurationMs formats as int64 milliseconds for ELK/Loki/ClickHouse. Error returns nil when err is nil (no field added).

slog integration

SlogHandler returns a slog.Handler that forwards log/slog records to a Logger. Use slog.New(SlogHandler(l)) to pass a logkit logger to code that expects slog. WithGroup and WithAttrs are supported.

Conventions

Do not log secrets (passwords, tokens, API keys) or unredacted PII in Fields. Control characters (including \r, \n, NUL, U+2028, U+2029) in messages and in field keys and values are replaced with space to reduce log injection.

Errors

ErrEmptyFilename is the only error returned by New; use errors.Is to detect it.

Thread safety

Logger methods are safe for concurrent use. Close is safe to call from multiple goroutines; only the first call has effect and closes the underlying output for all loggers sharing it.

Testing

Use Noop() when a Logger is required but output should be discarded (e.g. in tests or when logging is disabled). For asserting log calls in unit tests, use the mock package: mock.NewMockLogger(t) returns a MockLogger that implements Logger and records expectations; call EXPECT() to set up and verify calls.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrEmptyFilename is returned by New when Output is FileOutput or BothOutput but FileOptions.Filename is empty.
	// Use errors.Is(err, logkit.ErrEmptyFilename) to detect it and prompt the caller to set WithFileOptions with a non-empty Filename.
	ErrEmptyFilename = errors.New("logkit: filename required for file output")
)

Functions

func IntoContext

func IntoContext(ctx context.Context, l Logger) context.Context

IntoContext stores the logger in ctx so it can be retrieved later with FromContext. Use in middleware to set a request-scoped logger; handlers then call FromContext(ctx) to get it. Panics if ctx is nil. The same ctx should be passed along the request chain.

func SlogHandler

func SlogHandler(l Logger) slog.Handler

SlogHandler returns a slog.Handler that forwards log/slog records to the given Logger. Use slog.New(SlogHandler(l)) so code that expects slog.Logger or slog.Handler can use a logkit Logger. WithGroup and WithAttrs are supported; group names are prefixed to attribute keys (e.g. group "http", attr "method" → "http.method"). The adapter does not filter by level; Enabled always returns true—level filtering is done by the Logger.

Types

type Fields

type Fields map[string]any

Fields is a key-value map attached to a log event. Keys and values are sanitized: control characters (including \r, \n, NUL, U+2028, U+2029) are replaced with space to reduce log injection. Multiple Fields passed to one call are merged; later keys override earlier ones. Shallow-copied when passed to WithFields or log methods; do not mutate the map after passing.

func Component

func Component(name string) Fields

Component returns Fields with the component key. Use to tag events by handler name, service layer, or module so logs can be filtered by component in centralized logging.

func Duration

func Duration(d time.Duration) Fields

Duration returns Fields with the duration key formatted as a string (e.g. "1.5s"). Prefer DurationMs when logs are ingested by structured backends (ELK, Loki, ClickHouse) for querying and aggregation.

func DurationMs

func DurationMs(d time.Duration) Fields

DurationMs returns Fields with the duration key as int64 milliseconds. Use for structured backends (ELK, Loki, ClickHouse) so duration can be queried and aggregated; for human-readable logs use Duration.

func Error

func Error(err error) Fields

Error returns Fields with the error key for structured error logging. Returns nil if err is nil— in that case no field is added, so callers can pass the result directly to log methods.

func RequestID

func RequestID(id string) Fields

RequestID returns Fields with the request_id key. Use the same ID as in HTTP headers (e.g. X-Request-ID) so logs can be correlated with a single request across services.

func TraceID

func TraceID(id string) Fields

TraceID returns Fields with the trace_id key for distributed tracing. Attach to log events when a trace ID is available (e.g. from OpenTelemetry or incoming request headers).

func UserID

func UserID(id string) Fields

UserID returns Fields with the user_id key. Prefer opaque IDs; do not log unredacted PII or tokens.

type FileOptions

type FileOptions struct {
	Filename   string // Log file path (required for FileOutput or BothOutput).
	MaxSize    int    // Max megabytes per file before rotation; zero uses default (100).
	MaxBackups int    // Max number of old files to keep; zero uses default (5).
	MaxAge     int    // Max days to keep old files; zero uses default (30).
	Compress   bool   // Whether to gzip rotated files.
}

FileOptions configures file output (lumberjack). Filename is required when Output is FileOutput or BothOutput. Zero MaxSize, MaxBackups, and MaxAge use internal defaults (100 MB, 5 backups, 30 days); set them for explicit rotation.

type Level

type Level int

Level is the minimum level at which log events are emitted. Events below this level are dropped. Pass to WithLevel when building a logger; unknown values are treated as InfoLevel.

const (
	DebugLevel Level = iota
	InfoLevel
	WarnLevel
	ErrorLevel
	FatalLevel
)

Log levels; DebugLevel is the lowest, FatalLevel the highest.

type Logger

type Logger interface {
	Debug(msg string, fields ...Fields)
	Info(msg string, fields ...Fields)
	Warn(msg string, fields ...Fields)
	Error(msg string, fields ...Fields)
	Fatal(msg string, fields ...Fields)
	DebugContext(ctx context.Context, msg string, fields ...Fields)
	InfoContext(ctx context.Context, msg string, fields ...Fields)
	WarnContext(ctx context.Context, msg string, fields ...Fields)
	ErrorContext(ctx context.Context, msg string, fields ...Fields)
	FatalContext(ctx context.Context, msg string, fields ...Fields)
	WithFields(fields Fields) Logger
	WithError(err error) Logger
	Close() error
}

Logger is the interface for structured logging. Implementations are safe for concurrent use. Close releases underlying output (e.g. file); child loggers from WithFields or WithError share the same output— closing any of them closes it for all. Call Close only once, typically on the root logger via defer.

func FromContext

func FromContext(ctx context.Context) Logger

FromContext returns the logger from ctx (set by IntoContext). Returns Noop() if ctx is nil or if no logger was stored—so callers can always use the result without a nil check.

func New

func New(opts ...Option) (Logger, error)

New builds a Logger from the given options. Defaults are InfoLevel and ConsoleOutput; nil options are ignored. Use WithLevel, WithOutput, WithFileOptions, WithServiceName, and WithExitFunc to configure. When Output is FileOutput or BothOutput, FileOptions.Filename must be set; otherwise New returns ErrEmptyFilename. Unknown Level values are treated as InfoLevel. Call Close on the returned logger when done (e.g. defer) to release file output.

func Noop

func Noop() Logger

Noop returns a Logger that discards all output. Use in tests or when logging is disabled. Fatal does not call os.Exit(1), so it is safe to use in tests without terminating the process. FromContext returns Noop when ctx is nil or when no logger was set via IntoContext.

type Option

type Option func(*Options)

Option configures a logger when passed to New. Nil options are ignored; pass WithLevel, WithOutput, etc.

func WithExitFunc

func WithExitFunc(fn func(int)) Option

WithExitFunc sets the function called by Fatal after logging and Close. If nil, Fatal calls os.Exit(1). Use in tests to avoid terminating the process, or for graceful shutdown (e.g. run exit in a deferred path after flushing).

func WithFileOptions

func WithFileOptions(fo FileOptions) Option

WithFileOptions sets file output options. Required when Output is FileOutput or BothOutput; Filename must be non-empty or New returns ErrEmptyFilename.

func WithLevel

func WithLevel(level Level) Option

WithLevel sets the minimum log level. Events below this level are not emitted; unknown values are treated as InfoLevel.

func WithOutput

func WithOutput(output OutputType) Option

WithOutput sets the output destination. For FileOutput or BothOutput, also set FileOptions via WithFileOptions (Filename required).

func WithServiceName

func WithServiceName(name string) Option

WithServiceName sets the service name; adds a "service" field to every log event. Use for multi-service deployments so logs can be filtered by service in centralized logging.

type Options

type Options struct {
	Level       Level       // Minimum log level.
	Output      OutputType  // Where to write (console, file, or both).
	FileOptions FileOptions // Required when Output is FileOutput or BothOutput.
	ServiceName string      // Added as "service" field to every event when non-empty.
	ExitFunc    func(int)   // Called by Fatal after logging and Close; nil uses os.Exit.
}

Options holds configuration for New. Zero value for Level is treated as InfoLevel; zero Output as ConsoleOutput. When Output is FileOutput or BothOutput, FileOptions.Filename must be set or New returns ErrEmptyFilename.

type OutputType

type OutputType int

OutputType selects where log output is written (console, file, or both).

const (
	ConsoleOutput OutputType = iota
	FileOutput
	BothOutput
)

Output destinations.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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