log

package module
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Apr 12, 2026 License: Apache-2.0 Imports: 11 Imported by: 9

README

CI Go Report Card GoDoc

log

import "github.com/go-coldbrew/log"

Package log provides structured logging for ColdBrew microservices.

It uses a custom slog.Handler that automatically injects per-request context fields (added via AddToContext or AddAttrsToContext) into every log record.

Quick Start

Use the package-level functions for simple logging:

log.Info(ctx, "msg", "order processed", "order_id", "ORD-123")
log.Error(ctx, "msg", "connection failed", "host", "db.internal")
Native slog Support

After calling SetDefault, native slog calls automatically get ColdBrew context fields:

log.SetDefault(log.NewHandler())
ctx := context.Background()
ctx = log.AddToContext(ctx, "trace_id", "abc-123")
slog.InfoContext(ctx, "request handled", "status", 200) // includes trace_id
Adding Context Fields

Use AddAttrsToContext to add typed slog.Attr fields, or AddToContext for untyped key-value pairs. Both are included in all subsequent logs for that request:

ctx := context.Background()
ctx = log.AddAttrsToContext(ctx,
    slog.String("trace_id", id),
    slog.Int("user_id", uid),
)

AddAttrsToContext stores each slog.Attr in the context. At log time, the Handler recovers the typed Attr and emits it directly. Context storage goes through an any-typed API internally (one boxing per field per request), but the Attr's type information is preserved for emission.

High\-Performance Logging

Combine AddAttrsToContext with [slog.LogAttrs] for the lowest-overhead path. Per-call attributes passed to [slog.LogAttrs] avoid interface boxing entirely:

slog.LogAttrs(ctx, slog.LevelInfo, "request handled",
    slog.Int("status", 200),
    slog.Duration("latency", elapsed),
)
Custom Handlers

Use NewHandlerWithInner to compose ColdBrew's context injection with any slog.Handler:

multi := slogmulti.Fanout(jsonHandler, textHandler)
h := log.NewHandlerWithInner(multi)
log.SetDefault(h)

ColdBrew interceptors automatically add grpcMethod, trace ID, and HTTP path to the context, so these fields appear in all service logs.

Index

Constants

SupportPackageIsVersion1 is a compile-time assertion constant. Downstream packages reference this to enforce version compatibility.

const SupportPackageIsVersion1 = true

func AddAttrsToContext

func AddAttrsToContext(ctx context.Context, attrs ...slog.Attr) context.Context

AddAttrsToContext adds typed slog.Attr fields to the context. Each Attr is stored keyed by its own Key. At log time, the Handler recovers the typed Attr via a type switch, preserving the original slog type information.

Note: context storage goes through an any-typed API internally, so the Attr is boxed once when stored. The benefit is at log emission time — the Handler emits the Attr directly instead of wrapping it in slog.Any. Combine with slog.LogAttrs for per-call attrs to avoid boxing on the hot path:

ctx = log.AddAttrsToContext(ctx,
    slog.String("trace_id", id),
    slog.Int("user_id", uid),
)
slog.LogAttrs(ctx, slog.LevelInfo, "handled", slog.Int("status", 200))
Example

package main

import (
	"context"
	"log/slog"

	"github.com/go-coldbrew/log"
)

func main() {
	// SetDefault wires ColdBrew's Handler into slog so context fields are injected.
	// In production, core.New() calls this automatically.
	log.SetDefault(log.NewHandler())

	ctx := context.Background()

	// Typed attrs — the Handler recovers the slog.Attr at log time.
	// Per-call attrs via slog.LogAttrs avoid interface boxing entirely.
	ctx = log.AddAttrsToContext(ctx,
		slog.String("trace_id", "abc-123"),
		slog.Int("user_id", 42),
	)

	slog.LogAttrs(ctx, slog.LevelInfo, "request handled", slog.Int("status", 200))
}

func AddToContext

func AddToContext(ctx context.Context, key string, value any) context.Context

AddToContext adds log fields to the provided context. Any info added here will be included in all logs that use the returned context. This works with both ColdBrew's log functions and native slog.InfoContext.

Example

package main

import (
	"context"

	"github.com/go-coldbrew/log"
)

func main() {
	ctx := context.Background()

	// Add per-request fields to context — these appear in all subsequent log lines
	ctx = log.AddToContext(ctx, "request_id", "abc-123")
	ctx = log.AddToContext(ctx, "user_id", "user-42")

	// All logs using this context now include request_id and user_id
	log.Info(ctx, "msg", "processing request", "step", "validation")
	log.Info(ctx, "msg", "request complete", "status", "ok", "duration_ms", 42)
}

