Files
log/doc/api.md
T
Claude fe711ed2a5
Test / test (push) Canceled after 0s
Test / fuzz (./compat, FuzzParseFormat) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatJSON) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatTextPolicy) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSanitize) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSerializerJSON) (push) Canceled after 0s
v0.1.12 SetConsoleWriter routes console output to a host writer
A host that draws on the terminal (a TUI) cannot let the logger write to
stdout or stderr, yet the records are worth showing inside the host.
SetErrorHandler already covers internal diagnostics; SetConsoleWriter is
its sibling for console output.

- SetConsoleWriter(w) sends console output of every console_target to w,
  split's warn-and-above records included; nil restores stdout/stderr.
  It holds across ApplyConfig and is safe while logging.
- One stored value: ApplyConfig and SetConsoleWriter publish the console
  writers through storeConsole; the processor's split branch now reads
  the stored warn writer instead of writing os.Stderr directly.
- TestLoggerConsoleTargets becomes TestConsoleWriterTakesEveryTarget,
  which asserts where each target's records land; a second test checks
  that nil restores the configured writers.
- README names both hooks for terminal hosts; the API doc's callback
  contract covers console writers.

Verified: go build ./... ok; gofmt -l on changed files clean; go vet ./...
ok; go test ./... ok (all four packages, under 1 s); go test -race on the
new tests ok; mutation run 6 of 6 caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SyaMAhyEzAp3ULLWJZG4jQ
2026-10-10 20:14:00 -04:00

11 KiB

API Reference

Complete API documentation for the lixenwraith/log package.

Logger Creation

NewLogger

func NewLogger() *Logger

Creates a new, uninitialized logger instance with default configuration parameters registered internally.

Example:

logger := log.NewLogger()

Initialization Methods

ApplyConfig

func (l *Logger) ApplyConfig(cfg *Config) error

Applies a validated configuration to the logger. This is the recommended method for applications that need full control over configuration.

Parameters:

  • cfg: A *Config struct with desired settings

Returns:

  • error: Configuration error if invalid

Example:

logger := log.NewLogger()

cfg := log.DefaultConfig()
cfg.Level = log.LevelDebug
cfg.Directory = "/var/log/app"
err := logger.ApplyConfig(cfg)

ApplyConfigString

func (l *Logger) ApplyConfigString(overrides ...string) error

Applies key-value overrides to the logger. Convenient interface for minor changes.

Parameters:

  • overrides: Variadic overrides in the format "key=value"

Returns:

  • error: Configuration error if invalid

Example:

logger := log.NewLogger()

err := logger.ApplyConfigString("directory=/var/log/app", "name=app")

Logging Methods

Logging methods accept variadic arguments. Ordinary methods preserve them as positional values (a JSON array in JSON mode). Use LogContext with FlagKV for a keyed object, or LogStructured for a message and nested fields.

Debug

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

Logs a message at debug level (-4).

Example:

logger.Debug("Processing started", "items", 100, "mode", "batch")

Info

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

Logs a message at info level (0).

Example:

logger.Info("Server started", "port", 8080, "tls", true)

Warn

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

Logs a message at warning level (4).

Example:

logger.Warn("High memory usage", "used_mb", 1800, "limit_mb", 2048)

Error

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

Logs a message at error level (8).

Example:

logger.Error("Database connection failed", "host", "db.example.com", "error", err)

LogStructured

func (l *Logger) LogStructured(level int64, message string, fields map[string]any)

Logs a message with structured fields as proper JSON (when format="json").

Example:

logger.LogStructured(log.LevelInfo, "User action", map[string]any{
    "user_id": 42,
    "action": "login",
    "metadata": map[string]any{"ip": "192.168.1.1"},
     })

Write

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

Outputs raw, unformatted data regardless of configured format. Bypasses all formatting (timestamps, levels, JSON structure) and writes args as space-separated strings without a trailing newline.

Example:

logger.Write("METRIC", "cpu_usage", 85.5, "timestamp", 1234567890)
// Output: METRIC cpu_usage 85.5 timestamp 1234567890

Trace Logging Methods

These methods include function call traces in the log output.

DebugTrace

func (l *Logger) DebugTrace(depth int, args ...any)

Logs at debug level with function call trace.

Parameters:

  • depth: Number of stack frames to include (0-10)
  • args: Log message and fields

Example:

logger.DebugTrace(3, "Entering critical section", "mutex", "db_lock")

InfoTrace

func (l *Logger) InfoTrace(depth int, args ...any)

Logs at info level with function call trace.

WarnTrace

func (l *Logger) WarnTrace(depth int, args ...any)

Logs at warning level with function call trace.

ErrorTrace

func (l *Logger) ErrorTrace(depth int, args ...any)

Logs at error level with function call trace.

Special Logging Methods

Log

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

Logs with timestamp only, no level information (uses Info level internally).

Example:

logger.Log("Checkpoint reached", "step", 5)

Message

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

Logs using the configured format and sanitization, without timestamp or level.

Example:

logger.Message("Raw output for special formatting")

LogTrace

func (l *Logger) LogTrace(depth int, args ...any)

Logs with timestamp and trace, but no level information.

Example:

logger.LogTrace(2, "Function boundary", "entering", true)

Control Methods

Start and Stop

Start() error begins processing after configuration; repeated starts are no-ops. Stop(timeout ...time.Duration) error closes emission, drains accepted records, and joins the processor. A timeout does not permit a second processor to start while the first still owns resources. Retry Stop or Shutdown to wait again. Lifecycle timeouts bound the processor join after acquiring the lifecycle lock.

Context and fast filtering

