Skip to content

simp-lee/logger

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Logger

Lightweight logger built on Go log/slog, with console/file output, structured fields, custom templates, middleware, context attributes, and file rotation.

Requires Go 1.25+

Features

  • Multi-output: Console & file with independent configuration
  • Flexible formats: Text, JSON, and custom template support
  • Smart coloring: ANSI colors for console (auto-disabled for files)
  • Auto-rotation: Size-based rotation with configurable retention and gzip compression
  • Structured logging: Full slog API with groups and attributes
  • Middleware: Composable handler middleware chain
  • Context attributes: Inject slog.Attr via context.Context
  • Dynamic level: Change log level at runtime via SetLevel()
  • Attribute transformation: Custom processing via WithReplaceAttr
  • Drop-in replacement: Embeds *slog.Logger + easy SetDefault()
  • Efficient runtime: Buffered file writes and optimized custom formatter path

Installation

go get github.com/simp-lee/logger

Quick Start

package main

import "github.com/simp-lee/logger"

func main() {
    log, err := logger.New()
    if err != nil {
        panic(err)
    }
    defer log.Close()

    log.Info("Hello, world!")
    log.Info("User login", "userId", 123, "username", "johndoe")
}

Configuration Options

All options are functional options passed to logger.New(...). Unspecified fields use defaults from DefaultConfig().

Behavior Notes (AI-Friendly)

  • Options are applied in order; later options override earlier ones.
  • WithFilePath(path) automatically enables file output.
  • If WithFile(true) is set without a path, New() returns an error.
  • If both console and file are disabled, logger creation still succeeds and falls back to a default slog.TextHandler on os.Stderr.

Global Options

Option Description Default
WithLevel(slog.Level) Minimum logging level slog.LevelInfo
WithLevelVar(*slog.LevelVar) Use a shared LevelVar for dynamic level control across loggers auto-created internally
WithAddSource(bool) Include source file information (filename:function:line) false
WithTimeFormat(string) Go time format string for timestamps "2006/01/02 15:04:05"
WithTimeZone(*time.Location) Time zone for timestamps time.Local
WithReplaceAttr(func) Custom attribute transformation function nil
WithMiddleware(...Middleware) Append handler middlewares (applied in order) nil

Console Options

Option Description Default
WithConsole(bool) Enable/disable console logging true
WithConsoleWriter(io.Writer) Console output destination os.Stderr
WithConsoleColor(bool) Enable ANSI colored output true
WithConsoleFormat(OutputFormat) Console log format (FormatText, FormatJSON, FormatCustom) FormatCustom
WithConsoleFormatter(string) Custom format template for console (auto-sets format to FormatCustom) "{time} {level} {message} {file} {attrs}"

File Options

Option Description Default
WithFile(bool) Enable/disable file logging (requires non-empty path when enabled) false
WithFilePath(string) Path to the log file (auto-enables file logging) ""
WithFileFormat(OutputFormat) File log format (FormatText, FormatJSON, FormatCustom) FormatCustom
WithFileFormatter(string) Custom format template for file (auto-sets format to FormatCustom) "{time} {level} {message} {file} {attrs}"
WithMaxSizeMB(int) Max file size in MB before rotation (0 = disable rotation, negative = default) 10
WithRetentionDays(int) Days to retain rotated files (<=0 resets to default) 7
WithCompressRotated(bool) Gzip compress rotated log files false
WithMaxBackups(int) Max number of rotated backups to keep (0 = unlimited) 0

Shorthand Options

Set both console and file configurations at once:

Option Description
WithFormat(OutputFormat) Set log format for both console and file
WithFormatter(string) Set custom template for both console and file (auto-sets format to FormatCustom)

Output Formats

Three built-in formats:

Format Constant Description
Text FormatText Standard slog.TextHandler output
JSON FormatJSON Standard slog.JSONHandler output
Custom FormatCustom Template-based format with placeholders

Custom Template Placeholders

