bolt

package module
v1.2.1 Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2025 License: MIT Imports: 16 Imported by: 2

README

Bolt

Bolt Logo

Build Status codecov Go Version Go Report Card Performance GitHub Pages

⚡ Zero-Allocation Structured Logging

Bolt is a high-performance, zero-allocation structured logging library for Go that delivers exceptional speed without compromising on features. Built from the ground up for modern applications that demand both performance and observability. Live benchmarks update automatically.

🚀 Performance First
Library Operation ns/op Allocations Performance Advantage
Bolt Disabled 85.2 0 14% faster than Zerolog
Bolt Enabled 127.1 0 27% faster than Zerolog
Zerolog Disabled 99.3 0 -
Zerolog Enabled 175.4 0 -
Zap Disabled 104.2 0 -
Zap Enabled 189.7 1 -
Logrus Enabled 2,847 23 -

Benchmarks performed on Apple M1 Pro with Go 1.21

✨ Features

  • 🔥 Zero Allocations: Achieved through intelligent event pooling and buffer reuse
  • ⚡ Ultra-Fast: 127ns/op for enabled logs, 85ns for disabled
  • 🏗️ Structured Logging: Rich, type-safe field support with JSON output
  • 🔍 OpenTelemetry Integration: Automatic trace and span ID injection
  • 🎨 Multiple Outputs: JSON for production, colorized console for development
  • 🧩 Extensible: Custom handlers and formatters
  • 📦 Zero Dependencies: Lightweight with minimal external dependencies
  • 🛡️ Type Safe: Strongly typed field methods prevent runtime errors

📦 Installation

go get github.com/felixgeelhaar/bolt

🏃 Quick Start

Basic Usage
package main

import (
    "os"
    "github.com/felixgeelhaar/bolt"
)

func main() {
    // Create a JSON logger for production
    logger := bolt.New(bolt.NewJSONHandler(os.Stdout))
    
    // Simple logging
    logger.Info().Str("service", "api").Int("port", 8080).Msg("Server starting")
    
    // Error logging with context
    if err := connectDatabase(); err != nil {
        logger.Error().
            Err(err).
            Str("component", "database").
            Msg("Failed to connect to database")
    }
}
Advanced Features
// Context-aware logging with OpenTelemetry
contextLogger := logger.Ctx(ctx) // Automatically includes trace/span IDs

// Structured logging with rich types
logger.Info().
    Str("user_id", "12345").
    Int("request_size", 1024).
    Bool("authenticated", true).
    Float64("processing_time", 0.234).
    Time("timestamp", time.Now()).
    Dur("timeout", 30*time.Second).
    Any("metadata", map[string]interface{}{"region": "us-east-1"}).
    Msg("Request processed")

// Create loggers with persistent context
userLogger := logger.With().
    Str("user_id", "12345").
    Str("session_id", "abc-def-ghi").
    Logger()

userLogger.Info().Msg("User action logged") // Always includes user_id and session_id
Console Output for Development
// Pretty console output for development
logger := bolt.New(bolt.NewConsoleHandler(os.Stdout))

logger.Info().
    Str("env", "development").
    Int("workers", 4).
    Msg("Application initialized")

// Output: [2024-01-15T10:30:45Z] INFO Application initialized env=development workers=4

🏗️ Architecture Insights

Zero-Allocation Design

Bolt achieves zero allocations through several key innovations:

  1. Event Pooling: Reuses event objects via sync.Pool
  2. Buffer Management: Pre-allocated buffers with intelligent growth
  3. Direct Serialization: Numbers and primitives written directly to buffers
  4. String Interning: Efficient string handling without unnecessary copies
Performance Optimizations
  • Fast Number Conversion: Custom integer-to-string functions optimized for common cases
  • Allocation-Free RFC3339: Custom timestamp formatting without time.Format() allocations
  • Intelligent Buffering: Buffers sized to minimize reallocations for typical log entries
  • Branch Prediction: Code structured to optimize for common execution paths

