ll

package module
v0.1.7 Latest Latest
Warning

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

Go to latest
Published: Feb 22, 2026 License: MIT Imports: 17 Imported by: 7

README

ll - A Modern Structured Logging Library for Go

ll is a high-performance, production-ready logging library for Go, designed to provide hierarchical namespaces, structured logging, middleware pipelines, conditional logging, and support for multiple output formats, including text, JSON, colorized logs, syslog, VictoriaLogs, and compatibility with Go's slog. It's ideal for applications requiring fine-grained log control, extensibility, and scalability.

Key Features

  • Logging Enabled by Default - Zero configuration to start logging
  • Hierarchical Namespaces - Organize logs with fine-grained control over subsystems (e.g., "app/db")
  • Structured Logging - Add key-value metadata for machine-readable logs
  • Middleware Pipeline - Customize log processing with rate limiting, sampling, and deduplication
  • Conditional & Error-Based Logging - Optimize performance with fluent If, IfErr, IfAny, IfOne chains
  • Multiple Output Formats - Text, JSON, colorized ANSI, syslog, VictoriaLogs, and slog integration
  • Advanced Debugging Utilities - Source-aware Dbg(), hex/ASCII Dump(), private field Inspect(), and stack traces
  • Production Ready - Buffered batching, log rotation, duplicate suppression, and rate limiting
  • Thread-Safe - Built for high-concurrency with atomic operations, sharded mutexes, and lock-free fast paths
  • Performance Optimized - Zero allocations for disabled logs, sync.Pool buffers, LRU caching for source files

Installation

Install ll using Go modules:

go get github.com/olekukonko/ll

Requires Go 1.21 or later.

Quick Start

package main

import "github.com/olekukonko/ll"

func main() {
    // Logger is ENABLED by default - no .Enable() needed!
    logger := ll.New("app")
    
    // Basic logging - works immediately
    logger.Info("Server starting")     // Output: [app] INFO: Server starting
    logger.Warn("Memory high")         // Output: [app] WARN: Memory high
    logger.Error("Connection failed")  // Output: [app] ERROR: Connection failed
    
    // Structured fields
    logger.Fields("user", "alice", "status", 200).Info("Login successful")
    // Output: [app] INFO: Login successful [user=alice status=200]
}

That's it. No .Enable(), no handlers to configure—it just works.

Core Concepts

1. Enabled by Default, Configurable When Needed

Unlike many logging libraries that require explicit enabling, ll logs immediately. This eliminates boilerplate and reduces the chance of missing logs in production.

// This works out of the box:
ll.Info("Service started")  // Output: [] INFO: Service started

// But you still have full control:
ll.Disable()  // Global shutdown
ll.Enable()   // Reactivate
2. Hierarchical Namespaces

Organize logs hierarchically with precise control over subsystems:

// Create a logger hierarchy
root := ll.New("app")
db := root.Namespace("database")
cache := root.Namespace("cache").Style(lx.NestedPath)

// Control logging per namespace
root.NamespaceEnable("app/database")    // Enable database logs
root.NamespaceDisable("app/cache")      // Disable cache logs

db.Info("Connected")     // Output: [app/database] INFO: Connected
cache.Info("Hit")        // No output (disabled)
3. Structured Logging with Ordered Fields

Fields maintain insertion order and support fluent chaining:

// Fluent key-value pairs
logger.
    Fields("request_id", "req-123").
    Fields("user", "alice").
    Fields("duration_ms", 42).
    Info("Request processed")

// Map-based fields
logger.Field(map[string]interface{}{
    "method": "POST",
    "path": "/api/users",
}).Debug("API call")

// Persistent context (included in ALL subsequent logs)
logger.AddContext("environment", "production", "version", "1.2.3")
logger.Info("Deployed")  // Output: ... [environment=production version=1.2.3]
4. Conditional & Error-Based Logging

Optimize performance with fluent conditional chains that completely skip processing when conditions are false:

// Boolean conditions
logger.If(debugMode).Debug("Detailed diagnostics")  // No overhead when false
logger.If(featureEnabled).Info("Feature used")

// Error conditions
err := db.Query()
logger.IfErr(err).Error("Query failed")              // Logs only if err != nil

// Multiple conditions - ANY true
logger.IfErrAny(err1, err2, err3).Fatal("System failure")

// Multiple conditions - ALL true
logger.IfErrOne(validateErr, authErr).Error("Both checks failed")

// Chain conditions
logger.
    If(debugMode).
    IfErr(queryErr).
    Fields("query", sql).
    Debug("Query debug")

Performance: When conditions are false, the logger returns immediately with zero allocations.

5. Powerful Debugging Toolkit

ll includes advanced debugging utilities not found in standard logging libraries:

Dbg() - Source-Aware Variable Inspection

Captures both variable name AND value from your source code:

x := 42
user := &User{Name: "Alice"}
ll.Dbg(x, user)  
// Output: [file.go:123] x = 42, *user = &{Name:Alice}
Dump() - Hex/ASCII Binary Inspection

Perfect for protocol debugging and binary data:

ll.Handler(lh.NewColorizedHandler(os.Stdout))
ll.Dump([]byte("hello\nworld"))
// Output: Colorized hex/ASCII dump with offset markers
Inspect() - Private Field Reflection

Reveals unexported fields, embedded structs, and pointer internals:

type secret struct {
    password string  // unexported!
}

s := secret{password: "hunter2"}
ll.Inspect(s)
// Output: [file.go:123] INSPECT: {
//   "(password)": "hunter2"  // Note the parentheses
// }
Stack() - Configurable Stack Traces
ll.StackSize(8192)  // Larger buffer for deep stacks
ll.Stack("Critical failure")
// Output: ERROR: Critical failure [stack=goroutine 1 [running]...]
Mark() - Execution Flow Tracing
func process() {
    ll.Mark()           // *MARK*: [file.go:123]
    ll.Mark("phase1")   // *phase1*: [file.go:124]
    // ... work ...
}
6. Production-Ready Handlers
import (
    "github.com/olekukonko/ll"
    "github.com/olekukonko/ll/lh"
    "github.com/olekukonko/ll/l3rd/syslog"
    "github.com/olekukonko/ll/l3rd/victoria"
)

// JSON for structured logging
logger.Handler(lh.NewJSONHandler(os.Stdout))

// Colorized for development
logger.Handler(lh.NewColorizedHandler(os.Stdout, 
    lh.WithColorTheme("dark"),
    lh.WithColorIntensity(lh.IntensityVibrant),
))

// Buffered for high throughput (100 entries or 10 seconds)
buffered := lh.NewBuffered(
    lh.NewJSONHandler(os.Stdout),
    lh.WithBatchSize(100),
    lh.WithFlushInterval(10 * time.Second),
)
logger.Handler(buffered)
defer buffered.Close()  // Ensures flush on exit

// Syslog integration
syslogHandler, _ := syslog.New(
    syslog.WithTag("myapp"),
    syslog.WithFacility(syslog.LOG_LOCAL0),
)
logger.Handler(syslogHandler)

// VictoriaLogs (cloud-native)
victoriaHandler, _ := victoria.New(
    victoria.WithURL("http://victoria-logs:9428"),
    victoria.WithAppName("payment-service"),
    victoria.WithEnvironment("production"),
    victoria.WithBatching(200, 5*time.Second),
)
logger.Handler(victoriaHandler)
7. Middleware Pipeline

Transform, filter, or reject logs with a middleware pipeline:

// Rate limiting - 10 logs per second maximum
rateLimiter := lm.NewRateLimiter(lx.LevelInfo, 10, time.Second)
logger.Use(rateLimiter)

// Sampling - 10% of debug logs
sampler := lm.NewSampling(lx.LevelDebug, 0.1)
logger.Use(sampler)

// Deduplication - suppress identical logs for 2 seconds
deduper := lh.NewDedup(logger.GetHandler(), 2*time.Second)
logger.Handler(deduper)

// Custom middleware
logger.Use(ll.Middle(func(e *lx.Entry) error {
    if strings.Contains(e.Message, "password") {
        return fmt.Errorf("sensitive information redacted")
    }
    return nil
}))
8. Global Convenience API

Use package-level functions for quick logging without creating loggers:

import "github.com/olekukonko/ll"

func main() {
    ll.Info("Server starting")           // Global logger
    ll.Fields("port", 8080).Info("Listening")
    
    // Conditional logging at package level
    ll.If(simulation).Debug("Test mode")
    ll.IfErr(err).Error("Startup failed")
    
    // Debug utilities
    ll.Dbg(config)
    ll.Dump(requestBody)
    ll.Inspect(complexStruct)
}

Real-World Examples

Web Server with Structured Logging
package main

import (
    "github.com/olekukonko/ll"
    "github.com/olekukonko/ll/lh"
    "net/http"
    "time"
)

func main() {
    // Root logger - enabled by default
    log := ll.New("server")
    
    // JSON output for production
    log.Handler(lh.NewJSONHandler(os.Stdout))
    
    // Request logger with context
    http.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
        reqLog := log.Namespace("http").Fields(
            "method", r.Method,
            "path", r.URL.Path,
            "request_id", r.Header.Get("X-Request-ID"),
        )
        
        start := time.Now()
        reqLog.Info("request started")
        
        // ... handle request ...
        
        reqLog.Fields(
            "status", 200,
            "duration_ms", time.Since(start).Milliseconds(),
        ).Info("request completed")
    })
    
    log.Info("Server listening on :8080")
    http.ListenAndServe(":8080", nil)
}
Microservice with VictoriaLogs
package main

import (
    "github.com/olekukonko/ll"
    "github.com/olekukonko/ll/l3rd/victoria"
)

func main() {
    // Production setup
    vlHandler, _ := victoria.New(
        victoria.WithURL("http://logs.internal:9428"),
        victoria.WithAppName("payment-api"),
        victoria.WithEnvironment("production"),
        victoria.WithVersion("1.2.3"),
        victoria.WithBatching(500, 2*time.Second),
        victoria.WithRetry(3),
    )
    defer vlHandler.Close()
    
    logger := ll.New("payment").
        Handler(vlHandler).
        AddContext("region", "us-east-1")
    
    logger.Info("Payment service initialized")
    
    // Conditional error handling
    if err := processPayment(); err != nil {
        logger.IfErr(err).
            Fields("payment_id", paymentID).
            Error("Payment processing failed")
    }
}