func Debug

func Debug(ctx context.Context, args ...any)

Debug writes out a debug log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.DebugLevel, 1, args...)

func DefaultIsSet

func DefaultIsSet() bool

DefaultIsSet reports whether SetDefault has been called explicitly. Used by core to avoid overwriting a user-configured handler.

func Error

func Error(ctx context.Context, args ...any)

Error writes out an error log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.ErrorLevel, 1, args...)

Example

package main

import (
	"context"

	"github.com/go-coldbrew/log"
)

func main() {
	ctx := context.Background()
	log.Error(ctx, "msg", "database connection failed", "host", "db.internal", "port", 5432, "retry_in", "5s")
}

func FromSlogLevel

func FromSlogLevel(level slog.Level) loggers.Level

FromSlogLevel converts an slog.Level to a ColdBrew log level.

func GetLevel

func GetLevel() loggers.Level

GetLevel returns the current log level This is useful for checking if a log level is enabled

func GetOverridenLogLevel

func GetOverridenLogLevel(ctx context.Context) (loggers.Level, bool)

GetOverridenLogLevel fetches overriden log level from context If no log level is overriden, it returns false If log level is overriden, it returns the log level and true

func Info

func Info(ctx context.Context, args ...any)

Info writes out an info log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.InfoLevel, 1, args...)

Example

package main

import (
	"context"

	"github.com/go-coldbrew/log"
)

func main() {
	ctx := context.Background()
	log.Info(ctx, "msg", "order processed", "order_id", "ORD-123", "items", 3)
}

func OverrideLogLevel

func OverrideLogLevel(ctx context.Context, level loggers.Level) context.Context

OverrideLogLevel allows the default log level to be overridden from request context This is useful when you want to override the log level for a specific request For example, you can set the log level to debug for a specific request while the default log level is set to info

func SetDefault

func SetDefault(h *Handler)

SetDefault sets the global ColdBrew handler and also calls slog.SetDefault so that native slog.InfoContext/slog.ErrorContext calls automatically get ColdBrew context fields injected.

func SetLevel

func SetLevel(level loggers.Level)

SetLevel sets the log level to filter logs

func SetLogger

func SetLogger(l Logger)

SetLogger sets the global logger.

Deprecated: Use SetDefault with a *Handler instead. SetLogger is kept for backward compatibility with code that implements the Logger interface.

func ToSlogLevel

func ToSlogLevel(level loggers.Level) slog.Level

ToSlogLevel converts a ColdBrew log level to an slog.Level.

func Warn

func Warn(ctx context.Context, args ...any)

Warn writes out a warning log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.WarnLevel, 1, args...)

type Handler

Handler implements slog.Handler with automatic ColdBrew context field injection. Any fields added via loggers.AddToLogContext (or log.AddToContext) are automatically included in every log record processed by this handler.

Handler is composable — it can wrap any slog.Handler as its inner handler, and it can itself be wrapped by other slog.Handler implementations (e.g., slog-multi). WithAttrs and WithGroup return new *Handler instances that preserve context injection.

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

func GetHandler
func GetHandler() *Handler

GetHandler returns the global ColdBrew Handler.

func NewHandler
func NewHandler(options ...loggers.Option) *Handler

NewHandler creates a new Handler with the default inner handler (slog.JSONHandler or slog.TextHandler based on options).

func NewHandlerWithInner
func NewHandlerWithInner(inner slog.Handler, options ...loggers.Option) *Handler

NewHandlerWithInner creates a new Handler wrapping the provided slog.Handler. Use this to compose ColdBrew's context injection with custom handlers (e.g., slog-multi for fan-out, sampling handlers, or custom formatters).

Example:

multi := slogmulti.Fanout(jsonHandler, textHandler)
h := log.NewHandlerWithInner(multi)
log.SetDefault(h)

func (*Handler) Enabled
func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool

Enabled reports whether the handler handles records at the given level. It checks both the configured level and any per-request level override set via OverrideLogLevel. This means per-request debug logging works even for native slog.DebugContext calls.

func (*Handler) GetLevel
func (h *Handler) GetLevel() loggers.Level

GetLevel returns the current log level.

func (*Handler) Handle
func (h *Handler) Handle(ctx context.Context, record slog.Record) error