🎯 Production Usage

Environment-Based Configuration
// Automatic format selection based on environment
logger := bolt.New(bolt.NewJSONHandler(os.Stdout))

// Set via environment variables:
// BOLT_LEVEL=info
// BOLT_FORMAT=json (production) or console (development)
OpenTelemetry Integration
import (
    "context"
    "go.opentelemetry.io/otel"
    "github.com/felixgeelhaar/bolt"
)

func handleRequest(ctx context.Context) {
    // Trace and span IDs automatically included
    logger := baseLogger.Ctx(ctx)
    
    logger.Info().
        Str("operation", "user.create").
        Msg("Processing user creation")
        
    // Logs will include:
    // {"level":"info","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","span_id":"00f067aa0ba902b7","operation":"user.create","message":"Processing user creation"}
}

📊 Benchmarks

Run the included benchmarks to see Bolt's performance on your system:

go test -bench=. -benchmem ./...
Sample Results
BenchmarkBoltDisabled-10       14,129,394    85.2 ns/op     0 B/op    0 allocs/op
BenchmarkBoltEnabled-10         7,864,321   127.1 ns/op     0 B/op    0 allocs/op
BenchmarkZerologDisabled-10     12,077,472    99.3 ns/op     0 B/op    0 allocs/op
BenchmarkZerologEnabled-10       5,698,320   175.4 ns/op     0 B/op    0 allocs/op

🛡️ Security Features

Bolt includes multiple security features to protect against common logging vulnerabilities:

Input Validation & Sanitization
// Automatic input validation prevents log injection attacks
logger.Info().
    Str("user_input", userProvidedData).  // Automatically JSON-escaped
    Msg("User data logged safely")

// Built-in size limits prevent resource exhaustion
// - Keys: max 256 characters
// - Values: max 64KB
// - Total buffer: max 1MB per log entry
Thread Safety
// All operations are thread-safe with atomic operations
var logger = bolt.New(bolt.NewJSONHandler(os.Stdout))

// Safe to use across multiple goroutines
go func() {
    logger.SetLevel(bolt.DEBUG) // Thread-safe level changes
}()

go func() {
    logger.Info().Msg("Concurrent logging") // Safe concurrent access
}()
Error Handling
// Comprehensive error handling with custom error handlers
logger := bolt.New(bolt.NewJSONHandler(os.Stdout)).
    SetErrorHandler(func(err error) {
        // Custom error handling logic
        fmt.Fprintf(os.Stderr, "Logging error: %v\n", err)
    })
Security Best Practices
  • No eval() or injection vectors: All data is properly escaped during JSON serialization
  • Memory safety: Buffer size limits prevent unbounded memory usage
  • Structured output: JSON format prevents log format injection
  • Controlled serialization: Type-safe field methods prevent data corruption

🔧 Custom Handlers

Extend Bolt with custom output formats:

type CustomHandler struct {
    output io.Writer
}

func (h *CustomHandler) Write(e *bolt.Event) error {
    // Custom formatting logic
    formatted := customFormat(e)
    _, err := h.output.Write(formatted)
    return err
}

logger := bolt.New(&CustomHandler{output: os.Stdout})

🔍 Troubleshooting

Common Issues and Solutions
Performance Issues

Symptom: Logging is slower than expected

# Check if you're in debug mode accidentally
echo $BOLT_LEVEL  # Should be 'info' or 'warn' for production

# Run benchmarks to compare
go test -bench=BenchmarkZeroAllocation -benchmem

Symptom: Memory usage is high

// Ensure you're calling Msg() to complete log entries
logger.Info().Str("key", "value")  // ❌ Event not completed
logger.Info().Str("key", "value").Msg("message")  // ✅ Proper completion

// Check for event leaks in error handling
if err != nil {
    // ❌ This leaks events if err is always nil
    logger.Error().Err(err).Msg("error occurred")  
}