Performance

ll is engineered for high-performance environments:

Operation Time/op Allocations
Disabled log 15.9 ns 0 allocs
Simple text log 176 ns 2 allocs
With 2 fields 383 ns 4 allocs
JSON output 1006 ns 13 allocs
Namespace lookup (cached) 550 ns 6 allocs
Deduplication 214 ns 2 allocs

Key optimizations:

  • Zero allocations when logs are skipped (conditional, disabled)
  • Atomic operations for hot paths
  • Sync.Pool for buffer reuse
  • LRU cache for source file lines (Dbg)
  • Sharded mutexes for deduplication

Why Choose ll?

Feature ll slog zap logrus
Enabled by default
Hierarchical namespaces
Conditional logging
Error-based conditions
Source-aware Dbg()
Private field inspection
Hex/ASCII Dump()
Middleware pipeline ✅ (limited)
Deduplication
Rate limiting
VictoriaLogs support
Syslog support
Zero-allocs disabled logs
Thread-safe

Documentation

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Active

func Active() bool

Active returns true if the global logging system is currently active. Thread-safe via atomic operations. Example:

if ll.Active() {
    ll.Info("System active") // Output: [] INFO: System active
}

func Benchmark

func Benchmark(start time.Time)

Benchmark logs the duration since a start time at Info level using the default logger. It calculates the time elapsed since the provided start time and logs it with "start", "end", and "duration" fields. Thread-safe via the Logger’s mutex. Example:

start := time.Now()
time.Sleep(time.Millisecond)
ll.Benchmark(start) // Output: [] INFO: benchmark [start=... end=... duration=...]

func CanLog added in v0.0.7

func CanLog(level lx.LevelType) bool

CanLog checks if a log at the given level would be emitted by the default logger. It considers enablement, log level, namespaces, sampling, and rate limits. Thread-safe via the Logger’s shouldLog method. Example:

ll.Level(lx.LevelWarn)
canLog := ll.CanLog(lx.LevelInfo) // false

func Dbg

func Dbg(any ...interface{})

Dbg logs debug information including the source file, line number, and expression value using the default logger. It captures the calling line of code and displays both the expression and its value. Useful for debugging without temporary print statements. Example:

x := 42
ll.Dbg(x) // Output: [file.go:123] x = 42

func Debug

func Debug(args ...any)

Debug logs a message at Debug level with variadic arguments using the default logger. It concatenates the arguments with spaces and delegates to defaultLogger’s Debug method. Used for debugging information, typically disabled in production. Thread-safe. Example:

ll.Level(lx.LevelDebug)
ll.Debug("Debugging", "mode") // Output: [] DEBUG: Debugging mode

func Debugf added in v0.0.7

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

Debugf logs a message at Debug level with a format string using the default logger. It formats the message and delegates to defaultLogger’s Debugf method. Used for debugging information, typically disabled in production. Thread-safe. Example:

ll.Level(lx.LevelDebug)
ll.Debugf("Debug %s", "mode") // Output: [] DEBUG: Debug mode

func Dump

func Dump(values ...interface{})

Dump displays a hex and ASCII representation of a value’s binary form using the default logger. It serializes the value using gob encoding or direct conversion and shows a hex/ASCII dump. Useful for inspecting binary data structures. Example:

ll.Dump([]byte{0x41, 0x42}) // Outputs hex/ASCII dump

func Enabled

func Enabled() bool

Enabled returns whether the default logger is enabled for logging. It provides thread-safe read access to the enabled field using a read lock. Example:

ll.Enable()
if ll.Enabled() {
    ll.Info("Logging enabled") // Output: [] INFO: Logging enabled
}

func Err

func Err(errs ...error)

Err adds one or more errors to the default logger’s context and logs them. It stores non-nil errors in the "error" context field and logs their concatenated string representations (e.g., "failed 1; failed 2") at the Error level. Thread-safe via the Logger’s mutex. Example:

err1 := errors.New("failed 1")
ll.Err(err1)
ll.Info("Error occurred") // Output: [] ERROR: failed 1
                         //         [] INFO: Error occurred [error=failed 1]

func Error

func Error(args ...any)

Error logs a message at Error level with variadic arguments using the default logger. It concatenates the arguments with spaces and delegates to defaultLogger’s Error method. Used for error conditions requiring attention. Thread-safe. Example:

ll.Error("Database", "failure") // Output: [] ERROR: Database failure

func Errorf added in v0.0.7

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

Errorf logs a message at Error level with a format string using the default logger. It formats the message and delegates to defaultLogger’s Errorf method. Used for error conditions requiring attention. Thread-safe. Example:

ll.Errorf("Database %s", "failure") // Output: [] ERROR: Database failure

func Fatal

func Fatal(args ...any)

Fatal logs a message at Error level with a stack trace and variadic arguments using the default logger, then exits. It concatenates the arguments with spaces, logs with a stack trace, and terminates with exit code 1. Thread-safe. Example:

ll.Fatal("Fatal", "error") // Output: [] ERROR: Fatal error [stack=...], then exits

func Fatalf added in v0.0.7

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

Fatalf logs a formatted message at Error level with a stack trace using the default logger, then exits. It formats the message, logs with a stack trace, and terminates with exit code 1. Thread-safe. Example:

ll.Fatalf("Fatal %s", "error") // Output: [] ERROR: Fatal error [stack=...], then exits

func GetContext added in v0.0.7

func GetContext() map[string]interface{}

GetContext returns the default logger’s context map of persistent key-value fields. It provides thread-safe read access to the context using a read lock. Example:

ll.AddContext("user", "alice")
ctx := ll.GetContext() // Returns map[string]interface{}{"user": "alice"}k

func GetHandler added in v0.0.7

func GetHandler() lx.Handler

GetHandler returns the default logger’s current handler for customization or inspection. The returned handler should not be modified concurrently with logger operations. Example:

handler := ll.GetHandler() // Returns the current handler (e.g., TextHandler)

func GetLevel added in v0.0.7

func GetLevel() lx.LevelType

GetLevel returns the minimum log level for the default logger. It provides thread-safe read access to the level field using a read lock. Example:

ll.Level(lx.LevelWarn)
if ll.GetLevel() == lx.LevelWarn {
    ll.Warn("Warning level set") // Output: [] WARN: Warning level set
}

func GetPath added in v0.0.7

func GetPath() string

GetPath returns the default logger’s current namespace path. It provides thread-safe read access to the currentPath field using a read lock. Example:

logger := ll.Namespace("app")
path := logger.GetPath() // Returns "app"

func GetSeparator added in v0.0.7

func GetSeparator() string

GetSeparator returns the default logger’s namespace separator (e.g., "/"). It provides thread-safe read access to the separator field using a read lock. Example:

ll.Separator(".")
sep := ll.GetSeparator() // Returns "."

func GetStyle added in v0.0.7

func GetStyle() lx.StyleType

GetStyle returns the default logger’s namespace formatting style (FlatPath or NestedPath). It provides thread-safe read access to the style field using a read lock. Example:

ll.Style(lx.NestedPath)
if ll.GetStyle() == lx.NestedPath {
    ll.Info("Nested style") // Output: []: INFO: Nested style
}

func Info

func Info(args ...any)

Info logs a message at Info level with variadic arguments using the default logger. It concatenates the arguments with spaces and delegates to defaultLogger’s Info method. Thread-safe via the Logger’s log method. Example:

ll.Info("Service", "started") // Output: [] INFO: Service started

func Infof added in v0.0.7

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

Infof logs a message at Info level with a format string using the default logger. It formats the message using the provided format string and arguments, then delegates to defaultLogger’s Infof method. Thread-safe via the Logger’s log method. Example:

ll.Infof("Service %s", "started") // Output: [] INFO: Service started

func Inspect added in v0.1.3

func Inspect(values ...interface{})

Inspect logs one or more values in a **developer-friendly, deeply introspective format** at Info level. It includes the caller file and line number, and reveals **all fields** — including:

func Len added in v0.0.7

func Len() int64

Len returns the total number of log entries sent to the handler by the default logger. It provides thread-safe access to the entries counter using atomic operations. Example:

ll.Info("Test")
count := ll.Len() // Returns 1

func Mark added in v0.0.8

func Mark(names ...string)

Mark logs the current file and line number where it's called, without any additional debug information. It's useful for tracing execution flow without the verbosity of Dbg. Example:

logger.Mark() // *MARK*: [file.go:123]

func Measure

func Measure(fns ...func()) time.Duration

Measure is a benchmarking helper that measures and returns the duration of a function’s execution. It logs the duration at Info level with a "duration" field using defaultLogger. The function is executed once, and the elapsed time is returned. Thread-safe via the Logger’s mutex. Example:

duration := ll.Measure(func() { time.Sleep(time.Millisecond) })
// Output: [] INFO: function executed [duration=~1ms]

func Middle

func Middle(fn func(*lx.Entry) error) lx.Handler

Middle creates a middleware handler from a function. It wraps a function with the signature `func(*lx.Entry) error` into a middlewareFunc, allowing it to be used in the logger’s middleware pipeline. A non-nil error returned by the function will stop the log from being emitted, ensuring precise control over logging. Example:

logger.Use(ll.Middle(func(e *lx.Entry) error {
    if e.Level == lx.LevelDebug {
        return fmt.Errorf("debug logs disabled")
    }
    return nil
}))

func NamespaceEnabled added in v0.0.7

func NamespaceEnabled(path string) bool

NamespaceEnabled checks if a namespace is enabled in the default logger. It evaluates the namespace hierarchy, considering parent namespaces, and caches the result for performance. Thread-safe with read lock. Example:

ll.NamespaceDisable("app/db")
enabled := ll.NamespaceEnabled("app/db") // false

func Output added in v0.1.1

func Output(values ...interface{})

Output logs data in a human-readable JSON format at Info level, including caller file and line information. It is similar to Dbg but formats the output as JSON for better readability. It is thread-safe and respects the logger’s configuration (e.g., enabled, level, suspend, handler, middleware).

func Panic

func Panic(args ...any)

Panic logs a message at Error level with a stack trace and variadic arguments using the default logger, then panics. It concatenates the arguments with spaces, logs with a stack trace, and triggers a panic. Thread-safe. Example:

ll.Panic("Panic", "error") // Output: [] ERROR: Panic error [stack=...], then panics

func Panicf added in v0.0.7

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

Panicf logs a formatted message at Error level with a stack trace using the default logger, then panics. It formats the message, logs with a stack trace, and triggers a panic. Thread-safe. Example:

ll.Panicf("Panic %s", "error") // Output: [] ERROR: Panic error [stack=...], then panics

func Print

func Print(args ...any)

Print logs a message at Info level without format specifiers using the default logger. It concatenates variadic arguments with spaces, minimizing allocations, and delegates to defaultLogger’s Print method. Thread-safe via the Logger’s log method. Example:

ll.Print("message", "value") // Output: [] INFO: message value

func Printf added in v0.0.7

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

Printf logs a message at Info level with a format string using the default logger. It formats the message and delegates to defaultLogger’s Printf method. Thread-safe via the Logger’s log method. Example:

ll.Printf("Message %s", "value") // Output: [] INFO: Message value

func Println added in v0.0.8

func Println(args ...any)

Println logs a message at Info level without format specifiers, minimizing allocations by concatenating arguments with spaces. It is thread-safe via the log method. Example:

ll.Println("message", "value") // Output: [] INFO: message value [New Line]

func Remove added in v0.0.7

func Remove(m *Middleware)

Remove removes middleware by the reference returned from Use for the default logger. It delegates to the Middleware’s Remove method for thread-safe removal. Example:

mw := ll.Use(someMiddleware)
ll.Remove(mw) // Removes middleware

func Shutdown

func Shutdown()

Shutdown deactivates the global logging system. All logging operations are skipped, regardless of individual logger or namespace configurations, until Start() is called again. Thread-safe via atomic operations. Example:

ll.Shutdown()
ll.Info("Ignored") // Inactive output

func Stack

func Stack(args ...any)

Stack logs a message at Error level with a stack trace and variadic arguments using the default logger. It concatenates the arguments with spaces and delegates to defaultLogger’s Stack method. Thread-safe. Example:

ll.Stack("Critical", "error") // Output: [] ERROR: Critical error [stack=...]

func Stackf added in v0.0.7

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

Stackf logs a message at Error level with a stack trace and a format string using the default logger. It formats the message and delegates to defaultLogger’s Stackf method. Thread-safe. Example:

ll.Stackf("Critical %s", "error") // Output: [] ERROR: Critical error [stack=...]

func Start

func Start()

Start activates the global logging system. If the system was shut down, this re-enables all logging operations, subject to individual logger and namespace configurations. Thread-safe via atomic operations. Example:

ll.Shutdown()
ll.Info("Ignored") // Inactive output
ll.Start()
ll.Info("Logged")  // Output: [] INFO: Logged

func Warn

func Warn(args ...any)

Warn logs a message at Warn level with variadic arguments using the default logger. It concatenates the arguments with spaces and delegates to defaultLogger’s Warn method. Used for warning conditions that do not halt execution. Thread-safe. Example:

ll.Warn("Low", "memory") // Output: [] WARN: Low memory

func Warnf added in v0.0.7

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

Warnf logs a message at Warn level with a format string using the default logger. It formats the message and delegates to defaultLogger’s Warnf method. Used for warning conditions that do not halt execution. Thread-safe. Example:

ll.Warnf("Low %s", "memory") // Output: [] WARN: Low memory

Types

type Conditional

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

Conditional enables conditional logging based on a boolean condition. It wraps a logger with a condition that determines whether logging operations are executed, optimizing performance by skipping expensive operations (e.g., field computation, message formatting) when the condition is false. The struct supports fluent chaining for adding fields and logging.

func If added in v0.0.7

func If(condition bool) *Conditional

If creates a conditional logger that logs only if the condition is true using the default logger.

func IfErr added in v0.1.5

func IfErr(err error) *Conditional

IfErr creates a conditional logger that logs only if the error is non-nil using the default logger.

func IfErrAny added in v0.1.5

func IfErrAny(errs ...error) *Conditional

IfErrAny creates a conditional logger that logs only if AT LEAST ONE error is non-nil using the default logger.

func IfErrOne added in v0.1.5

func IfErrOne(errs ...error) *Conditional

IfErrOne creates a conditional logger that logs only if ALL errors are non-nil using the default logger.

func (*Conditional) Debug

func (cl *Conditional) Debug(args ...any)

Debug logs a message at Debug level with variadic arguments if the condition is true. It concatenates the arguments with spaces and delegates to the logger's Debug method if the condition is true. Skips processing if false, optimizing performance. Thread-safe via the logger's log method. Example:

logger := New("app").Enable().Level(lx.LevelDebug)
logger.If(true).Debug("Debugging", "mode")   // Output: [app] DEBUG: Debugging mode
logger.If(false).Debug("Debugging", "ignored") // No output

func (*Conditional) Debugf added in v0.0.7

func (cl *Conditional) Debugf(format string, args ...any)

Debugf logs a message at Debug level with a format string if the condition is true. It formats the message and delegates to the logger's Debugf method if the condition is true. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable().Level(lx.LevelDebug)
logger.If(true).Debugf("Debug %s", "mode")   // Output: [app] DEBUG: Debug mode
logger.If(false).Debugf("Debug %s", "ignored") // No output

func (*Conditional) Error

func (cl *Conditional) Error(args ...any)

Error logs a message at Error level with variadic arguments if the condition is true. It concatenates the arguments with spaces and delegates to the logger's Error method if the condition is true. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Error("Error", "occurred")   // Output: [app] ERROR: Error occurred
logger.If(false).Error("Error", "ignored") // No output

func (*Conditional) Errorf added in v0.0.7

func (cl *Conditional) Errorf(format string, args ...any)

Errorf logs a message at Error level with a format string if the condition is true. It formats the message and delegates to the logger's Errorf method if the condition is true. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Errorf("Error %s", "occurred")   // Output: [app] ERROR: Error occurred
logger.If(false).Errorf("Error %s", "ignored") // No output

func (*Conditional) Fatal added in v0.0.7

func (cl *Conditional) Fatal(args ...any)

Fatal logs a message at Error level with a stack trace and variadic arguments if the condition is true, then exits. It concatenates the arguments with spaces and delegates to the logger's Fatal method if the condition is true, terminating the program with exit code 1. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Fatal("Fatal", "error")   // Output: [app] ERROR: Fatal error [stack=...], then exits
logger.If(false).Fatal("Fatal", "ignored") // No output, no exit

func (*Conditional) Fatalf added in v0.0.7

func (cl *Conditional) Fatalf(format string, args ...any)

Fatalf logs a formatted message at Error level with a stack trace if the condition is true, then exits. It formats the message and delegates to the logger's Fatalf method if the condition is true, terminating the program with exit code 1. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Fatalf("Fatal %s", "error")   // Output: [app] ERROR: Fatal error [stack=...], then exits
logger.If(false).Fatalf("Fatal %s", "ignored") // No output, no exit

func (*Conditional) Field

func (cl *Conditional) Field(fields map[string]interface{}) *FieldBuilder

Field starts a fluent chain for adding fields from a map, if the condition is true. It returns a FieldBuilder to attach fields from a map, skipping processing if the condition is false. Thread-safe via the FieldBuilder's logger. Example:

logger := New("app").Enable()
logger.If(true).Field(map[string]interface{}{"user": "alice"}).Info("Logged") // Output: [app] INFO: Logged [user=alice]
logger.If(false).Field(map[string]interface{}{"user": "alice"}).Info("Ignored") // No output

func (*Conditional) Fields

func (cl *Conditional) Fields(pairs ...any) *FieldBuilder

Fields starts a fluent chain for adding fields using variadic key-value pairs, if the condition is true. It returns a FieldBuilder to attach fields, skipping field processing if the condition is false to optimize performance. Thread-safe via the FieldBuilder's logger. Example:

logger := New("app").Enable()
logger.If(true).Fields("user", "alice").Info("Logged") // Output: [app] INFO: Logged [user=alice]
logger.If(false).Fields("user", "alice").Info("Ignored") // No output, no field processing

func (*Conditional) IfAny

func (cl *Conditional) IfAny(conditions ...bool) *Conditional

IfAny creates a conditional logger that logs only if at least one condition is true. It evaluates a variadic list of boolean conditions, setting the condition to true if any is true (logical OR). Returns a new Conditional with the result. Thread-safe via the underlying logger. Example:

logger := New("app").Enable()
logger.IfAny(false, true).Info("Logged")   // Output: [app] INFO: Logged
logger.IfAny(false, false).Info("Ignored") // No output

func (*Conditional) IfErr added in v0.1.5

func (cl *Conditional) IfErr(err error) *Conditional

IfErr creates a conditional logger that logs only if the error is non-nil. Returns a new Conditional with the error check result. Example:

err := doSomething()
logger.If(true).IfErr(err).Error("Failed") // Only logs if condition true AND err != nil

func (*Conditional) IfErrAny added in v0.1.5

func (cl *Conditional) IfErrAny(errs ...error) *Conditional

IfErrAny creates a conditional logger that logs only if AT LEAST ONE error is non-nil. Returns a new Conditional with the logical OR result of error checks. Example:

err1 := validate(input)
err2 := authorize(user)
logger.If(true).IfErrAny(err1, err2).Error("Either failed") // Logs if condition true AND either error exists

func (*Conditional) IfErrOne added in v0.1.5

func (cl *Conditional) IfErrOne(errs ...error) *Conditional

IfErrOne creates a conditional logger that logs only if ALL errors are non-nil. Returns a new Conditional with the logical AND result of error checks. Example:

err1 := validate(input)
err2 := authorize(user)
logger.If(true).IfErrOne(err1, err2).Error("Both failed") // Logs if condition true AND both errors exist

func (*Conditional) IfOne

func (cl *Conditional) IfOne(conditions ...bool) *Conditional

IfOne creates a conditional logger that logs only if all conditions are true. It evaluates a variadic list of boolean conditions, setting the condition to true only if all are true (logical AND). Returns a new Conditional with the result. Thread-safe via the underlying logger. Example:

logger := New("app").Enable()
logger.IfOne(true, true).Info("Logged")   // Output: [app] INFO: Logged
logger.IfOne(true, false).Info("Ignored") // No output

func (*Conditional) Info

