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
Log
A high-performance, buffered, rotating file logger for Go applications with built-in disk management, operational monitoring, and framework compatibility adapters.
Key Features
- Buffered async logging with minimal application impact
- Automatic file rotation and disk space management
- Operational heartbeats for production monitoring
- Hot reconfiguration with draining on restart
- Framework adapters for gnet v2, fasthttp, Fiber v2
- Production-grade reliability with graceful shutdown
Quick Start
package main
import (
"fmt"
"github.com/lixenwraith/log"
)
func main() {
// Create and initialize logger
logger := log.NewLogger()
err := logger.ApplyConfigString("directory=/var/log/myapp", "enable_file=true", "format=txt")
if err != nil {
panic(fmt.Errorf("failed to apply logger config: %w", err))
}
defer logger.Shutdown()
// Start logging
if err = logger.Start(); err != nil {
panic(fmt.Errorf("failed to start logger: %w", err))
}
logger.Info("Application started", "version", "1.0.0")
logger.Debug("Debug information", "user_id", 12345)
logger.Warn("Warning message", "threshold", 0.95)
logger.Error("Error occurred", "code", 500)
}
Installation
go get github.com/lixenwraith/log
Documentation
- Getting Started - Installation and basic usage
- Configuration Guide - Configuration options
- Configuration Builder - Builder pattern guide
- API Reference - Complete API documentation
- Logging Guide - Logging methods and best practices
- Formatting & Sanitization - Standalone formatter and sanitizer packages
- Disk Management - File rotation and cleanup
- Heartbeat Monitoring - Operational statistics
- Compatibility Adapters - Framework integrations
- Testing and Performance - Race, stress, fuzz, and benchmark commands
Architecture Overview
Applications enqueue records into a bounded channel. A single background processor formats records, writes output, rotates files, and performs cleanup. A short read lock coordinates enqueues with lifecycle changes; producers never wait for queue capacity or output I/O. Full queues drop records and increment counters.
Call ApplyConfig (or Build) and then Start before logging. Stop drains accepted records and can be followed by Start. Shutdown also closes the file; after a timeout, retry it to finish cleanup. See the API reference for ownership and concurrency rules.
Hosts that own the terminal, such as TUIs, route console output with SetConsoleWriter and internal diagnostics with SetErrorHandler.
Contributing
Contributions and suggestions are welcome! There is no contribution policy, but if interested, please submit pull requests to the repository. Submit suggestions or issues at issue tracker.
License
BSD-3-Clause