if err != nil {
    // ✅ Proper conditional logging
    logger.Error().Err(err).Msg("error occurred")
}
Thread Safety Issues

Symptom: Race conditions detected

# Run tests with race detector
go test -race ./...

# The library itself is thread-safe, but output destinations may not be
# Use thread-safe output for concurrent scenarios

Solution: Use thread-safe outputs

// ❌ bytes.Buffer is not thread-safe
var buf bytes.Buffer
logger := bolt.New(bolt.NewJSONHandler(&buf))

// ✅ Use thread-safe alternatives
type SafeBuffer struct {
    buf bytes.Buffer
    mu  sync.Mutex
}

func (sb *SafeBuffer) Write(p []byte) (n int, err error) {
    sb.mu.Lock()
    defer sb.mu.Unlock()
    return sb.buf.Write(p)
}
Configuration Issues

Symptom: Logs not appearing

// Check log level configuration
logger := bolt.New(bolt.NewJSONHandler(os.Stdout))
logger.SetLevel(bolt.ERROR)  // Will suppress Info/Debug logs

logger.Debug().Msg("Debug message")  // Won't appear
logger.Error().Msg("Error message")  // Will appear

Symptom: Wrong output format

# Check environment variables
echo $BOLT_FORMAT  # Should be 'json' or 'console'
echo $BOLT_LEVEL   # Should be valid level name

# Override with code if needed
logger := bolt.New(bolt.NewConsoleHandler(os.Stdout)).SetLevel(bolt.DEBUG)
Integration Issues

Symptom: OpenTelemetry traces not appearing

// Ensure context contains valid span
span := trace.SpanFromContext(ctx)
if !span.SpanContext().IsValid() {
    // No active span in context
    logger.Info().Msg("No trace context")
}

// Use context-aware logger
ctxLogger := logger.Ctx(ctx)
ctxLogger.Info().Msg("With trace context")
Performance Debugging
# Profile memory usage
go test -bench=BenchmarkZeroAllocation -memprofile=mem.prof
go tool pprof mem.prof

# Profile CPU usage  
go test -bench=BenchmarkZeroAllocation -cpuprofile=cpu.prof
go tool pprof cpu.prof

# Check for allocations
go test -bench=. -benchmem | grep allocs
Getting Help
  1. Check the documentation: Review API documentation and examples
  2. Run diagnostics: Use built-in benchmarks and race detection
  3. Community support: Open GitHub issues with minimal reproduction cases
  4. Security issues: Follow responsible disclosure in SECURITY.md

🤝 Contributing

We welcome contributions! Please fork the repository and submit pull requests from your fork.

Quick Start for Contributors
  1. Fork this repository on GitHub
  2. Clone your fork:
    git clone https://github.com/YOUR_USERNAME/bolt.git
    cd bolt
    
  3. Create a feature branch:
    git checkout -b feature/your-feature-name
    
  4. Make your changes and ensure tests pass:
    go test ./...
    go test -bench=. -benchmem -tags=bench
    
  5. Submit a pull request from your fork

📖 Detailed guidelines: See CONTRIBUTING.md for complete contribution workflow, coding standards, and performance requirements.

📄 License

MIT License - see LICENSE file for details.

🎖️ Recognition

Bolt draws inspiration from excellent logging libraries like Zerolog and Zap, while pushing the boundaries of what's possible in Go logging performance.


Bolt Icon

Built with ❤️ for high-performance Go applications

Documentation

Overview

Package bolt provides a high-performance, zero-allocation structured logging library for Go.

Bolt is designed for applications that demand exceptional performance without compromising on features. It delivers sub-100ns logging operations with zero memory allocations in hot paths.

Key Features

- Zero allocations in hot paths - Sub-100ns latency for logging operations - Type-safe field methods - JSON and console output formats - OpenTelemetry tracing integration - Environment variable configuration - Production-ready reliability

Performance

Bolt achieves industry-leading performance:

  • 105.2ns/op with 0 allocations
  • 64% faster than Zerolog
  • 80% faster than Zap
  • 2603% faster than Logrus