func (cl *Conditional) Info(args ...any)

Info logs a message at Info level with variadic arguments if the condition is true. It concatenates the arguments with spaces and delegates to the logger's Info method if the condition is true. Skips processing if false, optimizing performance. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Info("Action", "started")   // Output: [app] INFO: Action started
logger.If(false).Info("Action", "ignored") // No output

func (*Conditional) Infof added in v0.0.7

func (cl *Conditional) Infof(format string, args ...any)

Infof logs a message at Info level with a format string if the condition is true. It formats the message using the provided format string and arguments, delegating to the logger's Infof method if the condition is true. Skips processing if false, optimizing performance. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Infof("Action %s", "started")   // Output: [app] INFO: Action started
logger.If(false).Infof("Action %s", "ignored") // No output

func (*Conditional) Panic added in v0.0.7

func (cl *Conditional) Panic(args ...any)

Panic logs a message at Error level with a stack trace and variadic arguments if the condition is true, then panics. It concatenates the arguments with spaces and delegates to the logger's Panic method if the condition is true, triggering a panic. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Panic("Panic", "error")   // Output: [app] ERROR: Panic error [stack=...], then panics
logger.If(false).Panic("Panic", "ignored") // No output, no panic

func (*Conditional) Panicf added in v0.0.7

func (cl *Conditional) Panicf(format string, args ...any)

Panicf logs a formatted message at Error level with a stack trace if the condition is true, then panics. It formats the message and delegates to the logger's Panicf method if the condition is true, triggering a panic. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Panicf("Panic %s", "error")   // Output: [app] ERROR: Panic error [stack=...], then panics
logger.If(false).Panicf("Panic %s", "ignored") // No output, no panic

func (*Conditional) Stack

func (cl *Conditional) Stack(args ...any)

Stack logs a message at Error level with a stack trace and variadic arguments if the condition is true. It concatenates the arguments with spaces and delegates to the logger's Stack method if the condition is true. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Stack("Critical", "error")   // Output: [app] ERROR: Critical error [stack=...]
logger.If(false).Stack("Critical", "ignored") // No output

func (*Conditional) Stackf added in v0.0.7

func (cl *Conditional) Stackf(format string, args ...any)

Stackf logs a message at Error level with a stack trace and a format string if the condition is true. It formats the message and delegates to the logger's Stackf method if the condition is true. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Stackf("Critical %s", "error")   // Output: [app] ERROR: Critical error [stack=...]
logger.If(false).Stackf("Critical %s", "ignored") // No output

func (*Conditional) Warn

func (cl *Conditional) Warn(args ...any)

Warn logs a message at Warn level with variadic arguments if the condition is true. It concatenates the arguments with spaces and delegates to the logger's Warn method if the condition is true. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Warn("Warning", "issued")   // Output: [app] WARN: Warning issued
logger.If(false).Warn("Warning", "ignored") // No output

func (*Conditional) Warnf added in v0.0.7

func (cl *Conditional) Warnf(format string, args ...any)

Warnf logs a message at Warn level with a format string if the condition is true. It formats the message and delegates to the logger's Warnf method if the condition is true. Skips processing if false. Thread-safe via the logger's log method. Example:

logger := New("app").Enable()
logger.If(true).Warnf("Warning %s", "issued")   // Output: [app] WARN: Warning issued
logger.If(false).Warnf("Warning %s", "ignored") // No output

type FieldBuilder

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

FieldBuilder enables fluent addition of fields before logging. It acts as a builder pattern to attach key-value pairs (fields) to log entries, supporting structured logging with metadata. The builder allows chaining to add fields and log messages at various levels (Info, Debug, Warn, Error, etc.) in a single expression.

func Field added in v0.0.6

func Field(fields map[string]interface{}) *FieldBuilder

Field starts a fluent chain for adding fields from a map with the default logger. It creates a FieldBuilder to attach fields from a map, supporting type-safe field addition. Thread-safe via the FieldBuilder’s logger. Example:

ll.Field(map[string]interface{}{"user": "alice"}).Info("Action") // Output: [] INFO: Action [user=alice]

func Fields added in v0.0.6

func Fields(pairs ...any) *FieldBuilder

Fields starts a fluent chain for adding fields using variadic key-value pairs with the default logger. It creates a FieldBuilder to attach fields, handling non-string keys or uneven pairs by adding an error field. Thread-safe via the FieldBuilder’s logger. Example:

ll.Fields("user", "alice").Info("Action") // Output: [] INFO: Action [user=alice]

func (*FieldBuilder) Debug

func (fb *FieldBuilder) Debug(args ...any)

Debug logs a message at Debug level with the builder's fields. It concatenates the arguments with spaces and delegates to the logger's log method. This method is used for debugging information. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Debug("Debugging", "mode") // Output: [app] DEBUG: Debugging mode [user=alice]

func (*FieldBuilder) Debugf added in v0.0.7

func (fb *FieldBuilder) Debugf(format string, args ...any)

Debugf logs a message at Debug level with the builder's fields. It formats the message and delegates to the logger's log method. This method is used for debugging information that may be disabled in production. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Debugf("Debug %s", "mode") // Output: [app] DEBUG: Debug mode [user=alice]

func (*FieldBuilder) Err

func (fb *FieldBuilder) Err(errs ...error) *FieldBuilder

Err adds one or more errors to the FieldBuilder as a field and logs them. It stores non-nil errors in the "error" field: a single error if only one is non-nil, or a slice of errors if multiple are non-nil. Returns the FieldBuilder for chaining. Example:

logger := New("app").Enable()
err1 := errors.New("failed 1")
err2 := errors.New("failed 2")
logger.Fields("k", "v").Err(err1, err2).Info("Error occurred")

func (*FieldBuilder) Error

func (fb *FieldBuilder) Error(args ...any)

Error logs a message at Error level with the builder's fields. It concatenates the arguments with spaces and delegates to the logger's log method. This method is used for error conditions. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Error("Error", "occurred") // Output: [app] ERROR: Error occurred [user=alice]

func (*FieldBuilder) Errorf added in v0.0.7

func (fb *FieldBuilder) Errorf(format string, args ...any)

Errorf logs a message at Error level with the builder's fields. It formats the message and delegates to the logger's log method. This method is used for error conditions that may require attention. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Errorf("Error %s", "occurred") // Output: [app] ERROR: Error occurred [user=alice]

func (*FieldBuilder) Fatal

func (fb *FieldBuilder) Fatal(args ...any)

Fatal logs a message at Error level with a stack trace and the builder's fields, then exits. It constructs the message from variadic arguments, logs it with a stack trace, and terminates the program with exit code 1. This method is used for unrecoverable errors. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Fatal("Fatal", "error") // Output: [app] ERROR: Fatal error [user=alice stack=...], then exits

func (*FieldBuilder) Fatalf added in v0.0.7

func (fb *FieldBuilder) Fatalf(format string, args ...any)

Fatalf logs a formatted message at Error level with a stack trace and the builder's fields, then exits. It delegates to Fatal. This method is used for unrecoverable errors. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Fatalf("Fatal %s", "error") // Output: [app] ERROR: Fatal error [user=alice stack=...], then exits

func (*FieldBuilder) Info

func (fb *FieldBuilder) Info(args ...any)

Info logs a message at Info level with the builder's fields. It concatenates the arguments with spaces and delegates to the logger's log method. This method is used for informational messages. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Info("Action", "started") // Output: [app] INFO: Action started [user=alice]

func (*FieldBuilder) Infof added in v0.0.7

func (fb *FieldBuilder) Infof(format string, args ...any)

Infof logs a message at Info level with the builder's fields. It formats the message using the provided format string and arguments, then delegates to the logger's internal log method. This method is part of the fluent API. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Infof("Action %s", "started") // Output: [app] INFO: Action started [user=alice]

func (*FieldBuilder) Logger

func (fb *FieldBuilder) Logger() *Logger

Logger creates a new logger with the builder's fields embedded in its context. It clones the parent logger and copies the builder's fields into the new logger's context, enabling persistent field inclusion in subsequent logs. This method supports fluent chaining after Fields or Field calls. Example:

logger := New("app").Enable()
newLogger := logger.Fields("user", "alice").Logger()
newLogger.Info("Action") // Output: [app] INFO: Action [user=alice]

func (*FieldBuilder) Merge

func (fb *FieldBuilder) Merge(pairs ...any) *FieldBuilder

Merge adds additional key-value pairs to the FieldBuilder. It processes variadic arguments as key-value pairs, expecting string keys. Returns the FieldBuilder for chaining. Example:

logger := New("app").Enable()
logger.Fields("k1", "v1").Merge("k2", "v2").Info("Action") // Output: [app] INFO: Action [k1=v1 k2=v2]

func (*FieldBuilder) Panic

func (fb *FieldBuilder) Panic(args ...any)

Panic logs a message at Error level with a stack trace and the builder's fields, then panics. It constructs the message from variadic arguments, logs it with a stack trace, and triggers a panic with the message. This method is used for critical errors. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Panic("Panic", "error") // Output: [app] ERROR: Panic error [user=alice stack=...], then panics

func (*FieldBuilder) Panicf added in v0.0.7

func (fb *FieldBuilder) Panicf(format string, args ...any)

Panicf logs a formatted message at Error level with a stack trace and the builder's fields, then panics. It delegates to Panic. This method is used for critical errors. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Panicf("Panic %s", "error") // Output: [app] ERROR: Panic error [user=alice stack=...], then panics

func (*FieldBuilder) Stack

func (fb *FieldBuilder) Stack(args ...any)

Stack logs a message at Error level with a stack trace and the builder's fields. It concatenates the arguments with spaces and delegates to the logger's log method. This method is useful for debugging critical errors. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Stack("Critical", "error") // Output: [app] ERROR: Critical error [user=alice stack=...]

func (*FieldBuilder) Stackf added in v0.0.7

func (fb *FieldBuilder) Stackf(format string, args ...any)

Stackf logs a message at Error level with a stack trace and the builder's fields. It formats the message and delegates to the logger's log method. This method is useful for debugging critical errors. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Stackf("Critical %s", "error") // Output: [app] ERROR: Critical error [user=alice stack=...]

func (*FieldBuilder) Warn

func (fb *FieldBuilder) Warn(args ...any)

