olekukonko/ll
GitHub: olekukonko/ll
Stars: 1 | Forks: 0
# ll - A Modern Structured Logging Library for Go
## 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
// 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
- [GoDoc](https://pkg.go.dev/github.com/olekukonko/ll) - Full API documentation
- [Examples](_example/) - Runable example code
- [Benchmarks](tests/ll_bench_test.go) - Performance benchmarks
## License
MIT License - see [LICENSE](LICENSE) for details.
标签:EVTX分析