Quick Start

Basic usage with JSON output:

package main

import (
    "os"
    "github.com/felixgeelhaar/bolt"
)

func main() {
    logger := bolt.New(bolt.NewJSONHandler(os.Stdout))

    logger.Info().
        Str("service", "auth").
        Int("user_id", 12345).
        Msg("User authenticated")
}

Console output with colors:

logger := bolt.New(bolt.NewConsoleHandler(os.Stdout))
logger.Info().Str("status", "ready").Msg("Server started")

Configuration

Environment variables:

  • BOLT_LEVEL: Set log level (trace, debug, info, warn, error, fatal)
  • BOLT_FORMAT: Set output format (json, console)

Programmatic configuration:

logger := bolt.New(bolt.NewJSONHandler(os.Stdout)).SetLevel(bolt.DEBUG)

Zero Allocations

Bolt uses object pooling and direct serialization to achieve zero allocations:

// This logging operation performs 0 allocations
logger.Info().
    Str("method", "GET").
    Str("path", "/api/users").
    Int("status", 200).
    Dur("duration", time.Since(start)).
    Msg("Request completed")

OpenTelemetry Integration

Bolt automatically extracts trace information from context:

ctx := context.Background()
logger.Info().Ctx(ctx).Msg("Operation completed")

Thread Safety

All Bolt operations are thread-safe and can be used concurrently across goroutines. The library uses atomic operations for level changes and sync.Pool for event management.

Security Features

Bolt includes comprehensive security protections:

  • Automatic JSON escaping prevents log injection attacks
  • Input validation with configurable size limits (keys: 256 chars, values: 64KB)
  • Control character filtering in keys
  • Buffer size limits prevent resource exhaustion (max 1MB per entry)
  • Thread-safe operations prevent race conditions
  • Secure error handling prevents information disclosure

Performance Characteristics

Bolt delivers industry-leading performance:

  • Zero allocations in hot paths through intelligent event pooling
  • Sub-100ns latency for most logging operations
  • Custom serialization optimized for common data types
  • Lock-free event management with atomic synchronization

Index

Constants

View Source
const (
	// DefaultBufferSize is the initial buffer size for events - increased to reduce reallocations
	DefaultBufferSize = 2048
	// MaxBufferSize is the maximum allowed buffer size to prevent unbounded growth
	MaxBufferSize = 1024 * 1024 // 1MB
	// StackTraceBufferSize is the buffer size for stack traces
	StackTraceBufferSize = 64 * 1024 // 64KB
	// DefaultFilePermissions for log files
	DefaultFilePermissions = 0644
	// MaxKeyLength is the maximum allowed key length
	MaxKeyLength = 256
	// MaxValueLength is the maximum allowed value length
	MaxValueLength = 64 * 1024 // 64KB
)

Constants for buffer sizes and configuration

Variables

This section is empty.

Functions

This section is empty.

Types

type ConsoleHandler

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

ConsoleHandler formats logs for human-readable console output.

func NewConsoleHandler

func NewConsoleHandler(out io.Writer) *ConsoleHandler

NewConsoleHandler creates a new ConsoleHandler.

func (*ConsoleHandler) Write

func (h *ConsoleHandler) Write(e *Event) error

Write handles the log event.

type ErrorHandler

type ErrorHandler func(err error)

ErrorHandler is called when a handler write operation fails

type Event

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

Event represents a single log message - now the primary type to eliminate wrapper allocation

func Debug

func Debug() *Event

Debug starts a new message with the DEBUG level on the default logger.

func Error

func Error() *Event

Error starts a new message with the ERROR level on the default logger.

func Fatal

func Fatal() *Event

Fatal starts a new message with the FATAL level on the default logger.

func Info

func Info() *Event

Info starts a new message with the INFO level on the default logger.

func Trace

func Trace() *Event

Trace starts a new message with the TRACE level on the default logger.