Warn logs a message at Warn level with the builder's fields. It concatenates the arguments with spaces and delegates to the logger's log method. This method is used for warning conditions. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Warn("Warning", "issued") // Output: [app] WARN: Warning issued [user=alice]

func (*FieldBuilder) Warnf added in v0.0.7

func (fb *FieldBuilder) Warnf(format string, args ...any)

Warnf logs a message at Warn level with the builder's fields. It formats the message and delegates to the logger's log method. This method is used for warning conditions that do not halt execution. Example:

logger := New("app").Enable()
logger.Fields("user", "alice").Warnf("Warning %s", "issued") // Output: [app] WARN: Warning issued [user=alice]

type Inspector added in v0.1.1

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

Inspector is a utility for Logger that provides advanced inspection and logging of data in human-readable JSON format. It uses reflection to access and represent unexported fields, nested structs, embedded structs, and pointers, making it useful for debugging complex data structures.

func NewInspector added in v0.1.1

func NewInspector(logger *Logger) *Inspector

NewInspector returns a new Inspector instance associated with the provided logger.

func (*Inspector) Log added in v0.1.1

func (o *Inspector) Log(skip int, values ...interface{})

Log outputs the given values as indented JSON at the Info level, prefixed with the caller's file name and line number. It handles structs (including unexported fields, nested, and embedded), pointers, errors, and other types. The skip parameter determines how many stack frames to skip when identifying the caller; typically set to 2 to account for the call to Log and its wrapper.

Example usage within a Logger method:

o := NewInspector(l)
o.Log(2, someStruct)

type Logger

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

Logger manages logging configuration and behavior, encapsulating state such as enablement, log level, namespaces, context fields, output style, handler, middleware, and formatting. It is thread-safe, using a read-write mutex to protect concurrent access to its fields.

func AddContext added in v0.0.7

func AddContext(pairs ...any) *Logger

AddContext adds a key-value pair to the default logger’s context, modifying it directly. It mutates the default logger’s context and is thread-safe using a write lock. Example:

ll.AddContext("user", "alice")
ll.Info("Action") // Output: [] INFO: Action [user=alice]

func Apply added in v0.1.4

func Apply(opts ...Option) *Logger

func Clear added in v0.0.7

func Clear() *Logger

Clear removes all middleware functions from the default logger. It resets the middleware chain to empty, ensuring no middleware is applied. Thread-safe with write lock. Returns the default logger for chaining. Example:

ll.Use(someMiddleware)
ll.Clear()
ll.Info("Inactive middleware") // Output: [] INFO: Inactive middleware

func Clone

func Clone() *Logger

Clone returns a new logger with the same configuration as the default logger. It creates a copy of defaultLogger’s settings (level, style, namespaces, etc.) but with an independent context, allowing customization without affecting the global logger. Thread-safe via the Logger’s Clone method. Example:

logger := ll.Clone().Namespace("sub")
logger.Info("Sub-logger") // Output: [sub] INFO: Sub-logger

func Context added in v0.0.7

func Context(fields map[string]interface{}) *Logger

Context creates a new logger with additional contextual fields using the default logger. It preserves existing context fields and adds new ones, returning a new logger instance to avoid mutating the default logger. Thread-safe with write lock. Example:

logger := ll.Context(map[string]interface{}{"user": "alice"})
logger.Info("Action") // Output: [] INFO: Action [user=alice]

func Disable

func Disable() *Logger

Disable deactivates logging for the default logger. It suppresses all logs, regardless of level or namespace. Thread-safe with write lock. Returns the default logger for method chaining. Example:

ll.Disable()
ll.Info("Ignored") // Inactive output

func Enable

func Enable() *Logger

Enable activates logging for the default logger. It allows logs to be emitted if other conditions (level, namespace) are met. Thread-safe with write lock. Returns the default logger for method chaining. Example:

ll.Disable()
ll.Info("Ignored") // Inactive output
ll.Enable()
ll.Info("Logged")  // Output: [] INFO: Logged

func Handler

func Handler(handler lx.Handler) *Logger

Handler sets the handler for the default logger. It configures the output destination and format (e.g., text, JSON) for logs emitted by defaultLogger. Returns the default logger for method chaining, enabling fluent configuration. Example:

ll.Handler(lh.NewJSONHandler(os.Stdout)).Enable()
ll.Info("Started") // Output: {"level":"INFO","message":"Started"}

func Indent added in v0.0.6

func Indent(depth int) *Logger

Indent sets the indentation level for all log messages of the default logger. Each level adds two spaces to the log message, useful for hierarchical output. Thread-safe with write lock. Returns the default logger for method chaining. Example:

ll.Indent(2)
ll.Info("Indented") // Output: [] INFO:     Indented

func Labels added in v0.1.5

func Labels(names ...string) *Logger

Labels temporarily attaches one or more label names to the logger for the next log entry. Labels are typically used for metrics, benchmarking, tracing, or categorizing logs in a structured way.

The labels are stored atomically and intended to be short-lived, applying only to the next log operation (or until overwritten by a subsequent call to Labels). Multiple labels can be provided as separate string arguments.

Example usage:

logger := New("app").Enable()

// Add labels for a specific operation
logger.Labels("load_users", "process_orders").Measure(func() {
    // ... perform work ...
}, func() {
    // ... optional callback ...
})

func Level

func Level(level lx.LevelType) *Logger

Level sets the minimum log level for the default logger. It determines which log messages (Debug, Info, Warn, Error) are emitted. Messages below the specified level are ignored. Returns the default logger for method chaining. Example:

ll.Level(lx.LevelInfo)
ll.Warn("Ignored") // Inactive output
ll.Info("Logged")  // Output: [] INFO: Logged

func Line added in v0.0.6

func Line(lines ...int) *Logger

Line adds vertical spacing (newlines) to the log output using the default logger. If no arguments are provided, it defaults to 1 newline. Multiple values are summed to determine the total lines. Useful for visually separating log sections. Thread-safe. Example:

ll.Line(2).Info("After two newlines") // Adds 2 blank lines before: [] INFO: After two newlines

func Namespace added in v0.0.6

func Namespace(name string) *Logger

Namespace creates a child logger with a sub-namespace appended to the current path. The child inherits the default logger’s configuration but has an independent context. Thread-safe with read lock. Returns the new logger for further configuration or logging. Example:

logger := ll.Namespace("app")
logger.Info("Started") // Output: [app] INFO: Started

func NamespaceDisable

func NamespaceDisable(path string) *Logger

NamespaceDisable disables logging for a namespace and its children using the default logger. It suppresses logging for the specified namespace path and all its descendants. Returns the default logger for method chaining. Thread-safe via the Logger’s mutex. Example:

ll.NamespaceDisable("app/db")
ll.Clone().Namespace("db").Info("Query") // Inactive output

func NamespaceEnable

func NamespaceEnable(path string) *Logger

NamespaceEnable enables logging for a namespace and its children using the default logger. It activates logging for the specified namespace path (e.g., "app/db") and all its descendants. Returns the default logger for method chaining. Thread-safe via the Logger’s mutex. Example:

ll.NamespaceEnable("app/db")
ll.Clone().Namespace("db").Info("Query") // Output: [app/db] INFO: Query

func New

func New(namespace string, opts ...Option) *Logger

New creates a new Logger with the given namespace and optional configurations. It initializes with defaults: disabled, Debug level, flat namespace style, text handler to os.Stdout, and an empty middleware chain. Options (e.g., WithHandler, WithLevel) can override defaults. The logger is thread-safe via mutex-protected methods. Example:

logger := New("app", WithHandler(lh.NewTextHandler(os.Stdout))).Enable()
logger.Info("Starting application") // Output: [app] INFO: Starting application

func Prefix added in v0.0.7

func Prefix(prefix string) *Logger

Prefix sets a prefix to be prepended to all log messages of the default logger. The prefix is applied before the message in the log output. Thread-safe with write lock. Returns the default logger for method chaining. Example:

ll.Prefix("APP: ")
ll.Info("Started") // Output: [] INFO: APP: Started

func Separator added in v0.0.7

func Separator(separator string) *Logger

Separator sets the namespace separator for the default logger (e.g., "/" or "."). It updates the separator used in namespace paths. Thread-safe with write lock. Returns the default logger for method chaining. Example:

ll.Separator(".")
ll.Namespace("app").Info("Log") // Output: [app] INFO: Log

func StackSize added in v0.0.7

func StackSize(size int) *Logger

StackSize sets the buffer size for stack trace capture in the default logger. It configures the maximum size for stack traces in Stack, Fatal, and Panic methods. Thread-safe with write lock. Returns the default logger for chaining. Example:

ll.StackSize(65536)
ll.Stack("Error") // Captures up to 64KB stack trace

func Style

func Style(style lx.StyleType) *Logger

Style sets the namespace style for the default logger. It controls how namespace paths are formatted in logs (FlatPath: parent/child, NestedPath: [parent]→[child]). Returns the default logger for method chaining. Example:

ll.Style(lx.NestedPath)
ll.Info("Test") // Output: []: INFO: Test

func Toggle added in v0.1.4

func Toggle(v bool) *Logger

func (*Logger) AddContext

func (l *Logger) AddContext(pairs ...any) *Logger

AddContext adds one or more key-value pairs to the logger's persistent context. These fields will be included in **every** subsequent log message from this logger (and its child namespace loggers).

It supports variadic key-value pairs (string key, any value). Non-string keys or uneven number of arguments will be safely ignored/logged.

Returns the logger for chaining.

Examples:

logger.AddContext("user", "alice", "env", "prod")
logger.AddContext("request_id", reqID, "trace_id", traceID)
logger.AddContext("service", "payment")                    // single pair

func (*Logger) Apply added in v0.1.4

func (l *Logger) Apply(opts ...Option) *Logger

Apply applies one or more functional options to the default/global logger. Useful for late configuration (e.g., after migration, attach VictoriaLogs handler, set level, add middleware, etc.) without changing existing New() calls.

Example:

// In main() or init(), after setting up handler
ll.Apply(
    ll.Handler(vlBatched),
    ll.Level(ll.LevelInfo),
    ll.Use(rateLimiterMiddleware),
)

Returns the default logger for chaining (if needed).

func (*Logger) Benchmark

func (l *Logger) Benchmark(start time.Time) time.Duration