Placeholder Content
{time} Timestamp (formatted by WithTimeFormat + WithTimeZone)
{level} Log level (DEBUG, INFO, WARN, ERROR)
{message} Log message
{file} Source location filename:function:line (requires WithAddSource(true))
{attrs} User attributes (key=value ...)

Empty placeholders (e.g. {file} without AddSource) are trimmed with surrounding whitespace automatically.

log, err := logger.New(
    logger.WithConsoleFormatter("{time} | {level} | {message} | {attrs}"),
)
if err != nil {
    panic(err)
}
defer log.Close()

Color Output

Console coloring (ANSI) is toggled with WithConsoleColor(true/false). File output never includes color codes.

Level color mapping: DEBUG = Bright Cyan, INFO = Green, WARN = Yellow, ERROR = Red (message text, error attribute key and value all emphasized).

Mixed Formats (Console vs File)

Formats are independent per output. Common pattern — human-readable console + structured file:

log, err := logger.New(
    logger.WithConsoleFormat(logger.FormatCustom),
    logger.WithConsoleFormatter("{time} {level} {message}"),
    logger.WithConsoleColor(true),
    logger.WithFilePath("./logs/app.log"),
    logger.WithFileFormat(logger.FormatJSON),
)
if err != nil {
    panic(err)
}
defer log.Close()

File Rotation & Retention

  • Trigger: Current file size exceeds WithMaxSizeMB(N) MB. Set 0 to disable rotation.
  • Naming: basename.YYYYMMDD.HHMMSS.mmm.ext (adds .counter suffix on collision).
  • Compression: Enable with WithCompressRotated(true) — rotated files are gzipped asynchronously (.gz suffix).
  • Retention: Files older than WithRetentionDays(D) are purged daily.
  • Backup limit: WithMaxBackups(N) caps the number of rotated files kept (oldest removed first). 0 = unlimited.
  • Lazy open: The log file is not opened until the first write, avoiding leaked file descriptors for unused loggers.
  • Buffered I/O: Writes go through a 64 KB buffer; call Sync() to flush explicitly.
log, err := logger.New(
    logger.WithFilePath("./logs/app.log"),
    logger.WithMaxSizeMB(50),
    logger.WithRetentionDays(30),
    logger.WithCompressRotated(true),
    logger.WithMaxBackups(10),
)
if err != nil {
    panic(err)
}
defer log.Close()

Middleware

Middleware is a func(slog.Handler) slog.Handler that wraps the final handler. Middlewares are applied in declaration order via WithMiddleware.

// Example: add a request ID to every log record
func RequestIDMiddleware(requestID string) logger.Middleware {
    return func(next slog.Handler) slog.Handler {
        return next.WithAttrs([]slog.Attr{slog.String("request_id", requestID)})
    }
}

log, err := logger.New(
    logger.WithMiddleware(RequestIDMiddleware("abc-123")),
)

Built-in Middleware: Context Attributes

ContextMiddleware() extracts slog.Attr values stored in a context.Context and appends them to each log record.

log, err := logger.New(
    logger.WithMiddleware(logger.ContextMiddleware()),
)
if err != nil {
    panic(err)
}
defer log.Close()

// Store attributes in context
ctx := logger.WithContextAttrs(context.Background(),
    slog.String("request_id", "req-001"),
    slog.String("user_id", "u-42"),
)

// Attributes are automatically included in log output
log.InfoContext(ctx, "processing request")

Context helpers:

Function Description
WithContextAttrs(ctx, ...slog.Attr) Returns a new context with the given attributes appended
FromContext(ctx) Extracts stored []slog.Attr from context (returns a copy)

Attribute Transformation (WithReplaceAttr)

Intercept and edit/remove attributes (built-in keys: time, level, msg, source, plus user attrs). Return an empty slog.Attr{} to drop an attribute.

log, err := logger.New(
    logger.WithReplaceAttr(func(groups []string, a slog.Attr) slog.Attr {
        if a.Key == "password" {
            return slog.String("password", "***")
        }
        return a
    }),
)

Logger Methods

Logger embeds *slog.Logger, so all standard slog methods (e.g. Info, Warn, Error, Debug, With, WithGroup, InfoContext, etc.) are available directly.

