Test / test (push) Canceled after 0s
Test / fuzz (./compat, FuzzParseFormat) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatJSON) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatTextPolicy) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSanitize) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSerializerJSON) (push) Canceled after 0s
436 lines
11 KiB
Markdown
436 lines
11 KiB
Markdown
# API Reference
|
|
|
|
Complete API documentation for the lixenwraith/log package.
|
|
|
|
## Logger Creation
|
|
|
|
### NewLogger
|
|
|
|
```go
|
|
func NewLogger() *Logger
|
|
```
|
|
|
|
Creates a new, uninitialized logger instance with default configuration parameters registered internally.
|
|
|
|
**Example:**
|
|
```go
|
|
logger := log.NewLogger()
|
|
```
|
|
|
|
## Initialization Methods
|
|
|
|
### ApplyConfig
|
|
|
|
```go
|
|
func (l *Logger) ApplyConfig(cfg *Config) error
|
|
```
|
|
|
|
Applies a validated configuration to the logger. This is the recommended method for applications that need full control over configuration.
|
|
|
|
**Parameters:**
|
|
- `cfg`: A `*Config` struct with desired settings
|
|
|
|
**Returns:**
|
|
- `error`: Configuration error if invalid
|
|
|
|
**Example:**
|
|
```go
|
|
logger := log.NewLogger()
|
|
|
|
cfg := log.DefaultConfig()
|
|
cfg.Level = log.LevelDebug
|
|
cfg.Directory = "/var/log/app"
|
|
err := logger.ApplyConfig(cfg)
|
|
```
|
|
|
|
### ApplyConfigString
|
|
|
|
```go
|
|
func (l *Logger) ApplyConfigString(overrides ...string) error
|
|
```
|
|
|
|
Applies key-value overrides to the logger. Convenient interface for minor changes.
|
|
|
|
**Parameters:**
|
|
- `overrides`: Variadic overrides in the format "key=value"
|
|
|
|
**Returns:**
|
|
- `error`: Configuration error if invalid
|
|
|
|
**Example:**
|
|
```go
|
|
logger := log.NewLogger()
|
|
|
|
err := logger.ApplyConfigString("directory=/var/log/app", "name=app")
|
|
```
|
|
|
|
## Logging Methods
|
|
|
|
Logging methods accept variadic arguments. Ordinary methods preserve them as positional values (a JSON array in JSON mode). Use `LogContext` with `FlagKV` for a keyed object, or `LogStructured` for a message and nested fields.
|
|
|
|
### Debug
|
|
|
|
```go
|
|
func (l *Logger) Debug(args ...any)
|
|
```
|
|
|
|
Logs a message at debug level (-4).
|
|
|
|
**Example:**
|
|
```go
|
|
logger.Debug("Processing started", "items", 100, "mode", "batch")
|
|
```
|
|
|
|
### Info
|
|
|
|
```go
|
|
func (l *Logger) Info(args ...any)
|
|
```
|
|
|
|
Logs a message at info level (0).
|
|
|
|
**Example:**
|
|
```go
|
|
logger.Info("Server started", "port", 8080, "tls", true)
|
|
```
|
|
|
|
### Warn
|
|
|
|
```go
|
|
func (l *Logger) Warn(args ...any)
|
|
```
|
|
|
|
Logs a message at warning level (4).
|
|
|
|
**Example:**
|
|
```go
|
|
logger.Warn("High memory usage", "used_mb", 1800, "limit_mb", 2048)
|
|
```
|
|
|
|
### Error
|
|
|
|
```go
|
|
func (l *Logger) Error(args ...any)
|
|
```
|
|
|
|
Logs a message at error level (8).
|
|
|
|
**Example:**
|
|
```go
|
|
logger.Error("Database connection failed", "host", "db.example.com", "error", err)
|
|
```
|
|
|
|
### LogStructured
|
|
|
|
```go
|
|
func (l *Logger) LogStructured(level int64, message string, fields map[string]any)
|
|
```
|
|
|
|
Logs a message with structured fields as proper JSON (when format="json").
|
|
|
|
**Example:**
|
|
```go
|
|
logger.LogStructured(log.LevelInfo, "User action", map[string]any{
|
|
"user_id": 42,
|
|
"action": "login",
|
|
"metadata": map[string]any{"ip": "192.168.1.1"},
|
|
})
|
|
```
|
|
|
|
### Write
|
|
|
|
```go
|
|
func (l *Logger) Write(args ...any)
|
|
```
|
|
|
|
Outputs raw, unformatted data regardless of configured format. Bypasses all formatting (timestamps, levels, JSON structure) and writes args as space-separated strings without a trailing newline.
|
|
|
|
**Example:**
|
|
```go
|
|
logger.Write("METRIC", "cpu_usage", 85.5, "timestamp", 1234567890)
|
|
// Output: METRIC cpu_usage 85.5 timestamp 1234567890
|
|
```
|
|
|
|
## Trace Logging Methods
|
|
|
|
These methods include function call traces in the log output.
|
|
|
|
### DebugTrace
|
|
|
|
```go
|
|
func (l *Logger) DebugTrace(depth int, args ...any)
|
|
```
|
|
|
|
Logs at debug level with function call trace.
|
|
|
|
**Parameters:**
|
|
- `depth`: Number of stack frames to include (0-10)
|
|
- `args`: Log message and fields
|
|
|
|
**Example:**
|
|
```go
|
|
logger.DebugTrace(3, "Entering critical section", "mutex", "db_lock")
|
|
```
|
|
|
|
### InfoTrace
|
|
|
|
```go
|
|
func (l *Logger) InfoTrace(depth int, args ...any)
|
|
```
|
|
|
|
Logs at info level with function call trace.
|
|
|
|
### WarnTrace
|
|
|
|
```go
|
|
func (l *Logger) WarnTrace(depth int, args ...any)
|
|
```
|
|
|
|
Logs at warning level with function call trace.
|
|
|
|
### ErrorTrace
|
|
|
|
```go
|
|
func (l *Logger) ErrorTrace(depth int, args ...any)
|
|
```
|
|
|
|
Logs at error level with function call trace.
|
|
|
|
## Special Logging Methods
|
|
|
|
### Log
|
|
|
|
```go
|
|
func (l *Logger) Log(args ...any)
|
|
```
|
|
|
|
Logs with timestamp only, no level information (uses Info level internally).
|
|
|
|
**Example:**
|
|
```go
|
|
logger.Log("Checkpoint reached", "step", 5)
|
|
```
|
|
|
|
### Message
|
|
|
|
```go
|
|
func (l *Logger) Message(args ...any)
|
|
```
|
|
|
|
Logs using the configured format and sanitization, without timestamp or level.
|
|
|
|
**Example:**
|
|
```go
|
|
logger.Message("Raw output for special formatting")
|
|
```
|
|
|
|
### LogTrace
|
|
|
|
```go
|
|
func (l *Logger) LogTrace(depth int, args ...any)
|
|
```
|
|
|
|
Logs with timestamp and trace, but no level information.
|
|
|
|
**Example:**
|
|
```go
|
|
logger.LogTrace(2, "Function boundary", "entering", true)
|
|
```
|
|
|
|
## Control Methods
|
|
|
|
### Start and Stop
|
|
|
|
`Start() error` begins processing after configuration; repeated starts are no-ops. `Stop(timeout ...time.Duration) error` closes emission, drains accepted records, and joins the processor. A timeout does not permit a second processor to start while the first still owns resources. Retry `Stop` or `Shutdown` to wait again. Lifecycle timeouts bound the processor join after acquiring the lifecycle lock.
|
|
|
|
### Context and fast filtering
|
|
|
|
`Enabled(level int64) bool` checks the current emit gate before constructing expensive arguments. `SetLevel(level int64)` updates the threshold without restarting. `SetContextKeys(tag string, vals ...string)` names a tag and up to three counters; `LogContext(ctx Context, flags, level, depth int64, args ...any)` stamps them onto a record. `Flags()` returns display defaults suitable for combining with `FlagKV`.
|
|
|
|
### Shutdown
|
|
|
|
```go
|
|
func (l *Logger) Shutdown(timeout ...time.Duration) error
|
|
```
|
|
|
|
Gracefully drains accepted records and closes the log file. If the processor times out, its resources remain open; retry `Shutdown` to finish cleanup. A fresh `ApplyConfig` permits reuse after shutdown.
|
|
|
|
**Parameters:**
|
|
- `timeout`: Optional timeout duration (defaults to 2x flush interval)
|
|
|
|
**Returns:**
|
|
- `error`: Shutdown error if flush fails or timeout exceeded
|
|
|
|
**Example:**
|
|
```go
|
|
err := logger.Shutdown(5 * time.Second)
|
|
if err != nil {
|
|
fmt.Printf("Shutdown error: %v\n", err)
|
|
}
|
|
```
|
|
|
|
### Flush
|
|
|
|
```go
|
|
func (l *Logger) Flush(timeout time.Duration) error
|
|
```
|
|
|
|
Drains records enqueued before the request and syncs the file. Later arrivals do not extend the drain indefinitely. The timeout covers both queueing and confirmation. A successful return reports successful sync; previously dropped records cannot be recovered. A concurrent stop may return a stopped-processor error.
|
|
|
|
**Parameters:**
|
|
- `timeout`: Maximum time to wait for flush completion
|
|
|
|
**Returns:**
|
|
- `error`: Flush error if timeout exceeded or logger is uninitialized.
|
|
|
|
**Example:**
|
|
```go
|
|
err := logger.Flush(1 * time.Second)
|
|
```
|
|
|
|
## Constants
|
|
|
|
### Log Levels
|
|
|
|
```go
|
|
const (
|
|
LevelTrace int64 = -8
|
|
LevelDebug int64 = -4
|
|
LevelInfo int64 = 0
|
|
LevelWarn int64 = 4
|
|
LevelError int64 = 8
|
|
)
|
|
```
|
|
|
|
Standard log levels for filtering output.
|
|
|
|
### Heartbeat Levels
|
|
|
|
```go
|
|
const (
|
|
LevelProc int64 = 12 // Process statistics
|
|
LevelDisk int64 = 16 // Disk usage statistics
|
|
LevelSys int64 = 20 // System statistics
|
|
)
|
|
```
|
|
|
|
Special levels for heartbeat monitoring that bypass level filtering.
|
|
|
|
### Level Helper Function
|
|
|
|
```go
|
|
func Level(levelStr string) (int64, error)
|
|
```
|
|
|
|
Converts level string to numeric constant.
|
|
|
|
**Parameters:**
|
|
- `levelStr`: Level name ("trace", "debug", "info", "warn", "error", "proc", "disk", "sys")
|
|
|
|
**Returns:**
|
|
- `int64`: Numeric level value
|
|
- `error`: Conversion error for invalid strings
|
|
|
|
**Example:**
|
|
```go
|
|
level, err := log.Level("debug") // Returns -4
|
|
```
|
|
|
|
### Format Flags
|
|
|
|
```go
|
|
const (
|
|
FlagRaw = formatter.FlagRaw // Bypass formatting and sanitization
|
|
FlagShowTimestamp = formatter.FlagShowTimestamp // Force include timestamp
|
|
FlagShowLevel = formatter.FlagShowLevel // Force include level
|
|
FlagStructuredJSON = formatter.FlagStructuredJSON // Structured JSON output
|
|
FlagNoTimestamp = formatter.FlagNoTimestamp // Suppress timestamp
|
|
FlagNoLevel = formatter.FlagNoLevel // Suppress level
|
|
FlagKV = formatter.FlagKV // Alternating string keys and values
|
|
FlagDefault = formatter.FlagDefault // Default flags
|
|
)
|
|
```
|
|
|
|
Control output formatting behavior. These flags are re-exported from the formatter package.
|
|
|
|
### Sanitization Policies
|
|
|
|
```go
|
|
const (
|
|
PolicyRaw = sanitizer.PolicyRaw // No sanitization
|
|
PolicyJSON = sanitizer.PolicyJSON // Content control-character escapes
|
|
PolicyTxt = sanitizer.PolicyTxt // Text file safe
|
|
PolicyShell = sanitizer.PolicyShell // Lossy filter, not shell quoting
|
|
)
|
|
```
|
|
|
|
Pre-configured sanitization policies. These are re-exported from the sanitizer package.
|
|
|
|
## Error Types
|
|
|
|
The logger returns errors prefixed with "log: " for easy identification:
|
|
|
|
```go
|
|
// Configuration errors
|
|
"log: invalid format: 'xml' (use txt, json, or raw)"
|
|
"log: buffer_size must be positive: 0"
|
|
|
|
// Initialization errors
|
|
"log: failed to create log directory '/var/log/app': permission denied"
|
|
"log: logger previously failed to initialize and is disabled"
|
|
|
|
// Runtime errors
|
|
"log: logger not initialized or already shut down"
|
|
"log: timeout waiting for flush confirmation (1s)"
|
|
```
|
|
|
|
## Thread Safety
|
|
|
|
Logger methods support concurrent calls. Lifecycle and configuration changes are serialized. Enqueues hold a short read lock to prevent records being stranded during a stop. Logger, Formatter, Sanitizer, and Builder instances must not be copied after use.
|
|
|
|
`ApplyConfig` takes a snapshot. Emission copies the argument slice, and `LogStructured` also copies the top-level fields map. Referenced values (byte slices, nested maps/slices, pointers, Stringers, and custom marshalers) remain caller-owned: keep them immutable until a successful `Flush` or `Stop`, or pass an application-created snapshot. Do not mutate configuration while an `ApplyConfig` call is reading it.
|
|
|
|
Builders and standalone formatter/sanitizer configuration are not synchronized; finish configuration before sharing. `SetSpawn` callbacks must launch the function asynchronously and return promptly. Error handlers must return promptly and must not invoke lifecycle/configuration methods or `Flush`.
|
|
|
|
### Usage Pattern Example
|
|
|
|
```go
|
|
type Service struct {
|
|
logger *log.Logger
|
|
}
|
|
|
|
func NewService() (*Service, error) {
|
|
logger := log.NewLogger()
|
|
err := logger.ApplyConfigString(
|
|
"directory=/var/log/service",
|
|
"format=json",
|
|
"buffer_size=2048",
|
|
"heartbeat_level=1")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("logger init: %w", err)
|
|
}
|
|
|
|
if err := logger.Start(); err != nil {
|
|
_ = logger.Shutdown()
|
|
return nil, err
|
|
}
|
|
return &Service{logger: logger}, nil
|
|
}
|
|
|
|
func (s *Service) ProcessRequest(id string) error {
|
|
s.logger.InfoTrace(1, "Processing request", "id", id)
|
|
|
|
if err := s.doWork(id); err != nil {
|
|
s.logger.Error("Request failed", "id", id, "error", err)
|
|
return err
|
|
}
|
|
|
|
s.logger.Info("Request completed", "id", id)
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) Shutdown() error {
|
|
return s.logger.Shutdown(5 * time.Second)
|
|
}
|
|
```
|