Benchmark logs the duration since a start time at Info level, including "start", "end", and "duration" fields. It is thread-safe via Fields and log methods. Example:

logger := New("app").Enable()
start := time.Now()
logger.Benchmark(start) // Output: [app] INFO: benchmark [start=... end=... duration=...]

func (*Logger) CanLog

func (l *Logger) CanLog(level lx.LevelType) bool

CanLog checks if a log at the given level would be emitted, considering enablement, log level, namespaces, sampling, and rate limits. It is thread-safe via shouldLog. Example:

logger := New("app").Enable().Level(lx.LevelWarn)
canLog := logger.CanLog(lx.LevelInfo) // false

func (*Logger) Clear

func (l *Logger) Clear() *Logger

Clear removes all middleware functions, resetting the middleware chain to empty. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable().Use(someMiddleware)
logger.Clear()
logger.Info("Inactive middleware") // Output: [app] INFO: Inactive middleware

func (*Logger) Clone

func (l *Logger) Clone() *Logger

Clone creates a new logger with the same configuration and namespace as the parent, but with a fresh context map to allow independent field additions. It is thread-safe using a read lock. Example:

logger := New("app").Enable().Context(map[string]interface{}{"k": "v"})
clone := logger.Clone()
clone.Info("Cloned") // Output: [app] INFO: Cloned [k=v]

func (*Logger) Context

func (l *Logger) Context(fields map[string]interface{}) *Logger

Context creates a new logger with additional contextual fields, preserving existing fields and adding new ones. It returns a new logger to avoid mutating the parent and is thread-safe using a write lock. Example:

logger := New("app").Enable()
logger = logger.Context(map[string]interface{}{"user": "alice"})
logger.Info("Action") // Output: [app] INFO: Action [user=alice]

func (*Logger) Dbg

func (l *Logger) Dbg(values ...interface{})

Dbg logs debug information including source file, line number, and the best-effort extracted expression.

Example:

x := 42
logger.Dbg("val", x)
Output: [file.go:123] "val" = "val", x = 42

func (*Logger) Debug

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

Debug logs a message at Debug level, formatting it and delegating to the internal log method. It is thread-safe. Example:

logger := New("app").Enable().Level(lx.LevelDebug)
logger.Debug("Debugging") // Output: [app] DEBUG: Debugging

func (*Logger) Debugf added in v0.0.7

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

Debugf logs a formatted message at Debug level, delegating to Debug. It is thread-safe. Example:

logger := New("app").Enable().Level(lx.LevelDebug)
logger.Debugf("Debug %s", "message") // Output: [app] DEBUG: Debug message

func (*Logger) Disable

func (l *Logger) Disable() *Logger

Disable deactivates logging, suppressing all logs regardless of level or namespace. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable().Disable()
logger.Info("Ignored") // Inactive output

func (*Logger) Dump

func (l *Logger) Dump(values ...interface{})

Dump displays a hex and ASCII representation of a value's binary form, using gob encoding or direct conversion. It is useful for inspecting binary data structures. Example:

type Data struct { X int; Y string }
logger.Dump(Data{42, "test"}) // Outputs hex/ASCII dump

func (*Logger) Enable

func (l *Logger) Enable() *Logger

Enable activates logging, allowing logs to be emitted if other conditions (e.g., level, namespace) are met. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable()
logger.Info("Started") // Output: [app] INFO: Started

func (*Logger) Enabled

func (l *Logger) Enabled() bool

Enabled checks if the logger is enabled for logging. It is thread-safe using a read lock. Example:

logger := New("app").Enable()
if logger.Enabled() {
    logger.Info("Logging is enabled") // Output: [app] INFO: Logging is enabled
}

func (*Logger) Err

func (l *Logger) Err(errs ...error)

Err adds one or more errors to the loggerâ s context and logs them at Error level. Non-nil errors are stored in the "error" context field (single error or slice) and logged as a concatenated string (e.g., "failed 1; failed 2"). It is thread-safe and returns the logger for chaining. Example:

logger := New("app").Enable()
err1 := errors.New("failed 1")
err2 := errors.New("failed 2")
logger.Err(err1, err2).Info("Error occurred")
// Output: [app] ERROR: failed 1; failed 2
//         [app] INFO: Error occurred [error=[failed 1 failed 2]]

func (*Logger) Error

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

Error logs a message at Error level, formatting it and delegating to the internal log method. It is thread-safe. Example:

logger := New("app").Enable()
logger.Error("Error occurred") // Output: [app] ERROR: Error occurred

func (*Logger) Errorf added in v0.0.7

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

Errorf logs a formatted message at Error level, delegating to Error. It is thread-safe. Example:

logger := New("app").Enable()
logger.Errorf("Error %s", "occurred") // Output: [app] ERROR: Error occurred

func (*Logger) Fatal

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

Fatal logs a message at Error level with a stack trace and exits the program with exit code 1. It is thread-safe. Example:

logger := New("app").Enable()
logger.Fatal("Fatal error") // Output: [app] ERROR: Fatal error [stack=...], then exits

func (*Logger) Fatalf added in v0.0.7

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

Fatalf logs a formatted message at Error level with a stack trace and exits the program. It delegates to Fatal and is thread-safe. Example:

logger := New("app").Enable()
logger.Fatalf("Fatal %s", "error") // Output: [app] ERROR: Fatal error [stack=...], then exits

func (*Logger) Field

func (l *Logger) Field(fields map[string]interface{}) *FieldBuilder

Field starts a fluent chain for adding fields from a map, creating a FieldBuilder for type-safe field addition. It is thread-safe via the FieldBuilderâ s logger. Example:

logger := New("app").Enable()
logger.Field(map[string]interface{}{"user": "alice"}).Info("Action") // Output: [app] INFO: Action [user=alice]

Field starts a fluent chain for adding fields from a map

func (*Logger) FieldOne added in v0.1.7

func (l *Logger) FieldOne(key string, value any) *FieldBuilder

FieldOne logs a message at Error level with a stack trace and exits the program with exit code 1. It is thread-safe.

func (*Logger) Fields

func (l *Logger) Fields(pairs ...any) *FieldBuilder

Fields starts a fluent chain for adding fields using variadic key-value pairs. It creates a FieldBuilder to attach fields, handling non-string keys or uneven pairs by adding an error field. Thread-safe via the FieldBuilder's logger. Example:

logger.Fields("user", "alice").Info("Action") // Output: [app] INFO: Action [user=alice]

func (*Logger) GetContext added in v0.0.7

func (l *Logger) GetContext() map[string]interface{}

GetContext returns the logger's context map of persistent key-value fields. It is thread-safe using a read lock. Example:

logger := New("app").AddContext("user", "alice")
ctx := logger.GetContext() // Returns map[string]interface{}{"user": "alice"}

func (*Logger) GetHandler

func (l *Logger) GetHandler() lx.Handler

GetHandler returns the logger's current handler for customization or inspection. The returned handler should not be modified concurrently with logger operations. Example:

logger := New("app")
handler := logger.GetHandler() // Returns the current handler (e.g., TextHandler)

func (*Logger) GetLevel

func (l *Logger) GetLevel() lx.LevelType

GetLevel returns the minimum log level for the logger. It is thread-safe using a read lock. Example:

logger := New("app").Level(lx.LevelWarn)
if logger.GetLevel() == lx.LevelWarn {
    logger.Warn("Warning level set") // Output: [app] WARN: Warning level set
}

func (*Logger) GetPath added in v0.0.7

func (l *Logger) GetPath() string

GetPath returns the logger's current namespace path. It is thread-safe using a read lock. Example:

logger := New("app").Namespace("sub")
path := logger.GetPath() // Returns "app/sub"

func (*Logger) GetSeparator added in v0.0.7

func (l *Logger) GetSeparator() string

GetSeparator returns the logger's namespace separator (e.g., "/"). It is thread-safe using a read lock. Example:

logger := New("app").Separator(".")
sep := logger.GetSeparator() // Returns "."

func (*Logger) GetStyle added in v0.0.7

func (l *Logger) GetStyle() lx.StyleType

GetStyle returns the logger's namespace formatting style (FlatPath or NestedPath). It is thread-safe using a read lock. Example:

logger := New("app").Style(lx.NestedPath)
if logger.GetStyle() == lx.NestedPath {
    logger.Info("Nested style") // Output: [app]: INFO: Nested style
}

func (*Logger) Handler

func (l *Logger) Handler(handler lx.Handler) *Logger

Handler sets the handler for processing log entries, configuring the output destination and format (e.g., text, JSON). It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable().Handler(lh.NewTextHandler(os.Stdout))
logger.Info("Log") // Output: [app] INFO: Log

func (*Logger) If

func (l *Logger) If(condition bool) *Conditional

If creates a conditional logger that logs only if the condition is true. It returns a Conditional struct that wraps the logger, enabling conditional logging methods. This method is typically called on a Logger instance to start a conditional chain. Thread-safe via the underlying logger's mutex. Example:

logger := New("app").Enable()
logger.If(true).Info("Logged")   // Output: [app] INFO: Logged
logger.If(false).Info("Ignored") // No output

func (*Logger) IfErr added in v0.1.5

func (l *Logger) IfErr(err error) *Conditional

IfErr creates a conditional logger that logs only if the error is non-nil. It's designed for the common pattern of checking errors before logging. Example:

err := doSomething()
logger.IfErr(err).Error("Operation failed") // Only logs if err != nil

func (*Logger) IfErrAny added in v0.1.5

func (l *Logger) IfErrAny(errs ...error) *Conditional

IfErrAny creates a conditional logger that logs only if AT LEAST ONE error is non-nil. It evaluates a variadic list of errors, setting the condition to true if any is non-nil (logical OR). Useful when any error should trigger logging. Example:

err1 := validate(input)
err2 := authorize(user)
logger.IfErrAny(err1, err2).Error("Either check failed") // Logs if EITHER error exists

func (*Logger) IfErrOne added in v0.1.5

func (l *Logger) IfErrOne(errs ...error) *Conditional

IfErrOne creates a conditional logger that logs only if ALL errors are non-nil. It evaluates a variadic list of errors, setting the condition to true only if all are non-nil (logical AND). Useful when you need all errors to be present. Example:

err1 := validate(input)
err2 := authorize(user)
logger.IfErrOne(err1, err2).Error("Both checks failed") // Logs only if BOTH errors exist