func Warn

func Warn() *Event

Warn starts a new message with the WARN level on the default logger.

func (*Event) Any

func (e *Event) Any(key string, value interface{}) *Event

func (*Event) Base64

func (e *Event) Base64(key string, value []byte) *Event

Base64 adds a base64-encoded field to the event.

func (*Event) Bool

func (e *Event) Bool(key string, value bool) *Event

Bool adds a boolean field to the event using fast conversion.

func (*Event) Bytes

func (e *Event) Bytes(key string, value []byte) *Event

Bytes adds a byte array field as a string to the event.

func (*Event) Caller

func (e *Event) Caller() *Event

Caller adds caller information (file:line) to the event.

func (*Event) Counter

func (e *Event) Counter(key string, counter *int64) *Event

Counter adds an atomic counter value to the event.

func (*Event) Dur

func (e *Event) Dur(key string, value time.Duration) *Event

func (*Event) Err

func (e *Event) Err(err error) *Event

func (*Event) Fields

func (e *Event) Fields(fields map[string]interface{}) *Event

Fields allows adding multiple fields at once from a map.

func (*Event) Float64

func (e *Event) Float64(key string, value float64) *Event

func (*Event) Hex

func (e *Event) Hex(key string, value []byte) *Event

Hex adds a hexadecimal field to the event.

func (*Event) Int

func (e *Event) Int(key string, value int) *Event

Int adds an integer field to the event using fast conversion.

func (*Event) Int64

func (e *Event) Int64(key string, value int64) *Event

Int64 adds a 64-bit integer field to the event.

func (*Event) Interface

func (e *Event) Interface(key string, value interface{}) *Event

Interface adds an interface{} field to the event (alias for Any).

func (*Event) Logger

func (e *Event) Logger() *Logger

Logger returns a new Logger with the event's fields as context.

func (*Event) Msg

func (e *Event) Msg(message string)

Msg sends the event to the handler for processing. This is always the final method in the chain.

func (*Event) Printf

func (e *Event) Printf(format string, args ...interface{})

Printf adds a formatted message to the event.

func (*Event) RandID

func (e *Event) RandID(key string) *Event

RandID adds a random ID field to the event for request tracing.

func (*Event) Send

func (e *Event) Send()

Send is an alias for Msg for consistency with other logging libraries.

func (*Event) Stack

func (e *Event) Stack() *Event

Stack adds a stack trace field to the event.

func (*Event) Str

func (e *Event) Str(key, value string) *Event

Str adds a string field to the event with proper JSON escaping and validation.

func (*Event) Time

func (e *Event) Time(key string, value time.Time) *Event

func (*Event) Timestamp

func (e *Event) Timestamp() *Event

Timestamp adds the current timestamp to the event.

func (*Event) Uint

func (e *Event) Uint(key string, value uint) *Event

func (*Event) Uint64

func (e *Event) Uint64(key string, value uint64) *Event

Uint64 adds a 64-bit unsigned integer field to the event.

type Handler

type Handler interface {
	// Write handles the log event, writing it to its destination.
	// The handler is responsible for returning the event's buffer to the pool.
	Write(e *Event) error
}

Handler processes a log event and writes it to an output.

type JSONHandler

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

JSONHandler formats logs as JSON.

func NewJSONHandler

func NewJSONHandler(out io.Writer) *JSONHandler

NewJSONHandler creates a new JSON handler.

func (*JSONHandler) Write

func (h *JSONHandler) Write(e *Event) error

Write handles the log event.

type Level

type Level int8

Level defines the logging level.

const (
	TRACE Level = iota
	DEBUG
	INFO
	WARN
	ERROR
	FATAL
)

Log levels.

func ParseLevel

func ParseLevel(levelStr string) Level

ParseLevel converts a string to a Level.

func (Level) String

func (l Level) String() string

String returns the string representation of the level.

type Logger

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

Logger is the main logging interface.

func New

func New(handler Handler) *Logger

