Files
log/doc/api.md
T
Claude fe711ed2a5
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
v0.1.12 SetConsoleWriter routes console output to a host writer
A host that draws on the terminal (a TUI) cannot let the logger write to
stdout or stderr, yet the records are worth showing inside the host.
SetErrorHandler already covers internal diagnostics; SetConsoleWriter is
its sibling for console output.

- SetConsoleWriter(w) sends console output of every console_target to w,
  split's warn-and-above records included; nil restores stdout/stderr.
  It holds across ApplyConfig and is safe while logging.
- One stored value: ApplyConfig and SetConsoleWriter publish the console
  writers through storeConsole; the processor's split branch now reads
  the stored warn writer instead of writing os.Stderr directly.
- TestLoggerConsoleTargets becomes TestConsoleWriterTakesEveryTarget,
  which asserts where each target's records land; a second test checks
  that nil restores the configured writers.
- README names both hooks for terminal hosts; the API doc's callback
  contract covers console writers.

Verified: go build ./... ok; gofmt -l on changed files clean; go vet ./...
ok; go test ./... ok (all four packages, under 1 s); go test -race on the
new tests ok; mutation run 6 of 6 caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SyaMAhyEzAp3ULLWJZG4jQ
2026-10-10 20:14:00 -04:00

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 and `SetConsoleWriter` writers 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)
}
```