Enabled(level int64) bool checks the current emit gate before constructing expensive arguments. SetLevel(level int64) updates the threshold without restarting. SetContextKeys(tag string, vals ...string) names a tag and up to three counters; LogContext(ctx Context, flags, level, depth int64, args ...any) stamps them onto a record. Flags() returns display defaults suitable for combining with FlagKV.

Shutdown

func (l *Logger) Shutdown(timeout ...time.Duration) error

Gracefully drains accepted records and closes the log file. If the processor times out, its resources remain open; retry Shutdown to finish cleanup. A fresh ApplyConfig permits reuse after shutdown.

Parameters:

  • timeout: Optional timeout duration (defaults to 2x flush interval)

Returns:

  • error: Shutdown error if flush fails or timeout exceeded

Example:

err := logger.Shutdown(5 * time.Second)
if err != nil {
    fmt.Printf("Shutdown error: %v\n", err)
}

Flush

func (l *Logger) Flush(timeout time.Duration) error

Drains records enqueued before the request and syncs the file. Later arrivals do not extend the drain indefinitely. The timeout covers both queueing and confirmation. A successful return reports successful sync; previously dropped records cannot be recovered. A concurrent stop may return a stopped-processor error.

Parameters:

  • timeout: Maximum time to wait for flush completion

Returns:

  • error: Flush error if timeout exceeded or logger is uninitialized.

Example:

err := logger.Flush(1 * time.Second)

Constants

Log Levels

const (
    LevelTrace int64 = -8
    LevelDebug int64 = -4
    LevelInfo  int64 = 0
    LevelWarn  int64 = 4
    LevelError int64 = 8
)

Standard log levels for filtering output.

Heartbeat Levels

const (
    LevelProc int64 = 12  // Process statistics
    LevelDisk int64 = 16  // Disk usage statistics
    LevelSys  int64 = 20  // System statistics
)

Special levels for heartbeat monitoring that bypass level filtering.

Level Helper Function

func Level(levelStr string) (int64, error)

Converts level string to numeric constant.

Parameters:

  • levelStr: Level name ("trace", "debug", "info", "warn", "error", "proc", "disk", "sys")

Returns:

  • int64: Numeric level value
  • error: Conversion error for invalid strings

Example:

level, err := log.Level("debug")  // Returns -4

Format Flags

const (
    FlagRaw            = formatter.FlagRaw            // Bypass formatting and sanitization
    FlagShowTimestamp  = formatter.FlagShowTimestamp  // Force include timestamp
    FlagShowLevel      = formatter.FlagShowLevel      // Force include level
    FlagStructuredJSON = formatter.FlagStructuredJSON // Structured JSON output
    FlagNoTimestamp    = formatter.FlagNoTimestamp    // Suppress timestamp
    FlagNoLevel        = formatter.FlagNoLevel        // Suppress level
    FlagKV             = formatter.FlagKV            // Alternating string keys and values
    FlagDefault        = formatter.FlagDefault        // Default flags
)

Control output formatting behavior. These flags are re-exported from the formatter package.

Sanitization Policies

const (
    PolicyRaw   = sanitizer.PolicyRaw   // No sanitization
    PolicyJSON  = sanitizer.PolicyJSON  // Content control-character escapes
    PolicyTxt   = sanitizer.PolicyTxt   // Text file safe
    PolicyShell = sanitizer.PolicyShell // Lossy filter, not shell quoting
)

Pre-configured sanitization policies. These are re-exported from the sanitizer package.

Error Types

The logger returns errors prefixed with "log: " for easy identification:

// Configuration errors
"log: invalid format: 'xml' (use txt, json, or raw)"
"log: buffer_size must be positive: 0"

// Initialization errors
"log: failed to create log directory '/var/log/app': permission denied"
"log: logger previously failed to initialize and is disabled"

// Runtime errors
"log: logger not initialized or already shut down"
"log: timeout waiting for flush confirmation (1s)"

Thread Safety

Logger methods support concurrent calls. Lifecycle and configuration changes are serialized. Enqueues hold a short read lock to prevent records being stranded during a stop. Logger, Formatter, Sanitizer, and Builder instances must not be copied after use.

ApplyConfig takes a snapshot. Emission copies the argument slice, and LogStructured also copies the top-level fields map. Referenced values (byte slices, nested maps/slices, pointers, Stringers, and custom marshalers) remain caller-owned: keep them immutable until a successful Flush or Stop, or pass an application-created snapshot. Do not mutate configuration while an ApplyConfig call is reading it.

Builders and standalone formatter/sanitizer configuration are not synchronized; finish configuration before sharing. SetSpawn callbacks must launch the function asynchronously and return promptly. Error handlers and SetConsoleWriter writers must return promptly and must not invoke lifecycle/configuration methods or Flush.

Usage Pattern Example

type Service struct {
    logger *log.Logger
}

func NewService() (*Service, error) {
    logger := log.NewLogger()
    err := logger.ApplyConfigString(
        "directory=/var/log/service",
        "format=json",
        "buffer_size=2048",
        "heartbeat_level=1")
    if err != nil {
        return nil, fmt.Errorf("logger init: %w", err)
    }
    
    if err := logger.Start(); err != nil {
        _ = logger.Shutdown()
        return nil, err
    }
    return &Service{logger: logger}, nil
}

func (s *Service) ProcessRequest(id string) error {
    s.logger.InfoTrace(1, "Processing request", "id", id)
    
    if err := s.doWork(id); err != nil {
        s.logger.Error("Request failed", "id", id, "error", err)
        return err
    }
    
    s.logger.Info("Request completed", "id", id)
    return nil
}

func (s *Service) Shutdown() error {
    return s.logger.Shutdown(5 * time.Second)
}