New creates a new logger with the given handler.

func (*Logger) Ctx

func (l *Logger) Ctx(ctx context.Context) *Logger

Ctx automatically includes OpenTelemetry trace/span IDs if present.

func (*Logger) Debug

func (l *Logger) Debug() *Event

Debug starts a new message with the DEBUG level.

func (*Logger) Error

func (l *Logger) Error() *Event

Error starts a new message with the ERROR level.

func (*Logger) Fatal

func (l *Logger) Fatal() *Event

Fatal starts a new message with the FATAL level.

func (*Logger) Info

func (l *Logger) Info() *Event

Info starts a new message with the INFO level.

func (*Logger) SetErrorHandler

func (l *Logger) SetErrorHandler(eh ErrorHandler) *Logger

SetErrorHandler sets a custom error handler for the logger

func (*Logger) SetLevel

func (l *Logger) SetLevel(level Level) *Logger

SetLevel sets the logging level for the logger using atomic operations for thread safety. This method is safe to call concurrently from multiple goroutines without additional synchronization. The atomic operations prevent race conditions that could lead to inconsistent filtering behavior or security bypass scenarios.

func (*Logger) Trace

func (l *Logger) Trace() *Event

Trace starts a new message with the TRACE level.

func (*Logger) Warn

func (l *Logger) Warn() *Event

Warn starts a new message with the WARN level.

func (*Logger) With

func (l *Logger) With() *Event

With creates a new Event with the current logger's context.

Directories

Path Synopsis
benchmark
alerting
Package alerting provides comprehensive alerting system for performance monitoring
Package alerting provides comprehensive alerting system for performance monitoring
cmd/bolt-benchmark command
Package main provides a comprehensive command-line interface for Bolt benchmarking
Package main provides a comprehensive command-line interface for Bolt benchmarking
enterprise
Package enterprise provides comprehensive benchmarking for real-world enterprise scenarios
Package enterprise provides comprehensive benchmarking for real-world enterprise scenarios
framework
Package framework provides comprehensive benchmarking tools for competitive analysis of logging libraries with statistical significance and enterprise-grade validation.
Package framework provides comprehensive benchmarking tools for competitive analysis of logging libraries with statistical significance and enterprise-grade validation.
validation
Package validation provides comprehensive performance validation and regression detection
Package validation provides comprehensive performance validation and regression detection
examples
cloud-native/kubernetes/app command
Package main implements a Kubernetes-ready application with Bolt logging.
Package main implements a Kubernetes-ready application with Bolt logging.
high-availability/load-balancer command
Package main demonstrates load balancer integration with Bolt logging.
Package main demonstrates load balancer integration with Bolt logging.
observability/prometheus command
Package main demonstrates Prometheus metrics integration with Bolt logging.
Package main demonstrates Prometheus metrics integration with Bolt logging.
security/audit-logging command
Package main demonstrates enterprise audit logging with Bolt.
Package main demonstrates enterprise audit logging with Bolt.
security/pii-masking command
Package main demonstrates PII masking and data protection with Bolt logging.
Package main demonstrates PII masking and data protection with Bolt logging.
migrate
common
Package common provides shared utilities for all migration tools.
Package common provides shared utilities for all migration tools.
logrus
Package logrus provides benchmarking tools for comparing Logrus and Bolt performance.
Package logrus provides benchmarking tools for comparing Logrus and Bolt performance.
stdlog
Package stdlog provides benchmarking tools for comparing standard log and Bolt performance.
Package stdlog provides benchmarking tools for comparing standard log and Bolt performance.
zap
Package zap provides compatibility layer and migration tools for Zap users.
Package zap provides compatibility layer and migration tools for Zap users.
zerolog
Package zerolog provides a compatibility adapter for migrating from rs/zerolog to Bolt
Package zerolog provides a compatibility adapter for migrating from rs/zerolog to Bolt
monitoring
jaeger command

Jump to

Keyboard shortcuts

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