Handle processes the log record, injecting ColdBrew context fields and caller info, then delegates to the inner handler.

func (*Handler) Inner
func (h *Handler) Inner() slog.Handler

Inner returns the wrapped slog.Handler.

func (*Handler) SetLevel
func (h *Handler) SetLevel(level loggers.Level)

SetLevel changes the log level dynamically. If the inner handler supports SetLevel (e.g., the BaseLogger adapter), the level change is propagated.

func (*Handler) WithAttrs
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a new Handler with the given attributes pre-applied. The returned handler preserves ColdBrew context field injection.

func (*Handler) WithGroup
func (h *Handler) WithGroup(name string) slog.Handler

WithGroup returns a new Handler with the given group name. The returned handler preserves ColdBrew context field injection.

type Logger

Logger is the interface for ColdBrew's structured logging. It extends loggers.BaseLogger with convenience methods for each log level.

type Logger interface {
    loggers.BaseLogger //nolint:staticcheck // intentional use for backward compatibility
    // Debug logs a message at level Debug.
    // ctx is used to extract per-request context fields.
    Debug(ctx context.Context, args ...any)
    // Info logs a message at level Info.
    // ctx is used to extract per-request context fields.
    Info(ctx context.Context, args ...any)
    // Warn logs a message at level Warn.
    // ctx is used to extract per-request context fields.
    Warn(ctx context.Context, args ...any)
    // Error logs a message at level Error.
    // ctx is used to extract per-request context fields.
    Error(ctx context.Context, args ...any)
}

func GetLogger
func GetLogger() Logger

GetLogger returns the global logger. If the global logger is not set, it will create a new one with the default Handler.

func NewLogger
func NewLogger(bl loggers.BaseLogger) Logger

NewLogger creates a new logger with a provided BaseLogger.

Deprecated: Use NewHandler or NewHandlerWithInner instead. NewLogger is kept for backward compatibility.

Generated by gomarkdoc

Documentation

Overview

Package log provides structured logging for ColdBrew microservices.

It uses a custom slog.Handler that automatically injects per-request context fields (added via AddToContext or AddAttrsToContext) into every log record.

Quick Start

Use the package-level functions for simple logging:

log.Info(ctx, "msg", "order processed", "order_id", "ORD-123")
log.Error(ctx, "msg", "connection failed", "host", "db.internal")

Native slog Support

After calling SetDefault, native slog calls automatically get ColdBrew context fields:

log.SetDefault(log.NewHandler())
ctx := context.Background()
ctx = log.AddToContext(ctx, "trace_id", "abc-123")
slog.InfoContext(ctx, "request handled", "status", 200) // includes trace_id

Adding Context Fields

Use AddAttrsToContext to add typed slog.Attr fields, or AddToContext for untyped key-value pairs. Both are included in all subsequent logs for that request:

ctx := context.Background()
ctx = log.AddAttrsToContext(ctx,
    slog.String("trace_id", id),
    slog.Int("user_id", uid),
)

AddAttrsToContext stores each slog.Attr in the context. At log time, the Handler recovers the typed Attr and emits it directly. Context storage goes through an any-typed API internally (one boxing per field per request), but the Attr's type information is preserved for emission.

High-Performance Logging

Combine AddAttrsToContext with slog.LogAttrs for the lowest-overhead path. Per-call attributes passed to slog.LogAttrs avoid interface boxing entirely:

slog.LogAttrs(ctx, slog.LevelInfo, "request handled",
    slog.Int("status", 200),
    slog.Duration("latency", elapsed),
)

Custom Handlers

Use NewHandlerWithInner to compose ColdBrew's context injection with any slog.Handler:

multi := slogmulti.Fanout(jsonHandler, textHandler)
h := log.NewHandlerWithInner(multi)
log.SetDefault(h)

ColdBrew interceptors automatically add grpcMethod, trace ID, and HTTP path to the context, so these fields appear in all service logs.

Index

Examples

Constants

View Source
const SupportPackageIsVersion1 = true

SupportPackageIsVersion1 is a compile-time assertion constant. Downstream packages reference this to enforce version compatibility.

Variables

This section is empty.

Functions

func AddAttrsToContext added in v0.4.0

func AddAttrsToContext(ctx context.Context, attrs ...slog.Attr) context.Context

AddAttrsToContext adds typed slog.Attr fields to the context. Each Attr is stored keyed by its own Key. At log time, the Handler recovers the typed Attr via a type switch, preserving the original slog type information.