Additional methods on *Logger:

Method Description
Close() error Release all resources (files, goroutines, timers). Always defer this.
SetDefault() Set this logger as the default for slog.Info(), slog.Error(), etc.
SetLevel(slog.Level) Dynamically change the minimum log level at runtime. No-op for Default() loggers.
Rotate() error Trigger log file rotation immediately. No-op if file logging is not enabled.
Sync() error Flush buffered data to the underlying file. No-op if file logging is not enabled.

Constructors

Function Description
New(...Option) (*Logger, error) Create a configured logger with resource management. Recommended.
Default() *Logger Wrap slog.Default(). Does not support SetLevel(). No Close() needed.

Standard Library Integration

log, err := logger.New(logger.WithAddSource(true))
if err != nil {
    panic(err)
}
defer log.Close()

log.SetDefault()
slog.Info("routed through custom logger", "module", "auth")

Dynamic Log Level

log, err := logger.New(logger.WithLevel(slog.LevelInfo))
if err != nil {
    panic(err)
}
defer log.Close()

log.Debug("hidden")          // not printed (level is Info)
log.SetLevel(slog.LevelDebug)
log.Debug("now visible")     // printed

Complete Example

package main

import (
    "context"
    "log/slog"

    "github.com/simp-lee/logger"
)

func main() {
    log, err := logger.New(
        logger.WithLevel(slog.LevelDebug),
        logger.WithAddSource(true),
        logger.WithConsoleFormatter("{time} [{level}] {message} {attrs}"),
        logger.WithFilePath("./logs/app.log"),
        logger.WithFileFormat(logger.FormatJSON),
        logger.WithMaxSizeMB(50),
        logger.WithRetentionDays(30),
        logger.WithCompressRotated(true),
        logger.WithMiddleware(logger.ContextMiddleware()),
    )
    if err != nil {
        panic(err)
    }
    defer log.Close()

    log.SetDefault()

    log.Info("startup", "version", "1.0.0")

    ctx := logger.WithContextAttrs(context.Background(),
        slog.String("request_id", "req-001"),
    )
    log.InfoContext(ctx, "handling request", "path", "/api/users")

    userLogger := log.WithGroup("user")
    userLogger.Info("login", "id", 42)
}

API Quick Reference

# Constructors
logger.New(opts ...Option) (*Logger, error)
logger.Default() *Logger

# Logger methods (in addition to embedded *slog.Logger)
(*Logger) Close() error
(*Logger) SetDefault()
(*Logger) SetLevel(slog.Level)
(*Logger) Rotate() error
(*Logger) Sync() error

# Global options
WithLevel(slog.Level)                          WithLevelVar(*slog.LevelVar)
WithAddSource(bool)                            WithTimeFormat(string)
WithTimeZone(*time.Location)                   WithReplaceAttr(func([]string, slog.Attr) slog.Attr)
WithMiddleware(...Middleware)

# Console options
WithConsole(bool)                              WithConsoleWriter(io.Writer)
WithConsoleColor(bool)                         WithConsoleFormat(OutputFormat)
WithConsoleFormatter(string)

# File options
WithFile(bool)                                 WithFilePath(string)
WithFileFormat(OutputFormat)                    WithFileFormatter(string)
WithMaxSizeMB(int)                             WithRetentionDays(int)
WithCompressRotated(bool)                      WithMaxBackups(int)

# Shorthand options
WithFormat(OutputFormat)                        WithFormatter(string)

# Output formats
FormatText   FormatJSON   FormatCustom

# Context helpers
WithContextAttrs(ctx, ...slog.Attr) context.Context
FromContext(ctx) []slog.Attr

# Built-in middleware
ContextMiddleware() Middleware

# Types
type Middleware func(slog.Handler) slog.Handler
type OutputFormat string   // "text" | "json" | "custom"

License

MIT License

About

A flexible, lightweight logger for Go built on slog, supporting multiple outputs, colored output, customizable formatting, and log rotation.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages