v0.1.0 Release

This commit is contained in:
2025-11-11 03:53:43 -05:00
parent ce6b178855
commit 1379455528
44 changed files with 1152 additions and 472 deletions

View File

@ -11,11 +11,11 @@ The `compat` package provides adapters that allow the lixenwraith/log logger to
### Features
- Full interface compatibility
- Preserves structured logging
- Configurable behavior
- Shared logger instances
- Optional field extraction
- Full interface compatibility
- Preserves structured logging
- Configurable behavior
- Shared logger instances
- Optional field extraction
## gnet Adapter
@ -188,6 +188,7 @@ logger := log.NewLogger()
cfg := log.DefaultConfig()
cfg.Level = log.LevelDebug
logger.ApplyConfig(cfg)
logger.Start()
defer logger.Shutdown()
// Create builder with existing logger
@ -195,7 +196,10 @@ builder := compat.NewBuilder().WithLogger(logger)
// Build adapters
gnetAdapter, _ := builder.BuildGnet()
if err != nil { return err }
fasthttpAdapter, _ := builder.BuildFastHTTP()
if err != nil { return err }
```
### Creating New Logger
@ -210,6 +214,7 @@ builder := compat.NewBuilder().WithConfig(cfg)
// Option 2: Default config (created on first build)
builder := compat.NewBuilder()
if err != nil { return err }
// Build adapters
gnetAdapter, _ := builder.BuildGnet()
@ -261,63 +266,6 @@ adapter.Infof("Connected to server")
// → {"msg": "Connected to server"}
```
## Example Configuration
### High-Performance Setup
```go
builder := compat.NewBuilder().
WithOptions(
"directory=/var/log/highperf",
"format=json",
"buffer_size=8192", // Large buffer
"flush_interval_ms=1000", // Batch writes
"enable_periodic_sync=false", // Reduce I/O
"heartbeat_level=1", // Monitor drops
)
```
### Development Setup
```go
builder := compat.NewBuilder().
WithOptions(
"directory=./log",
"format=txt", // Human-readable
"level=-4", // Debug level
"trace_depth=3", // Include traces
"enable_console=true", // Console output
"flush_interval_ms=50", // Quick feedback
)
```
### Container Setup
```go
builder := compat.NewBuilder().
WithOptions(
"enable_file=false", // No files
"enable_console=true", // Console only
"format=json", // For aggregators
"level=0", // Info and above
)
```
### Helper Functions
Configure servers with adapters:
```go
// Simple integration
logger := log.NewLogger()
builder := compat.NewBuilder().WithLogger(logger)
gnetAdapter, _ := builder.BuildGnet()
gnet.Run(handler, "tcp://127.0.0.1:9000",
gnet.WithLogger(gnetAdapter))
```
### Integration Examples
#### Microservice with Both Frameworks
@ -330,41 +278,40 @@ type Service struct {
}
func NewService() (*Service, error) {
builder := compat.NewBuilder().
WithOptions(
"directory=/var/log/service",
"format=json",
"heartbeat_level=2",
)
gnet, fasthttp, err := builder.Build()
if err != nil {
// Create and configure logger
logger := log.NewLogger()
cfg := log.DefaultConfig()
cfg.Directory = "/var/log/service"
cfg.Format = "json"
cfg.HeartbeatLevel = 2
if err := logger.ApplyConfig(cfg); err != nil {
return nil, err
}
return &Service{
gnetAdapter: gnet,
fasthttpAdapter: fasthttp,
logger: builder.GetLogger(),
}, nil
}
func (s *Service) StartTCPServer() error {
return gnet.Run(handler, "tcp://0.0.0.0:9000",
gnet.WithLogger(s.gnetAdapter),
)
}
func (s *Service) StartHTTPServer() error {
server := &fasthttp.Server{
Handler: s.handleHTTP,
Logger: s.fasthttpAdapter,
if err := logger.Start(); err != nil {
return nil, err
}
return server.ListenAndServe(":8080")
}
func (s *Service) Shutdown() error {
return s.logger.Shutdown(5 * time.Second)
// Create builder with the logger
builder := compat.NewBuilder().WithLogger(logger)
// Build adapters
gnetAdapter, err := builder.BuildGnet()
if err != nil {
logger.Shutdown()
return nil, err
}
fasthttpAdapter, err := builder.BuildFastHTTP()
if err != nil {
logger.Shutdown()
return nil, err
}
return &Service{
gnetAdapter: gnetAdapter,
fasthttpAdapter: fasthttpAdapter,
logger: logger,
}, nil
}
```
@ -405,5 +352,4 @@ func requestLogger(adapter *compat.FastHTTPAdapter) fasthttp.RequestHandler {
```
---
[← Heartbeat Monitoring](heartbeat-monitoring.md) | [← Back to README](../README.md)

View File

@ -388,5 +388,4 @@ func (s *Service) Shutdown() error {
```
---
[← Configuration Builder](config-builder.md) | [← Back to README](../README.md) | [Logging Guide →](logging-guide.md)

90
doc/builder.md Normal file
View File

@ -0,0 +1,90 @@
# Builder Pattern Guide
The Builder provides a fluent API for constructing and initializing logger instances with compile-time safety and deferred validation.
## Creating a Builder
NewBuilder creates a new builder for constructing a logger instance.
```go
func NewBuilder() *Builder
```
```go
builder := log.NewBuilder()
```
## Builder Methods
All builder methods return `*Builder` for chaining. Errors are accumulated and returned by `Build()`.
### Common Methods
| Method | Parameters | Description |
|--------|------------|-------------|
| `Level(level int64)` | `level`: Numeric log level | Sets log level (-4 to 8) |
| `LevelString(level string)` | `level`: Named level | Sets level by name ("debug", "info", etc.) |
| `Name(name string)` | `name`: Base filename | Sets log file base name |
| `Directory(dir string)` | `dir`: Path | Sets log directory |
| `Format(format string)` | `format`: Output format | Sets format ("txt", "json", "raw") |
| `Extension(ext string)` | `ext`: File extension | Sets log file extension |
| `BufferSize(size int64)` | `size`: Buffer size | Sets channel buffer size |
| `MaxSizeKB(size int64)` | `size`: Size in KB | Sets max file size in KB |
| `MaxSizeMB(size int64)` | `size`: Size in MB | Sets max file size in MB |
| `MaxTotalSizeKB(size int64)` | `size`: Size in KB | Sets max total log directory size in KB |
| `MaxTotalSizeMB(size int64)` | `size`: Size in MB | Sets max total log directory size in MB |
| `MinDiskFreeKB(size int64)` | `size`: Size in KB | Sets minimum required free disk space in KB |
| `MinDiskFreeMB(size int64)` | `size`: Size in MB | Sets minimum required free disk space in MB |
| `EnableConsole(enable bool)` | `enable`: Boolean | Enables console output |
| `EnableFile(enable bool)` | `enable`: Boolean | Enables file output |
| `ConsoleTarget(target string)` | `target`: "stdout"/"stderr" | Sets console output target |
| `ShowTimestamp(show bool)` | `show`: Boolean | Controls timestamp display |
| `ShowLevel(show bool)` | `show`: Boolean | Controls log level display |
| `TimestampFormat(format string)` | `format`: Time format | Sets timestamp format (Go time format) |
| `HeartbeatLevel(level int64)` | `level`: 0-3 | Sets monitoring level (0=off) |
| `HeartbeatIntervalS(interval int64)` | `interval`: Seconds | Sets heartbeat interval |
| `FlushIntervalMs(interval int64)` | `interval`: Milliseconds | Sets buffer flush interval |
| `TraceDepth(depth int64)` | `depth`: 0-10 | Sets default function trace depth |
| `DiskCheckIntervalMs(interval int64)` | `interval`: Milliseconds | Sets disk check interval |
| `EnableAdaptiveInterval(enable bool)` | `enable`: Boolean | Enables adaptive disk check intervals |
| `MinCheckIntervalMs(interval int64)` | `interval`: Milliseconds | Sets minimum adaptive interval |
| `MaxCheckIntervalMs(interval int64)` | `interval`: Milliseconds | Sets maximum adaptive interval |
| `EnablePeriodicSync(enable bool)` | `enable`: Boolean | Enables periodic disk sync |
| `RetentionPeriodHrs(hours float64)` | `hours`: Hours | Sets log retention period |
| `RetentionCheckMins(mins float64)` | `mins`: Minutes | Sets retention check interval |
| `InternalErrorsToStderr(enable bool)` | `enable`: Boolean | Send internal errors to stderr |
## Build
```go
func (b *Builder) Build() (*Logger, error)
```
Creates and initializes a logger instance with the configured settings.
Returns accumulated errors if any builder operations failed.
```go
logger, err := builder.Build()
if err != nil {
// Handle validation or initialization errors
}
defer logger.Shutdown()
```
## Usage Pattern
```go
// Single-step logger creation and initialization
logger, err := log.NewBuilder().
Directory("/var/log/app").
Format("json").
LevelString("debug").
Build()
if err != nil { return err }
defer logger.Shutdown()
// Start the logger
err = logger.Start()
if err != nil { return err }
logger.Info("Application started")
```
---
[← Configuration](configuration.md) | [← Back to README](../README.md) | [API Reference →](api-reference.md)

View File

@ -1,71 +0,0 @@
# Builder Pattern Guide
The ConfigBuilder provides a fluent API for constructing logger configurations with compile-time safety and deferred validation.
## Creating a Builder
NewConfigBuilder creates a new configuration builder initialized with default values.
```go
func NewConfigBuilder() *ConfigBuilder
```
```go
builder := log.NewConfigBuilder()
```
## Builder Methods
All builder methods return `*ConfigBuilder` for chaining. Errors are accumulated and returned by `Build()`.
### Common Methods
| Method | Parameters | Description |
|-------------------------------|----------------------------|--------------------------------------------|
| `Level(level int64)` | `level`: Numeric log level | Sets log level (-4 to 8) |
| `LevelString(level string)` | `level`: Named level | Sets level by name ("debug", "info", etc.) |
| `Directory(dir string)` | `dir`: Path | Sets log directory |
| `Format(format string)` | `format`: Output format | Sets format ("txt", "json", "raw") |
| `BufferSize(size int64)` | `size`: Buffer size | Sets channel buffer size |
| `MaxSizeKB(size int64)` | `size`: Size in MB | Sets max file size |
| `EnableConsole(enable bool)` | `enable`: Boolean | Enables console output |
| `EnableFile(enable bool)` | `enable`: Boolean | Enable file output |
| `HeartbeatLevel(level int64)` | `level`: 0-3 | Sets monitoring level |
## Build
```go
func (b *ConfigBuilder) Build() (*Config, error)
```
Validates builder configuration and returns logger config.
Returns accumulated errors if any builder operations failed.
```go
cfg, err := builder.Build()
if err != nil {
// Handle validation or conversion errors
}
```
## Usage pattern
```go
logger := log.NewLogger()
cfg, err := log.NewConfigBuilder().
Directory("/var/log/app").
Format("json").
LevelString("debug").
Build()
if err != nil {
return err
}
err = logger.ApplyConfig(cfg)
```
---
[← Configuration](configuration.md) | [← Back to README](../README.md) | [API Reference →](api-reference.md)

View File

@ -102,5 +102,4 @@ logger.Info("info txt log record written to /var/log/myapp.txt")
| `heartbeat_interval_s` | `int64` | Heartbeat interval (seconds) | `60` |
---
[← Getting Started](getting-started.md) | [← Back to README](../README.md) | [Configuration Builder →](config-builder.md)

View File

@ -24,18 +24,32 @@ The logger follows an instance-based design. You create logger instances and cal
package main
import (
"fmt"
"github.com/lixenwraith/log"
)
func main() {
// Create a new logger instance with default configuration
// Writes to both console (stdout) and file ./log/log.log
logger := log.NewLogger()
// Create a new logger instance with default configuration
logger := log.NewLogger()
// Apply configuration
err := logger.ApplyConfigString("directory=/var/log/myapp")
if err != nil {
panic(fmt.Errorf("failed to apply logger config: %w", err))
}
defer logger.Shutdown()
// Start the logger (required before logging)
if err = logger.Start(); err != nil {
panic(fmt.Errorf("failed to start logger: %w", err))
}
// Start logging!
logger.Info("Application started")
logger.Debug("Debug mode enabled", "verbose", true)
logger.Warn("Warning message", "threshold", 0.95)
logger.Error("Error occurred", "code", 500)
}
```
@ -64,6 +78,8 @@ func NewService() (*Service, error) {
); err != nil {
return nil, fmt.Errorf("logger init failed: %w", err)
}
logger.Start()
return &Service{
logger: logger,
@ -101,5 +117,4 @@ func loggingMiddleware(logger *log.Logger) func(http.Handler) http.Handler {
```
---
[← Back to README](../README.md) | [Configuration →](configuration.md)

View File

@ -165,5 +165,4 @@ With `format=txt`, heartbeats are human-readable:
```
---
[← Disk Management](disk-management.md) | [← Back to README](../README.md) | [Compatibility Adapters →](compatibility-adapters.md)

View File

@ -0,0 +1,513 @@
# lixenwraith/log LLM Usage Guide
This guide details the `lixenwraith/log` package, a high-performance, buffered, rotating file logger for Go with built-in disk management, operational monitoring, and framework compatibility adapters.
## Quick Start: Recommended Usage
The recommended pattern uses the **Builder** with type-safe configuration. This provides compile-time safety and eliminates runtime errors.
```go
package main
import (
"fmt"
"time"
"github.com/lixenwraith/log"
)
func main() {
// 1. Use the builder pattern for configuration (recommended).
logger, err := log.NewBuilder().
Directory("/var/log/myapp"). // Log directory path
LevelString("info"). // Minimum log level
Format("json"). // Output format
BufferSize(2048). // Channel buffer size
MaxSizeMB(10). // Max file size before rotation
HeartbeatLevel(1). // Enable operational monitoring
HeartbeatIntervalS(300). // Every 5 minutes
Build() // Build the logger instance
if err != nil {
panic(fmt.Errorf("logger build failed: %w", err))
}
defer logger.Shutdown(5 * time.Second)
// 2. Start the logger (required before logging).
if err := logger.Start(); err != nil {
panic(fmt.Errorf("logger start failed: %w", err))
}
// 3. Begin logging with structured key-value pairs.
logger.Info("Application started", "version", "1.0.0", "pid", os.Getpid())
logger.Debug("Debug information", "user_id", 12345)
logger.Warn("High memory usage", "used_mb", 1800, "limit_mb", 2048)
logger.Error("Connection failed", "host", "db.example.com", "error", err)
}
```
## Alternative Initialization Methods
### Using ApplyConfigString (Quick Configuration)
```go
logger := log.NewLogger()
err := logger.ApplyConfigString(
"directory=/var/log/app",
"format=json",
"level=debug",
"max_size_kb=5000",
)
if err != nil {
return fmt.Errorf("config failed: %w", err)
}
defer logger.Shutdown()
logger.Start()
```
### Using ApplyConfig (Full Control)
```go
logger := log.NewLogger()
cfg := log.DefaultConfig()
cfg.Directory = "/var/log/app"
cfg.Format = "json"
cfg.Level = log.LevelDebug
cfg.MaxSizeKB = 5000
cfg.HeartbeatLevel = 2 // Process + disk stats
err := logger.ApplyConfig(cfg)
if err != nil {
return fmt.Errorf("config failed: %w", err)
}
defer logger.Shutdown()
logger.Start()
```
## Builder Pattern
The `Builder` is the primary way to construct a `Logger` instance with compile-time safety.
```go
// NewBuilder creates a new logger builder.
func NewBuilder() *Builder
// Build finalizes configuration and creates the logger.
func (b *Builder) Build() (*Logger, error)
```
### Builder Methods
All builder methods return `*Builder` for chaining.
**Basic Configuration:**
- `Level(level int64)`: Set numeric log level (-4 to 8)
- `LevelString(level string)`: Set level by name ("debug", "info", "warn", "error")
- `Directory(dir string)`: Set log directory path
- `Name(name string)`: Set base filename (default: "log")
- `Format(format string)`: Set format ("txt", "json", "raw")
- `Extension(ext string)`: Set file extension (default: ".log")
**Buffer and Performance:**
- `BufferSize(size int64)`: Channel buffer size (default: 1024)
- `FlushIntervalMs(ms int64)`: Buffer flush interval (default: 100ms)
- `TraceDepth(depth int64)`: Default function trace depth 0-10 (default: 0)
**File Management:**
- `MaxSizeKB(size int64)` / `MaxSizeMB(size int64)`: Max file size before rotation
- `MaxTotalSizeKB(size int64)` / `MaxTotalSizeMB(size int64)`: Max total directory size
- `MinDiskFreeKB(size int64)` / `MinDiskFreeMB(size int64)`: Required free disk space
- `RetentionPeriodHrs(hours float64)`: Hours to keep logs (0=disabled)
- `RetentionCheckMins(mins float64)`: Retention check interval
**Output Control:**
- `EnableConsole(enable bool)`: Enable stdout/stderr output
- `EnableFile(enable bool)`: Enable file output
- `ConsoleTarget(target string)`: "stdout", "stderr", or "split"
**Formatting:**
- `ShowTimestamp(show bool)`: Add timestamps
- `ShowLevel(show bool)`: Add level labels
- `TimestampFormat(format string)`: Go time format string
**Monitoring:**
- `HeartbeatLevel(level int64)`: 0=off, 1=proc, 2=+disk, 3=+sys
- `HeartbeatIntervalS(seconds int64)`: Heartbeat interval
**Disk Monitoring:**
- `DiskCheckIntervalMs(ms int64)`: Base disk check interval
- `EnableAdaptiveInterval(enable bool)`: Adjust interval based on load
- `MinCheckIntervalMs(ms int64)`: Minimum adaptive interval
- `MaxCheckIntervalMs(ms int64)`: Maximum adaptive interval
- `EnablePeriodicSync(enable bool)`: Periodic disk sync
**Error Handling:**
- `InternalErrorsToStderr(enable bool)`: Send internal errors to stderr
## API Reference
### Logger Creation
```go
func NewLogger() *Logger
```
Creates a new uninitialized logger with default configuration.
### Configuration Methods
```go
func (l *Logger) ApplyConfig(cfg *Config) error
func (l *Logger) ApplyConfigString(overrides ...string) error
func (l *Logger) GetConfig() *Config
```
### Lifecycle Methods
```go
func (l *Logger) Start() error // Start log processing
func (l *Logger) Stop(timeout ...time.Duration) error // Stop (can restart)
func (l *Logger) Shutdown(timeout ...time.Duration) error // Terminal shutdown
func (l *Logger) Flush(timeout time.Duration) error // Force buffer flush
```
### Standard Logging Methods
```go
func (l *Logger) Debug(args ...any) // Level -4
func (l *Logger) Info(args ...any) // Level 0
func (l *Logger) Warn(args ...any) // Level 4
func (l *Logger) Error(args ...any) // Level 8
```
### Trace Logging Methods
Include function call traces (depth 0-10):
```go
func (l *Logger) DebugTrace(depth int, args ...any)
func (l *Logger) InfoTrace(depth int, args ...any)
func (l *Logger) WarnTrace(depth int, args ...any)
func (l *Logger) ErrorTrace(depth int, args ...any)
```
### Special Logging Methods
```go
func (l *Logger) LogStructured(level int64, message string, fields map[string]any)
func (l *Logger) Write(args ...any) // Raw output, no formatting
func (l *Logger) Log(args ...any) // Timestamp only, no level
func (l *Logger) Message(args ...any) // No timestamp or level
func (l *Logger) LogTrace(depth int, args ...any) // Timestamp + trace, no level
```
## Constants and Levels
### Standard Log Levels
```go
const (
LevelDebug int64 = -4 // Verbose debugging
LevelInfo int64 = 0 // Informational messages
LevelWarn int64 = 4 // Warning conditions
LevelError int64 = 8 // Error conditions
)
```
### Heartbeat Monitoring Levels
Special levels that bypass filtering:
```go
const (
LevelProc int64 = 12 // Process statistics
LevelDisk int64 = 16 // Disk usage statistics
LevelSys int64 = 20 // System statistics
)
```
### Level Helper
```go
func Level(levelStr string) (int64, error)
```
Converts level string to numeric constant: "debug", "info", "warn", "error", "proc", "disk", "sys".
## Configuration Structure
```go
type Config struct {
// Output Settings
EnableConsole bool // Enable stdout/stderr output
ConsoleTarget string // "stdout", "stderr", or "split"
EnableFile bool // Enable file output
// Basic Settings
Level int64 // Minimum log level
Name string // Base filename (default: "log")
Directory string // Log directory path
Format string // "txt", "json", or "raw"
Extension string // File extension (default: ".log")
// Formatting
ShowTimestamp bool // Add timestamps
ShowLevel bool // Add level labels
TimestampFormat string // Go time format
// Buffer and Performance
BufferSize int64 // Channel buffer size
FlushIntervalMs int64 // Buffer flush interval
TraceDepth int64 // Default trace depth (0-10)
// File Management
MaxSizeKB int64 // Max file size (KB)
MaxTotalSizeKB int64 // Max total directory size (KB)
MinDiskFreeKB int64 // Required free disk space (KB)
RetentionPeriodHrs float64 // Hours to keep logs
RetentionCheckMins float64 // Retention check interval
// Disk Monitoring
DiskCheckIntervalMs int64 // Base check interval
EnableAdaptiveInterval bool // Adjust based on load
MinCheckIntervalMs int64 // Minimum interval
MaxCheckIntervalMs int64 // Maximum interval
EnablePeriodicSync bool // Periodic disk sync
// Heartbeat
HeartbeatLevel int64 // 0=off, 1=proc, 2=+disk, 3=+sys
HeartbeatIntervalS int64 // Heartbeat interval
// Error Handling
InternalErrorsToStderr bool // Write internal errors to stderr
}
```
### Default Configuration
```go
func DefaultConfig() *Config
```
Returns default configuration with sensible values:
- Console output enabled to stdout
- File output enabled
- Info level logging
- 1MB max file size
- 5MB max total size
- 100ms flush interval
## Output Formats
### Text Format (default)
Human-readable format with optional timestamps and levels:
```
2024-01-15T10:30:00.123456Z INFO Application started version="1.0.0" pid=1234
2024-01-15T10:30:01.456789Z ERROR Connection failed host="db.example.com" error="timeout"
```
### JSON Format
Structured JSON output for log aggregation:
```json
{"time":"2024-01-15T10:30:00.123456Z","level":"INFO","fields":["Application started","version","1.0.0","pid",1234]}
{"time":"2024-01-15T10:30:01.456789Z","level":"ERROR","fields":["Connection failed","host","db.example.com","error","timeout"]}
```
### Raw Format
Minimal format without timestamps or levels:
```
Application started version="1.0.0" pid=1234
Connection failed host="db.example.com" error="timeout"
```
## Framework Adapters (compat package)
### gnet v2 Adapter
```go
import (
"github.com/lixenwraith/log"
"github.com/lixenwraith/log/compat"
"github.com/panjf2000/gnet/v2"
)
// Create adapter
adapter := compat.NewGnetAdapter(logger)
// Use with gnet
gnet.Run(handler, "tcp://127.0.0.1:9000", gnet.WithLogger(adapter))
```
### fasthttp Adapter
```go
import (
"github.com/lixenwraith/log"
"github.com/lixenwraith/log/compat"
"github.com/valyala/fasthttp"
)
// Create adapter
adapter := compat.NewFastHTTPAdapter(logger)
// Use with fasthttp
server := &fasthttp.Server{
Handler: requestHandler,
Logger: adapter,
}
```
### Adapter Builder Pattern
```go
// Share logger across adapters
builder := compat.NewBuilder().WithLogger(logger)
gnetAdapter, err := builder.BuildGnet()
fasthttpAdapter, err := builder.BuildFastHTTP()
// Or create structured adapters
structuredGnet, err := builder.BuildStructuredGnet()
```
## Common Patterns
### Service with Shared Logger
```go
type Service struct {
logger *log.Logger
}
func NewService() (*Service, error) {
logger, err := log.NewBuilder().
Directory("/var/log/service").
Format("json").
BufferSize(2048).
HeartbeatLevel(2).
Build()
if err != nil {
return nil, err
}
if err := logger.Start(); err != nil {
return nil, err
}
return &Service{logger: logger}, nil
}
func (s *Service) Close() error {
return s.logger.Shutdown(5 * time.Second)
}
func (s *Service) ProcessRequest(id string) {
s.logger.Info("Processing", "request_id", id)
// ... process ...
s.logger.Info("Completed", "request_id", id)
}
```
### HTTP Middleware
```go
func loggingMiddleware(logger *log.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
wrapped := &responseWriter{ResponseWriter: w, status: 200}
next.ServeHTTP(wrapped, r)
logger.Info("HTTP request",
"method", r.Method,
"path", r.URL.Path,
"status", wrapped.status,
"duration_ms", time.Since(start).Milliseconds(),
"remote_addr", r.RemoteAddr,
)
})
}
}
```
### Hot Reconfiguration
```go
// Initial configuration
logger.ApplyConfigString("level=info")
// Debugging reconfiguration
logger.ApplyConfigString(
"level=debug",
"heartbeat_level=3",
"heartbeat_interval_s=60",
)
// Revert to normal
logger.ApplyConfigString(
"level=info",
"heartbeat_level=1",
"heartbeat_interval_s=300",
)
```
### Graceful Shutdown
```go
// Setup signal handling
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
// Shutdown sequence
<-sigChan
logger.Info("Shutdown initiated")
// Flush pending logs with timeout
if err := logger.Shutdown(5 * time.Second); err != nil {
fmt.Fprintf(os.Stderr, "Logger shutdown error: %v\n", err)
}
```
## Thread Safety
All public methods are thread-safe. The logger uses:
- Atomic operations for state management
- Channels for log record passing
- No locks in the critical logging path
## Performance Characteristics
- **Zero-allocation logging path**: Uses pre-allocated buffers
- **Lock-free async design**: Non-blocking sends to buffered channel
- **Adaptive disk checks**: Adjusts I/O based on load
- **Batch writes**: Flushes buffer periodically, not per-record
- **Drop tracking**: Counts dropped logs when buffer full
## Migration Guide
### From standard log package
```go
// Before: standard log
log.Printf("User login: id=%d name=%s", id, name)
// After: lixenwraith/log
logger.Info("User login", "id", id, "name", name)
```
### From other structured loggers
```go
// Before: zap
zap.Info("User login",
zap.Int("id", id),
zap.String("name", name))
// After: lixenwraith/log
logger.Info("User login", "id", id, "name", name)
```
## Best Practices
1. **Use Builder pattern** for configuration - compile-time safety
2. **Use structured logging** - consistent key-value pairs
3. **Use appropriate levels** - filter noise in logs

View File

@ -131,11 +131,11 @@ func logWithContext(ctx context.Context, logger *log.Logger, level string, msg s
Default format for development and debugging:
```
2024-01-15T10:30:45.123456789Z INFO User login user_id=42 email="user@example.com" ip="192.168.1.100"
2024-01-15T10:30:45.123456789Z INFO User login user_id=42 email=user@example.com ip=192.168.1.100
2024-01-15T10:30:45.234567890Z WARN Rate limit approaching user_id=42 requests=95 limit=100
```
Note: The txt format does not add quotes around string values containing spaces. This ensures predictability for simple, space-delimited parsing tools. For logs where maintaining the integrity of such values is critical, `json` format is recommended.
Note: The txt format adds quotes around non-string values (errors, stringers, complex types) when they contain spaces. Plain string arguments are not quoted. Control characters in strings are sanitized to hex representation. For logs requiring exact preservation of all values, `json` format is recommended.
Configuration:
```go
@ -336,5 +336,4 @@ func (m *MetricsCollector) logMetrics() {
```
---
[← API Reference](api-reference.md) | [← Back to README](../README.md) | [Disk Management →](disk-management.md)

View File

@ -10,13 +10,13 @@ Log files are automatically rotated when they reach the configured size limit:
```go
logger.ApplyConfigString(
"max_size_mb=100", // Rotate at 100MB
"max_size_kb=100", // Rotate at 100MB
)
```
### Rotation Behavior
1. **Size Check**: Before each write, the logger checks if the file would exceed `max_size_mb`
1. **Size Check**: Before each write, the logger checks if the file would exceed `max_size_kb`
2. **New File Creation**: Creates a new file with timestamp: `appname_240115_103045_123456789.log`
3. **Seamless Transition**: No logs are lost during rotation
4. **Old File Closure**: Previous file is properly closed and synced
@ -44,8 +44,8 @@ The logger enforces two types of space limits:
```go
logger.ApplyConfigString(
"max_total_size_mb=1000", // Total log directory size
"min_disk_free_mb=5000", // Minimum free disk space
"max_total_size_kb=1000", // Total log directory size
"min_disk_free_kb=5000", // Minimum free disk space
)
```
@ -62,23 +62,23 @@ When limits are exceeded, the logger:
```go
// Conservative: Strict limits
logger.ApplyConfigString(
"max_size_mb=50", // 50MB files
"max_total_size_mb=500", // 500MB total
"min_disk_free_mb=1000", // 1GB free required
"max_size_kb=500", // 500KB files
"max_total_size_kb=5000", // 5MB total
"min_disk_free_kb=1000000", // 1GB free required
)
// Generous: Large files, external archival
logger.ApplyConfigString(
"max_size_mb=1000", // 1GB files
"max_total_size_mb=0", // No total limit
"min_disk_free_mb=100", // 100MB free required
"max_size_kb=100000", // 100MB files
"max_total_size_kb=0", // No total limit
"min_disk_free_kb=10000", // 10MB free required
)
// Balanced: Production defaults
logger.ApplyConfigString(
"max_size_mb=100", // 100MB files
"max_total_size_mb=5000", // 5GB total
"min_disk_free_mb=500", // 500MB free required
"max_size_kb=100000", // 100MB files
"max_total_size_kb=5000000", // 5GB total
"min_disk_free_kb=500000", // 500MB free required
)
```
@ -102,21 +102,21 @@ logger.ApplyConfigString(
logger.ApplyConfigString(
"retention_period_hrs=720", // 30 days
"retention_check_mins=60", // Check hourly
"max_size_mb=1000", // 1GB daily files
"max_size_kb=1000000", // 1GB daily files
)
// High-frequency logs, keep 24 hours
logger.ApplyConfigString(
"retention_period_hrs=24", // 1 day
"retention_check_mins=15", // Check every 15 min
"max_size_mb=100", // 100MB files
"max_size_kb=100000", // 100MB files
)
// Compliance: Keep 90 days
logger.ApplyConfigString(
"retention_period_hrs=2160", // 90 days
"retention_check_mins=360", // Check every 6 hours
"max_total_size_mb=100000", // 100GB total
"max_total_size_kb=100000000", // 100GB total
)
```
@ -161,7 +161,7 @@ logger.ApplyConfigString(
Output:
```
2024-01-15T10:30:00Z DISK type="disk" sequence=1 rotated_files=5 deleted_files=2 total_log_size_mb="487.32" log_file_count=8 current_file_size_mb="23.45" disk_status_ok=true disk_free_mb="5234.67"
2024-01-15T10:30:00Z DISK type="disk" sequence=1 rotated_files=5 deleted_files=2 total_log_size_kb="487.32" log_file_count=8 current_file_size_kb="23.45" disk_status_ok=true disk_free_kb="5234.67"
```
## Manual Recovery
@ -183,5 +183,4 @@ df -h /var/log
```
---
[← Logging Guide](logging-guide.md) | [← Back to README](../README.md) | [Heartbeat Monitoring →](heartbeat-monitoring.md)