Note: context storage goes through an any-typed API internally, so the Attr is boxed once when stored. The benefit is at log emission time — the Handler emits the Attr directly instead of wrapping it in slog.Any. Combine with slog.LogAttrs for per-call attrs to avoid boxing on the hot path:

ctx = log.AddAttrsToContext(ctx,
    slog.String("trace_id", id),
    slog.Int("user_id", uid),
)
slog.LogAttrs(ctx, slog.LevelInfo, "handled", slog.Int("status", 200))
Example
package main

import (
	"context"
	"log/slog"

	"github.com/go-coldbrew/log"
)

func main() {
	// SetDefault wires ColdBrew's Handler into slog so context fields are injected.
	// In production, core.New() calls this automatically.
	log.SetDefault(log.NewHandler())

	ctx := context.Background()

	// Typed attrs — the Handler recovers the slog.Attr at log time.
	// Per-call attrs via slog.LogAttrs avoid interface boxing entirely.
	ctx = log.AddAttrsToContext(ctx,
		slog.String("trace_id", "abc-123"),
		slog.Int("user_id", 42),
	)

	slog.LogAttrs(ctx, slog.LevelInfo, "request handled", slog.Int("status", 200))
}

func AddToContext added in v0.2.6

func AddToContext(ctx context.Context, key string, value any) context.Context

AddToContext adds log fields to the provided context. Any info added here will be included in all logs that use the returned context. This works with both ColdBrew's log functions and native slog.InfoContext.

Example
package main

import (
	"context"

	"github.com/go-coldbrew/log"
)

func main() {
	ctx := context.Background()

	// Add per-request fields to context — these appear in all subsequent log lines
	ctx = log.AddToContext(ctx, "request_id", "abc-123")
	ctx = log.AddToContext(ctx, "user_id", "user-42")

	// All logs using this context now include request_id and user_id
	log.Info(ctx, "msg", "processing request", "step", "validation")
	log.Info(ctx, "msg", "request complete", "status", "ok", "duration_ms", 42)
}

func Debug

func Debug(ctx context.Context, args ...any)

Debug writes out a debug log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.DebugLevel, 1, args...)

func DefaultIsSet added in v0.4.1

func DefaultIsSet() bool

DefaultIsSet reports whether SetDefault has been called explicitly. Used by core to avoid overwriting a user-configured handler.

func Error

func Error(ctx context.Context, args ...any)

Error writes out an error log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.ErrorLevel, 1, args...)

Example
package main

import (
	"context"

	"github.com/go-coldbrew/log"
)

func main() {
	ctx := context.Background()
	log.Error(ctx, "msg", "database connection failed", "host", "db.internal", "port", 5432, "retry_in", "5s")
}

func FromSlogLevel added in v0.4.0

func FromSlogLevel(level slog.Level) loggers.Level

FromSlogLevel converts an slog.Level to a ColdBrew log level.

func GetLevel

func GetLevel() loggers.Level

GetLevel returns the current log level This is useful for checking if a log level is enabled

func GetOverridenLogLevel added in v0.2.2

func GetOverridenLogLevel(ctx context.Context) (loggers.Level, bool)

GetOverridenLogLevel fetches overriden log level from context If no log level is overriden, it returns false If log level is overriden, it returns the log level and true

func Info

func Info(ctx context.Context, args ...any)

Info writes out an info log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.InfoLevel, 1, args...)

Example
package main

import (
	"context"

	"github.com/go-coldbrew/log"
)

func main() {
	ctx := context.Background()
	log.Info(ctx, "msg", "order processed", "order_id", "ORD-123", "items", 3)
}

func OverrideLogLevel added in v0.2.2

func OverrideLogLevel(ctx context.Context, level loggers.Level) context.Context

OverrideLogLevel allows the default log level to be overridden from request context This is useful when you want to override the log level for a specific request For example, you can set the log level to debug for a specific request while the default log level is set to info

func SetDefault added in v0.4.0

func SetDefault(h *Handler)

SetDefault sets the global ColdBrew handler and also calls slog.SetDefault so that native slog.InfoContext/slog.ErrorContext calls automatically get ColdBrew context fields injected.

func SetLevel

func SetLevel(level loggers.Level)

SetLevel sets the log level to filter logs

func SetLogger deprecated

func SetLogger(l Logger)

SetLogger sets the global logger.

Deprecated: Use SetDefault with a *Handler instead. SetLogger is kept for backward compatibility with code that implements the Logger interface.

func ToSlogLevel added in v0.4.0

func ToSlogLevel(level loggers.Level) slog.Level

ToSlogLevel converts a ColdBrew log level to an slog.Level.

func Warn

func Warn(ctx context.Context, args ...any)

Warn writes out a warning log to global logger This is a convenience function for GetLogger().Log(ctx, loggers.WarnLevel, 1, args...)

Types

type Handler added in v0.4.0

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

Handler implements slog.Handler with automatic ColdBrew context field injection. Any fields added via loggers.AddToLogContext (or log.AddToContext) are automatically included in every log record processed by this handler.

Handler is composable — it can wrap any slog.Handler as its inner handler, and it can itself be wrapped by other slog.Handler implementations (e.g., slog-multi). WithAttrs and WithGroup return new *Handler instances that preserve context injection.

func GetHandler added in v0.4.0

func GetHandler() *Handler

GetHandler returns the global ColdBrew Handler.

func NewHandler added in v0.4.0

func NewHandler(options ...loggers.Option) *Handler

NewHandler creates a new Handler with the default inner handler (slog.JSONHandler or slog.TextHandler based on options).

func NewHandlerWithInner added in v0.4.0

func NewHandlerWithInner(inner slog.Handler, options ...loggers.Option) *Handler

NewHandlerWithInner creates a new Handler wrapping the provided slog.Handler. Use this to compose ColdBrew's context injection with custom handlers (e.g., slog-multi for fan-out, sampling handlers, or custom formatters).

Example:

multi := slogmulti.Fanout(jsonHandler, textHandler)
h := log.NewHandlerWithInner(multi)
log.SetDefault(h)

func (*Handler) Enabled added in v0.4.0

func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool

Enabled reports whether the handler handles records at the given level. It checks both the configured level and any per-request level override set via OverrideLogLevel. This means per-request debug logging works even for native slog.DebugContext calls.

func (*Handler) GetLevel added in v0.4.0

func (h *Handler) GetLevel() loggers.Level

GetLevel returns the current log level.

func (*Handler) Handle added in v0.4.0

func (h *Handler) Handle(ctx context.Context, record slog.Record) error

Handle processes the log record, injecting ColdBrew context fields and caller info, then delegates to the inner handler.

func (*Handler) Inner added in v0.4.0

func (h *Handler) Inner() slog.Handler

Inner returns the wrapped slog.Handler.

func (*Handler) SetLevel added in v0.4.0

func (h *Handler) SetLevel(level loggers.Level)

SetLevel changes the log level dynamically. If the inner handler supports SetLevel (e.g., the BaseLogger adapter), the level change is propagated.

func (*Handler) WithAttrs added in v0.4.0

func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a new Handler with the given attributes pre-applied. The returned handler preserves ColdBrew context field injection.

func (*Handler) WithGroup added in v0.4.0

func (h *Handler) WithGroup(name string) slog.Handler

WithGroup returns a new Handler with the given group name. The returned handler preserves ColdBrew context field injection.

type Logger

type Logger interface {
	loggers.BaseLogger //nolint:staticcheck // intentional use for backward compatibility
	// Debug logs a message at level Debug.
	// ctx is used to extract per-request context fields.
	Debug(ctx context.Context, args ...any)
	// Info logs a message at level Info.
	// ctx is used to extract per-request context fields.
	Info(ctx context.Context, args ...any)
	// Warn logs a message at level Warn.
	// ctx is used to extract per-request context fields.
	Warn(ctx context.Context, args ...any)
	// Error logs a message at level Error.
	// ctx is used to extract per-request context fields.
	Error(ctx context.Context, args ...any)
}

Logger is the interface for ColdBrew's structured logging. It extends loggers.BaseLogger with convenience methods for each log level.

func GetLogger

func GetLogger() Logger

GetLogger returns the global logger. If the global logger is not set, it will create a new one with the default Handler.

func NewLogger deprecated

func NewLogger(bl loggers.BaseLogger) Logger

NewLogger creates a new logger with a provided BaseLogger.

Deprecated: Use NewHandler or NewHandlerWithInner instead. NewLogger is kept for backward compatibility.

Directories

Path Synopsis
Package loggers provides loggers implementation for log package
Package loggers provides loggers implementation for log package

Jump to

Keyboard shortcuts

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