gookit/slog Documentation

repository·master·Indexed 20 days ago

https://github.com/gookit/slog

A lightweight, structured, and extensible logging library for Golang designed as a 'batteries-included' solution for applications and CLI tools. It features built-in handlers for console, file (with size and time-based rotation), syslog, and email, as well as support for JSON and text formatting, custom processors for metadata, and Fatal/Panic log levels.

Tokens
20.9K
Snippets
76
Records
95
Agent score
67%

What's inside gookit/slog

  1. Available built-in log handlers in the handler package

    master

    The handler package provides several pre-configured slog.Handler implementations for different output destinations and behaviors:

    • Console: For logging to the terminal/console.
    • File: For logging to local files.
    • Stream: For logging to an io.Writer.
    • Syslog: For logging to the system log.
    • Email: For sending logs via email.
    • FlushClose: A wrapper that ensures logs are flushed and the underlying writer is closed.
    • SyncClose: A handler designed for file-based logging that ensures synchronization and closing of files.
  2. Compare slog with standard log/slog

    master

    Choosing between gookit/slog and the standard library log/slog (introduced in Go 1.21) depends on your use case:

    • Use log/slog (Standard Library) if you need zero dependencies and high performance (e.g., for a library or a core service) and you prefer using strongly-typed Attr/Value to minimize allocations.
    • Use gookit/slog if you want an application/CLI-oriented experience with out-of-the-box features like:
      • Built-in file rotation (rotatefile) with size/time splitting, cleanup, and gzip compression.
      • Colorful, templated console output.
      • Multiple built-in handlers (file, syslog, email, buffered, multi).
      • Support for Fatal and Panic log levels.
      • A logrus/zap-sugar style API (Infof, WithField).

    Interoperability: Since rotatefile.Writer implements the standard io.Writer interface, you can use gookit's file rotation logic directly with the standard log/slog.

  3. Performance Note: Log Level Filtering Overhead

    master

    Performance Limitation: Lack of Logger-level Level Gates

    Currently, the library lacks a "fast gate" at the Logger level for checking log levels.

    The Issue: Even if a log level is disabled (e.g., Debug is disabled in production), the library performs message formatting (e.g., fmt.Sprintf or calling Stringer.String()) before checking if the level is enabled. This means disabled logs still incur the CPU and allocation costs of argument formatting and lock contention.

    Affected Files:

    • record.go (lines 348-371)
    • logger_write.go (lines 60-95)

    Impact: High-frequency disabled logs (like Debug) will still consume significant resources in production environments.

  4. Performance Note: Serialized Formatting and Writing

    master

    Performance Limitation: Single Mutex Bottleneck

    In the current implementation, the entire process of formatting a log and writing it to the output occurs while holding a single mutex (l.mu) on the logger.

    The Issue: writeRecord holds the lock during:

    1. Caller stack trace retrieval
    2. Processor execution
    3. Formatting (CPU intensive)
    4. I/O operations

    Impact: Under high concurrency, throughput is limited by this single lock, as formatting (which could be done in parallel per record) is forced to be serial.

  5. Configure log handlers using ConfigFn

    master

    Many handler constructors (especially those in SyncCloseHandler) accept variadic ConfigFn arguments. These functions allow you to customize the handler's behavior using a builder-like pattern.

    Common configuration options include:

    • File/Rotation: WithLogfile, WithMaxSize, WithRotateMode, WithRotateTime, WithBackupNum, WithCompress.
    • Buffering: WithBuffMode, WithBuffSize.
    • Levels: WithLogLevel, WithLogLevels, WithLevelNames, WithMaxLevelName.
    • Format: WithUseJSON (to switch between text and JSON output).
    • Permissions: WithFilePerm.
    // Example of using ConfigFn with a file handler
    handler.NewFileHandler("app.log", 
        handler.WithUseJSON(true),
        handler.WithMaxSize(1024 * 1024 * 10), // 10MB
        handler.WithCompress(true),
    )
  6. How slog's core components work together

    master

    The slog library uses a hierarchical dispatch system to manage log records. Understanding the relationship between these four components is key to configuring your logging pipeline:

    1. Logger: The central dispatcher. A single Logger can register multiple Handlers and Processors.
    2. Processor: Used for extended processing. Processors are called before the log Record reaches a Handler. They are ideal for adding metadata (like hostnames or request IDs) to every log record.
    3. Handler: The destination for logs. Each log is passed to a Handler.Handle() method. Handlers are responsible for sending logs to specific outputs like the console, files, or remote servers.
    4. Formatter: The data transformation layer. Usually attached to a Handler, a Formatter converts a Record into a specific format (like JSON or Text) before the Handler writes it.

    Log Scheduler Flow: Logger $\rightarrow$ Processors $\rightarrow$ Handlers (which may use Formatters)

              Processors
    Logger --{ 
              Handlers --|- Handler0 With Formatter0
                         |- Handler1 With Formatter1
                         |- Handler2 (can also without Formatter)
                         |- ... more
  7. How the slog architecture works

    master

    The slog library uses a hierarchical dispatch model to process log entries. Understanding the relationship between these components is key to customizing your logging pipeline:

    1. Logger: The central dispatcher. A single Logger can register multiple Handlers and Processors.
    2. Record: Represents a single log entry.
    3. Processor: Used to extend or modify a Record before it reaches any Handler. Use this to add global fields (like hostname or request_id) or extra metadata.
    4. Handler: The destination for the log. It receives the Record and is responsible for sending it to a specific output like the console, a file, or a remote server.
    5. Formatter: Responsible for transforming a Record into a specific data format (e.g., JSON or Text). Formatter is typically configured within a Handler.

    Dispatch Flow: Logger $\rightarrow$ Processors $\rightarrow$ Handlers (which may use Formatters)

              Processors
    Logger --{
              Handlers --|- Handler0 With Formatter0
                         |- Handler1 With Formatter1
                         |- Handler2 (can also without Formatter)
                         |- ... more
  8. Compare gookit/slog with standard log/slog

    master

    Choose gookit/slog when you need a 'batteries-included' logger for applications or CLI tools. It provides features that the standard library lacks, such as:

    • Built-in file rotation (size/time based, cleanup, and gzip).
    • Colored and template-based console output.
    • Multiple built-in handlers (file, syslog, email, buffered, multi).
    • Support for Fatal and Panic levels.

    Choose the standard log/slog when you want a zero-dependency, high-performance logger for libraries or services where you intend to provide your own sinks.

  9. Configure log file buffering modes

    master

    When using file handlers, you can configure how logs are buffered using BuffMode. This is controlled via the Config.BuffMode field or configuration functions.

    • BuffModeBite (Byte buffering): The buffer writes to the file once it reaches the specified BuffSize in bytes.
    • BuffModeLine (Line buffering): The buffer ensures that logs are written only when a complete line is formed, preventing log content from being truncated mid-line.

    Important: If write buffering is enabled, you must call slog.MustClose() or logger.Close() at the end of your program to flush the remaining contents of the buffer to the file.

  10. Output logs to files with rotation

    master

    The handler package includes specialized handlers for automatic log file rotation based on size or time.

    Rotation Handlers:

    • NewSizeRotateFile(logfile string, maxSize int, fns ...ConfigFn): Rotates files based on a maximum size in bytes.
    • NewTimeRotateFile(logfile string, rt rotatefile.RotateTime, fns ...ConfigFn): Rotates files based on a time interval (e.g., rotatefile.EveryHour).
    • NewRotateFileHandler(logfile string, rt rotatefile.RotateTime, fns ...ConfigFn): Supports both size and time-based rotation. Defaults to 20MB size and 1-hour intervals.

    Key Features:

    • Compression: Enable gzip compression for rotated files using handler.WithCompress(true).
    • Buffering: Use handler.WithBuffSize(size) to enable buffered writes. Important: If buffering is enabled, you must call slog.MustClose() or logger.Close() before the program exits to flush the buffer to disk.
    • Configuration: Use fns ...ConfigFn to set options like log retention time or buffer size.
    // Example: Rotating file handler with compression and time-based rotation
    h1 := handler.MustRotateFile("/tmp/error.log", rotatefile.EveryHour, 
        handler.WithLogLevels(slog.DangerLevels), 
        handler.WithCompress(true),
    )
    
    slog.PushHandler(h1)
    slog.Info("message")
  11. Integrate rotatefile with standard log/slog

    master

    Since rotatefile.Writer implements the io.Writer interface, you can use it with the standard Go log/slog package (Go 1.21+) to get advanced file rotation features while maintaining the standard API.

    package main
    
    import (
    	"log/slog"
    	"github.com/gookit/rotatefile"
    )
    
    func main() {
    	// Configure rotation via rotatefile.NewConfig
    	w, err := rotatefile.NewConfig("testdata/std_slog.log", func(c *rotatefile.Config) {
    		c.MaxSize = 50 * 1024 * 1024 // 50MB
    		c.RotateTime = rotatefile.EveryDay
    		c.BackupNum = 7
    	}).Create()
    	if err != nil {
    		panic(err)
    	}
    
    	// Plug the rotatefile writer into a standard slog handler
    	logger := slog.New(slog.NewJSONHandler(w, nil))
    	logger.Info("log message via std log/slog", "key", "value")
    }
    package main
    
    import (
    	"log/slog"
    
    	"github.com/gookit/rotatefile"
    )
    
    func main() {
    	// rotate by size/time + clean + gzip, all from rotatefile config
    	w, err := rotatefile.NewConfig("testdata/std_slog.log", func(c *rotatefile.Config) {
    		c.MaxSize = 50 * 1024 * 1024 // 50MB
    		c.RotateTime = rotatefile.EveryDay
    		c.BackupNum = 7
    	}).Create()
    	if err != nil {
    		panic(err)
    	}
    
    	logger := slog.New(slog.NewJSONHandler(w, nil))
    	logger.Info("log message via std log/slog", "key", "value")
    }
  12. Run log library benchmarks via Go test

    master

    Alternatively, you can run the benchmarks directly using the go test command. This allows for more granular control over CPU usage, verbosity, and benchmark duration.

    go test -v -cpu=4 -run=none -bench=. -benchtime=10s -benchmem bench_loglibs_test.go