func (*Logger) Indent

func (l *Logger) Indent(depth int) *Logger

Indent sets the indentation level for log messages, adding two spaces per level. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable().Indent(2)
logger.Info("Indented") // Output: [app] INFO:     Indented

func (*Logger) Info

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

Info logs a message at Info level, formatting it and delegating to the internal log method. It is thread-safe. Example:

logger := New("app").Enable().Style(lx.NestedPath)
logger.Info("Started") // Output: [app]: INFO: Started

func (*Logger) Infof added in v0.0.7

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

Infof logs a formatted message at Info level, delegating to Info. It is thread-safe. Example:

logger := New("app").Enable().Style(lx.NestedPath)
logger.Infof("Started %s", "now") // Output: [app]: INFO: Started now

func (*Logger) Inspect added in v0.1.3

func (l *Logger) Inspect(values ...interface{})

Inspect logs one or more values in a **developer-friendly, deeply introspective format** at Info level. It includes the caller file and line number, and reveals **all fields** â including:

  • Private (unexported) fields â prefixed with `(field)`
  • Embedded structs (inlined)
  • Pointers and nil values â shown as `*(field)` or `nil`
  • Full struct nesting and type information

This method uses `NewInspector` under the hood, which performs **full reflection-based traversal**. It is **not** meant for production logging or REST APIs â use `Output` for that.

Ideal for:

  • Debugging complex internal state
  • Inspecting structs with private fields
  • Understanding struct embedding and pointer behavior

func (*Logger) Labels added in v0.1.5

func (l *Logger) Labels(names ...string) *Logger

Labels temporarily attaches one or more label names to the logger for the next log entry. Labels are typically used for metrics, benchmarking, tracing, or categorizing logs in a structured way.

The labels are stored atomically and intended to be short-lived, applying only to the next log operation (or until overwritten by a subsequent call to Labels). Multiple labels can be provided as separate string arguments.

Example usage:

logger := New("app").Enable()

// Add labels for a specific operation
logger.Labels("load_users", "process_orders").Measure(func() {
    // ... perform work ...
}, func() {
    // ... optional callback ...
})

func (*Logger) Len

func (l *Logger) Len() int64

Len returns the total number of log entries sent to the handler, using atomic operations for thread safety. Example:

logger := New("app").Enable()
logger.Info("Test")
count := logger.Len() // Returns 1

func (*Logger) Level

func (l *Logger) Level(level lx.LevelType) *Logger

Level sets the minimum log level, ignoring messages below it. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable().Level(lx.LevelWarn)
logger.Info("Ignored") // Inactive output
logger.Warn("Logged") // Output: [app] WARN: Logged

func (*Logger) Line added in v0.0.6

func (l *Logger) Line(lines ...int) *Logger

Line adds vertical spacing (newlines) to the log output, defaulting to 1 if no arguments are provided. Multiple values are summed for total lines. It is thread-safe and returns the logger for chaining. Example:

logger := New("app").Enable()
logger.Line(2).Info("After 2 newlines") // Adds 2 blank lines before logging
logger.Line().Error("After 1 newline")  // Defaults to 1

func (*Logger) Mark added in v0.0.8

func (l *Logger) Mark(name ...string)

Mark logs the current file and line number where it's called, without any additional debug information. It's useful for tracing execution flow without the verbosity of Dbg. Example:

logger.Mark() // *MARK*: [file.go:123]

func (*Logger) Measure

func (l *Logger) Measure(fns ...func()) time.Duration

Measure executes one or more functions and logs the duration of each. It returns the total cumulative duration across all functions.

Each function in `fns` is run sequentially. If a function is `nil`, it is skipped.

Optional labels previously set via `Labels(...)` are applied to the corresponding function by position. If there are fewer labels than functions, missing labels are replaced with default names like "fn_0", "fn_1", etc. Labels are cleared after the call to prevent reuse.

Example usage:

logger := New("app").Enable()

// Optional: add labels for functions
logger.Labels("load_users", "process_orders")

total := logger.Measure(
    func() {
        // simulate work 1
        time.Sleep(100 * time.Millisecond)
    },
    func() {
        // simulate work 2
        time.Sleep(200 * time.Millisecond)
    },
    func() {
        // simulate work 3
        time.Sleep(50 * time.Millisecond)
    },
)

// Logs something like:
// [load_users] completed  duration=100ms
// [process_orders] completed  duration=200ms
// [fn_2] completed  duration=50ms

Returns the sum of durations of all executed functions.

func (*Logger) Namespace

func (l *Logger) Namespace(name string) *Logger

Namespace creates a child logger with a sub-namespace appended to the current path, inheriting the parentâ s configuration but with an independent context. It is thread-safe using a read lock. Example:

parent := New("parent").Enable()
child := parent.Namespace("child")
child.Info("Child log") // Output: [parent/child] INFO: Child log

func (*Logger) NamespaceDisable

func (l *Logger) NamespaceDisable(relativePath string) *Logger

NamespaceDisable disables logging for a namespace and its children, invalidating the namespace cache. It is thread-safe via lx.Namespaceâ s sync.Map and returns the logger for chaining. Example:

logger := New("parent").Enable().NamespaceDisable("parent/child")
logger.Namespace("child").Info("Ignored") // Inactive output

func (*Logger) NamespaceEnable

func (l *Logger) NamespaceEnable(relativePath string) *Logger

NamespaceEnable enables logging for a namespace and its children, invalidating the namespace cache. It is thread-safe via lx.Namespaceâ s sync.Map and returns the logger for chaining. Example:

logger := New("parent").Enable().NamespaceEnable("parent/child")
logger.Namespace("child").Info("Log") // Output: [parent/child] INFO: Log

func (*Logger) NamespaceEnabled

func (l *Logger) NamespaceEnabled(relativePath string) bool

NamespaceEnabled checks if a namespace is enabled, considering parent namespaces and caching results for performance. It is thread-safe using a read lock. Example:

logger := New("parent").Enable().NamespaceDisable("parent/child")
enabled := logger.NamespaceEnabled("parent/child") // false

func (*Logger) Output added in v0.1.1

func (l *Logger) Output(values ...interface{})

Output logs each value as pretty-printed JSON for REST debugging. Each value is logged on its own line with [file:line] and a blank line after the header. Ideal for inspecting outgoing/incoming REST payloads.

func (*Logger) Panic

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

Panic logs a message at Error level with a stack trace and triggers a panic. It is thread-safe. Example:

logger := New("app").Enable()
logger.Panic("Panic error") // Output: [app] ERROR: Panic error [stack=...], then panics

func (*Logger) Panicf added in v0.0.7

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

Panicf logs a formatted message at Error level with a stack trace and triggers a panic. It delegates to Panic and is thread-safe. Example:

logger := New("app").Enable()
logger.Panicf("Panic %s", "error") // Output: [app] ERROR: Panic error [stack=...], then panics

func (*Logger) Prefix

func (l *Logger) Prefix(prefix string) *Logger

Prefix sets a prefix prepended to all log messages. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable().Prefix("APP: ")
logger.Info("Started") // Output: [app] INFO: APP: Started

func (*Logger) Print

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

Print logs a message at Info level without format specifiers, minimizing allocations by concatenating arguments with spaces. It is thread-safe via the log method. Example:

logger := New("app").Enable()
logger.Print("message", "value") // Output: [app] INFO: message value

func (*Logger) Printf added in v0.0.7

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

Printf logs a formatted message at Info level, delegating to Print. It is thread-safe. Example:

logger := New("app").Enable()
logger.Printf("Message %s", "value") // Output: [app] INFO: Message value

func (*Logger) Println added in v0.0.8

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

Println logs a message at Info level without format specifiers, minimizing allocations by concatenating arguments with spaces. It is thread-safe via the log method. Example:

logger := New("app").Enable()
logger.Println("message", "value") // Output: [app] INFO: message value

func (*Logger) Remove

func (l *Logger) Remove(m *Middleware)

Remove removes middleware by the reference returned from Use, delegating to the Middlewareâ s Remove method for thread-safe removal. Example:

logger := New("app").Enable()
mw := logger.Use(someMiddleware)
logger.Remove(mw) // Removes middleware

func (*Logger) Resume added in v0.0.8

func (l *Logger) Resume() *Logger

Resume reactivates logging for the current logger after it has been suspended. It clears the suspend flag, allowing logs to be emitted if other conditions (e.g., level, namespace) are met. Thread-safe with a write lock. Returns the logger for method chaining. Example:

logger := New("app").Enable().Suspend()
logger.Resume()
logger.Info("Resumed") // Output: [app] INFO: Resumed

func (*Logger) Separator

func (l *Logger) Separator(separator string) *Logger

Separator sets the namespace separator for grouping namespaces and log entries (e.g., "/" or "."). It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Separator(".")
logger.Namespace("sub").Info("Log") // Output: [app.sub] INFO: Log

func (*Logger) Since added in v0.1.5

func (l *Logger) Since(startTime ...time.Time) *SinceBuilder

Since creates a timer that will log the duration when completed If startTime is provided, uses that as the start time; otherwise uses time.Now()

defer logger.Since().Info("request")        // Auto-start
logger.Since(start).Info("request")         // Manual timing
logger.Since().If(debug).Debug("timing")    // Conditional

func (*Logger) Stack

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

Stack logs messages at Error level with a stack trace for each provided argument. It is thread-safe and skips logging if Debug level is not enabled. Example:

logger := New("app").Enable()
logger.Stack("Critical error") // Output: [app] ERROR: Critical error [stack=...]

func (*Logger) StackSize

func (l *Logger) StackSize(size int) *Logger

StackSize sets the buffer size for stack trace capture in Stack, Fatal, and Panic methods. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("app").Enable().StackSize(65536)
logger.Stack("Error") // Captures up to 64KB stack trace

func (*Logger) Stackf added in v0.0.7

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

Stackf logs a formatted message at Error level with a stack trace, delegating to Stack. It is thread-safe. Example:

logger := New("app").Enable()
logger.Stackf("Critical %s", "error") // Output: [app] ERROR: Critical error [stack=...]

func (*Logger) Style

func (l *Logger) Style(style lx.StyleType) *Logger

Style sets the namespace formatting style (FlatPath or NestedPath). FlatPath uses parent/child, while NestedPath uses [parent]â [child]. It is thread-safe using a write lock and returns the logger for chaining. Example:

logger := New("parent/child").Enable().Style(lx.NestedPath)
logger.Info("Log") // Output: [parent]â   [child]: INFO: Log

func (*Logger) Suspend added in v0.0.8

func (l *Logger) Suspend() *Logger

Suspend temporarily deactivates logging for the current logger. It sets the suspend flag, suppressing all logs regardless of level or namespace until resumed. Thread-safe with a write lock. Returns the logger for method chaining. Example:

logger := New("app").Enable()
logger.Suspend()
logger.Info("Ignored") // Inactive output

func (*Logger) Suspended added in v0.0.8

func (l *Logger) Suspended() bool

Suspended returns whether the logger is currently suspended. It provides thread-safe read access to the suspend flag using a write lock. Example:

logger := New("app").Enable().Suspend()
if logger.Suspended() {
    fmt.Println("Logging is suspended") // Prints message
}

func (*Logger) Timestamped added in v0.0.9

func (l *Logger) Timestamped(enable bool, format ...string) *Logger

Timestamped enables or disables timestamp logging for the logger and optionally sets the timestamp format. It is thread-safe, using a write lock to ensure safe concurrent access. If the logger's handler supports the lx.Timestamper interface, the timestamp settings are applied. The method returns the logger instance to support method chaining. Parameters:

enable: Boolean to enable or disable timestamp logging
format: Optional string(s) to specify the timestamp format

func (*Logger) Toggle added in v0.1.4

func (l *Logger) Toggle(v bool) *Logger

Toggle enables or disables the logger based on the provided boolean value and returns the updated logger instance.

func (*Logger) Use

func (l *Logger) Use(fn lx.Handler) *Middleware

Use adds a middleware function to process log entries before they are handled, returning a Middleware handle for removal. Middleware returning a non-nil error stops the log. It is thread-safe using a write lock. Example:

logger := New("app").Enable()
mw := logger.Use(ll.FuncMiddleware(func(e *lx.Entry) error {
    if e.Level < lx.LevelWarn {
        return fmt.Errorf("level too low")
    }
    return nil
}))
logger.Info("Ignored") // Inactive output
mw.Remove()
logger.Info("Now logged") // Output: [app] INFO: Now logged

func (*Logger) Warn

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

Warn logs a message at Warn level, formatting it and delegating to the internal log method. It is thread-safe. Example:

logger := New("app").Enable()
logger.Warn("Warning") // Output: [app] WARN: Warning

func (*Logger) Warnf added in v0.0.7

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

Warnf logs a formatted message at Warn level, delegating to Warn. It is thread-safe. Example:

logger := New("app").Enable()
logger.Warnf("Warning %s", "issued") // Output: [app] WARN: Warning issued

type Middleware

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

Middleware represents a registered middleware and its operations in the logging pipeline. It holds an ID for identification, a reference to the parent logger, and the handler function that processes log entries. Middleware is used to transform or filter log entries before they are passed to the logger's output handler.

func Use added in v0.0.7

func Use(fn lx.Handler) *Middleware

Use adds a middleware function to process log entries before they are handled by the default logger. It registers the middleware and returns a Middleware handle for removal. Middleware returning a non-nil error stops the log. Thread-safe with write lock. Example:

mw := ll.Use(ll.FuncMiddleware(func(e *lx.Entry) error {
    if e.Level < lx.LevelWarn {
        return fmt.Errorf("level too low")
    }
    return nil
}))
ll.Info("Ignored") // Inactive output
mw.Remove()
ll.Info("Logged") // Output: [] INFO: Logged

func (*Middleware) Error

func (m *Middleware) Error(args ...any) *Middleware

Error logs an error message at the Error level if the middleware blocks a log entry. It uses the parent logger to emit the error and returns the middleware for chaining. This is useful for debugging or auditing when middleware rejects a log. Example:

mw := logger.Use(ll.Middle(func(e *lx.Entry) error {
    if e.Level < lx.LevelWarn {
        return fmt.Errorf("level too low")
    }
    return nil
}))
mw.Error("Rejected low-level log")

func (*Middleware) Errorf added in v0.0.7

func (m *Middleware) Errorf(format string, args ...any) *Middleware

Errorf logs an error message at the Error level if the middleware blocks a log entry. It uses the parent logger to emit the error and returns the middleware for chaining. This is useful for debugging or auditing when middleware rejects a log. Example:

mw := logger.Use(ll.Middle(func(e *lx.Entry) error {
    if e.Level < lx.LevelWarn {
        return fmt.Errorf("level too low")
    }
    return nil
}))
mw.Errorf("Rejected low-level log")

func (*Middleware) Logger

func (m *Middleware) Logger() *Logger

Logger returns the parent logger for optional chaining. This allows middleware to access the logger for additional operations, such as logging errors or creating derived loggers. It is useful for fluent API patterns. Example:

mw := logger.Use(authMiddleware)
mw.Logger().Info("Middleware registered")

func (*Middleware) Remove

func (m *Middleware) Remove()

Remove unregisters the middleware from the logger’s middleware chain. It safely removes the middleware by its ID, ensuring thread-safety with a mutex lock. If the middleware or logger is nil, it returns early to prevent panics. Example usage:

// Using a named middleware function
mw := logger.Use(authMiddleware)
defer mw.Remove()

// Using an inline middleware
mw = logger.Use(ll.Middle(func(e *lx.Entry) error {
    if e.Level < lx.LevelWarn {
        return fmt.Errorf("level too low")
    }
    return nil
}))
defer mw.Remove()

type Option

type Option func(*Logger)

Option defines a functional option for configuring a Logger.

func WithFatalExits added in v0.1.4

func WithFatalExits(enabled bool) Option

Functional options (can be passed to New() or applied later)

func WithFatalStack added in v0.1.4

func WithFatalStack(enabled bool) Option

func WithHandler

func WithHandler(handler lx.Handler) Option

WithHandler sets the handler for the logger as a functional option for configuring a new logger instance. Example:

logger := New("app", WithHandler(lh.NewJSONHandler(os.Stdout)))

func WithLevel

func WithLevel(level lx.LevelType) Option

WithLevel sets the minimum log level for the logger as a functional option for configuring a new logger instance. Example:

logger := New("app", WithLevel(lx.LevelWarn))

func WithStyle

func WithStyle(style lx.StyleType) Option

WithStyle sets the namespace formatting style for the logger as a functional option for configuring a new logger instance. Example:

logger := New("app", WithStyle(lx.NestedPath))

func WithTimestamped added in v0.0.9

func WithTimestamped(enable bool, format ...string) Option

WithTimestamped returns an Option that configures timestamp settings for the logger's existing handler. It enables or disables timestamp logging and optionally sets the timestamp format if the handler supports the lx.Timestamper interface. If no handler is set, the function has no effect. Parameters:

enable: Boolean to enable or disable timestamp logging
format: Optional string(s) to specify the timestamp format

type SinceBuilder added in v0.1.5

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

SinceBuilder provides a fluent API for logging timed operations It mirrors FieldBuilder exactly for field operations

func Since added in v0.1.5

func Since(start ...time.Time) *SinceBuilder

Since creates a timer that will log the duration when completed If startTime is provided, uses that as the start time; otherwise uses time.Now()

defer logger.Since().Info("request")        // Auto-start
logger.Since(start).Info("request")         // Manual timing
logger.Since().If(debug).Debug("timing")    // Conditional

func (*SinceBuilder) Debug added in v0.1.5

func (sb *SinceBuilder) Debug(msg string) time.Duration

Debug logs the duration at Debug level with message

func (*SinceBuilder) Elapsed added in v0.1.5

func (sb *SinceBuilder) Elapsed() time.Duration

Elapsed returns the current duration without logging

func (*SinceBuilder) Err added in v0.1.5

func (sb *SinceBuilder) Err(errs ...error) *SinceBuilder

Err adds one or more errors as a field EXACT match to FieldBuilder.Err()

func (*SinceBuilder) Error added in v0.1.5

func (sb *SinceBuilder) Error(msg string) time.Duration

Error logs the duration at Error level with message

func (*SinceBuilder) Field added in v0.1.5

func (sb *SinceBuilder) Field(fields map[string]interface{}) *SinceBuilder

Field adds fields from a map EXACT match to FieldBuilder.Field()

func (*SinceBuilder) Fields added in v0.1.5

func (sb *SinceBuilder) Fields(pairs ...any) *SinceBuilder

Fields adds key-value pairs as fields (variadic) EXACT match to FieldBuilder.Fields()

func (*SinceBuilder) If added in v0.1.5

func (sb *SinceBuilder) If(condition bool) *SinceBuilder

If adds a condition to this timer - only logs if condition is true

func (*SinceBuilder) IfAny added in v0.1.5

func (sb *SinceBuilder) IfAny(conditions ...bool) *SinceBuilder

IfAny logs if ANY condition is true

func (*SinceBuilder) IfErr added in v0.1.5

func (sb *SinceBuilder) IfErr(err error) *SinceBuilder

IfErr adds an error condition - only logs if err != nil

func (*SinceBuilder) IfOne added in v0.1.5

func (sb *SinceBuilder) IfOne(conditions ...bool) *SinceBuilder

IfOne logs if ALL conditions are true

func (*SinceBuilder) Info added in v0.1.5

func (sb *SinceBuilder) Info(msg string) time.Duration

Info logs the duration at Info level with message

func (*SinceBuilder) Log added in v0.1.5

func (sb *SinceBuilder) Log(msg string) time.Duration

Log is an alias for Info (for backward compatibility)

func (*SinceBuilder) Merge added in v0.1.5

func (sb *SinceBuilder) Merge(pairs ...any) *SinceBuilder

Merge adds additional key-value pairs to the fields EXACT match to FieldBuilder.Merge()

func (*SinceBuilder) Reset added in v0.1.5

func (sb *SinceBuilder) Reset(startTime ...time.Time) *SinceBuilder

Reset allows reusing the builder with a new start time Zero-allocation - keeps fields slice capacity

func (*SinceBuilder) Warn added in v0.1.5

func (sb *SinceBuilder) Warn(msg string) time.Duration

Warn logs the duration at Warn level with message

Directories

Path Synopsis
l3rd

Jump to

Keyboard shortcuts

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