From ccbe65bf407843ef39ccfa8b45266dc63951d91a76addf61b7aade005911b7ea Mon Sep 17 00:00:00 2001 From: Lixen Wraith Date: Tue, 8 Jul 2025 22:13:11 -0400 Subject: [PATCH] e1.4.4 Fix module path and dependency issues, compatibility package added. --- README.md | 12 +- compat/README.md | 188 +++++++++++++++++++++++++++++ compat/builder.go | 72 +++++++++++ compat/fasthttp.go | 103 ++++++++++++++++ compat/gnet.go | 79 ++++++++++++ compat/structured.go | 131 ++++++++++++++++++++ config.go | 2 +- example/fasthttp/main.go | 75 ++++++++++++ example/gnet/main.go | 47 ++++++++ {cmd => example}/heartbeat/main.go | 3 +- {cmd => example}/reconfig/main.go | 3 +- {cmd => example}/simple/main.go | 7 +- {cmd => example}/stress/main.go | 7 +- format.go | 2 +- go.mod | 19 ++- go.sum | 38 +++++- interface.go | 2 +- logger.go | 4 +- processor.go | 2 +- state.go | 6 +- storage.go | 1 + utility.go | 2 +- 22 files changed, 776 insertions(+), 29 deletions(-) create mode 100644 compat/README.md create mode 100644 compat/builder.go create mode 100644 compat/fasthttp.go create mode 100644 compat/gnet.go create mode 100644 compat/structured.go create mode 100644 example/fasthttp/main.go create mode 100644 example/gnet/main.go rename {cmd => example}/heartbeat/main.go (97%) rename {cmd => example}/reconfig/main.go (94%) rename {cmd => example}/simple/main.go (95%) rename {cmd => example}/stress/main.go (97%) diff --git a/README.md b/README.md index 72a0a5b..0166024 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Log A high-performance, buffered, rotating file logger for Go applications, configured via -the [LixenWraith/config](https://github.com/LixenWraith/config) package or simple overrides. Designed for +the [lixenwraith/config](https://github.com/lixenwraith/config) package or simple overrides. Designed for production-grade reliability with features like disk management, log retention, and lock-free asynchronous processing using atomic operations and channels. @@ -14,7 +14,7 @@ using atomic operations and channels. - **Lock-free Asynchronous Logging:** Non-blocking log operations with minimal application impact. Logs are sent via a buffered channel, processed by a dedicated background goroutine. Uses atomic operations for state management, avoiding mutexes in the hot path. -- **External Configuration:** Fully configured using `github.com/LixenWraith/config`, supporting both TOML files and CLI +- **External Configuration:** Fully configured using `github.com/lixenwraith/config`, supporting both TOML files and CLI overrides with centralized management. Also supports simple initialization with defaults and string overrides via `InitWithDefaults`. - **Automatic File Rotation:** Seamlessly rotates log files when they reach configurable size limits (`max_size_mb`), @@ -47,8 +47,8 @@ using atomic operations and channels. ## Installation ```bash -go get github.com/LixenWraith/log -go get github.com/LixenWraith/config +go get github.com/lixenwraith/log +go get github.com/lixenwraith/config ``` ## Basic Usage @@ -59,7 +59,7 @@ This example shows minimal initialization using defaults with a single override, package main import ( - "github.com/LixenWraith/log" + "github.com/lixenwraith/log" ) func main() { @@ -287,7 +287,7 @@ err := logger.InitWithDefaults( condition is resolved. - **Configuration Dependencies:** - For full configuration management (TOML file loading, CLI overrides, etc.), the `github.com/LixenWraith/config` package is required when using the `Init` method. For simpler initialization without this external dependency, use `InitWithDefaults`. + For full configuration management (TOML file loading, CLI overrides, etc.), the `github.com/lixenwraith/config` package is required when using the `Init` method. For simpler initialization without this external dependency, use `InitWithDefaults`. - **Retention Accuracy:** Log retention relies on file modification times, which could potentially be affected by external file system operations. diff --git a/compat/README.md b/compat/README.md new file mode 100644 index 0000000..0e61096 --- /dev/null +++ b/compat/README.md @@ -0,0 +1,188 @@ +# Compatibility Adapters for lixenwraith/log + +This package provides compatibility adapters to use the `github.com/lixenwraith/log` logger with popular Go networking frameworks: + +- **gnet v2**: High-performance event-driven networking framework +- **fasthttp**: Fast HTTP implementation + +## Features + +- ✅ Full interface compatibility with both frameworks +- ✅ Preserves structured logging capabilities +- ✅ Configurable fatal behavior for gnet +- ✅ Automatic log level detection for fasthttp +- ✅ Optional structured field extraction from printf formats +- ✅ Thread-safe and high-performance +- ✅ Shared logger instance for multiple adapters + +## Installation + +```bash +go get github.com/lixenwraith/log +``` + +## Quick Start + +### Basic Usage with gnet + +```go +import ( + "github.com/lixenwraith/log" + "github.com/lixenwraith/log/compat" + "github.com/panjf2000/gnet/v2" +) + +// Create and configure logger +logger := log.NewLogger() +logger.InitWithDefaults("directory=/var/log/gnet", "level=-4") +defer logger.Shutdown() + +// Create gnet adapter +adapter := compat.NewGnetAdapter(logger) + +// Use with gnet +gnet.Run(eventHandler, "tcp://127.0.0.1:9000", gnet.WithLogger(adapter)) +``` + +### Basic Usage with fasthttp + +```go +import ( + "github.com/lixenwraith/log" + "github.com/lixenwraith/log/compat" + "github.com/valyala/fasthttp" +) + +// Create and configure logger +logger := log.NewLogger() +logger.InitWithDefaults("directory=/var/log/fasthttp") +defer logger.Shutdown() + +// Create fasthttp adapter +adapter := compat.NewFastHTTPAdapter(logger) + +// Use with fasthttp +server := &fasthttp.Server{ + Handler: requestHandler, + Logger: adapter, +} +server.ListenAndServe(":8080") +``` + +### Using the Builder Pattern + +```go +// Create adapters with shared configuration +builder := compat.NewBuilder(). + WithOptions( + "directory=/var/log/app", + "level=0", + "format=json", + "max_size_mb=100", + ) + +gnetAdapter, fasthttpAdapter, err := builder.Build() +if err != nil { + panic(err) +} +defer builder.GetLogger().Shutdown() +``` + +## Advanced Features + +### Structured Field Extraction + +The structured adapters can extract key-value pairs from printf-style format strings: + +```go +// Use structured adapter +adapter := compat.NewStructuredGnetAdapter(logger) + +// These calls will extract structured fields: +adapter.Infof("client=%s port=%d", "192.168.1.1", 8080) +// Logs: {"client": "192.168.1.1", "port": 8080, "source": "gnet"} + +adapter.Errorf("user: %s, action: %s, error: %s", "john", "login", "invalid password") +// Logs: {"user": "john", "action": "login", "error": "invalid password", "source": "gnet"} +``` + +### Custom Fatal Handling + +```go +adapter := compat.NewGnetAdapter(logger, + compat.WithFatalHandler(func(msg string) { + // Custom cleanup + saveState() + notifyAdmin(msg) + os.Exit(1) + }), +) +``` + +### Custom Level Detection for fasthttp + +```go +adapter := compat.NewFastHTTPAdapter(logger, + compat.WithDefaultLevel(log.LevelInfo), + compat.WithLevelDetector(func(msg string) int64 { + if strings.Contains(msg, "CRITICAL") { + return log.LevelError + } + return 0 // Use default detection + }), +) +``` + +## Configuration Examples + +### High-Performance Configuration + +```go +builder := compat.NewBuilder(). + WithOptions( + "directory=/var/log/highperf", + "level=0", // Info and above + "format=json", // Structured logs + "buffer_size=4096", // Large buffer + "flush_interval_ms=1000", // Less frequent flushes + "enable_periodic_sync=false", // Disable periodic sync + ) +``` + +### Development Configuration + +```go +builder := compat.NewBuilder(). + WithOptions( + "directory=./logs", + "level=-4", // Debug level + "format=txt", // Human-readable + "show_timestamp=true", + "show_level=true", + "trace_depth=3", // Include call traces + "flush_interval_ms=100", // Frequent flushes + ) +``` + +### Production Configuration with Monitoring + +```go +builder := compat.NewBuilder(). + WithOptions( + "directory=/var/log/prod", + "level=0", + "format=json", + "max_size_mb=1000", // 1GB files + "max_total_size_mb=10000", // 10GB total + "retention_period_hrs=168", // 7 days + "heartbeat_level=2", // Process + disk heartbeats + "heartbeat_interval_s=300", // 5 minutes + ) +``` + +## Performance Considerations + +1. **Printf Overhead**: The adapters must format printf-style strings, adding minimal overhead +2. **Structured Extraction**: The structured adapters use regex matching, which adds ~1-2μs per call +3. **Level Detection**: FastHTTP adapter's level detection adds <100ns for simple string checks +4. **Buffering**: The underlying logger's buffering minimizes I/O impact \ No newline at end of file diff --git a/compat/builder.go b/compat/builder.go new file mode 100644 index 0000000..0145a61 --- /dev/null +++ b/compat/builder.go @@ -0,0 +1,72 @@ +// FILE: compat/builder.go +package compat + +import ( + "github.com/lixenwraith/log" + "github.com/panjf2000/gnet/v2" + "github.com/valyala/fasthttp" +) + +// Builder provides a convenient way to create configured loggers for both frameworks +type Builder struct { + logger *log.Logger + options []string // InitWithDefaults options +} + +// NewBuilder creates a new adapter builder +func NewBuilder() *Builder { + return &Builder{ + logger: log.NewLogger(), + } +} + +// WithOptions adds configuration options for the underlying logger +func (b *Builder) WithOptions(opts ...string) *Builder { + b.options = append(b.options, opts...) + return b +} + +// Build initializes the logger and returns adapters for both frameworks +func (b *Builder) Build() (*GnetAdapter, *FastHTTPAdapter, error) { + // Initialize the logger + if err := b.logger.InitWithDefaults(b.options...); err != nil { + return nil, nil, err + } + + // Create adapters + gnetAdapter := NewGnetAdapter(b.logger) + fasthttpAdapter := NewFastHTTPAdapter(b.logger) + + return gnetAdapter, fasthttpAdapter, nil +} + +// BuildStructured initializes the logger and returns structured adapters +func (b *Builder) BuildStructured() (*StructuredGnetAdapter, *FastHTTPAdapter, error) { + // Initialize the logger + if err := b.logger.InitWithDefaults(b.options...); err != nil { + return nil, nil, err + } + + // Create adapters + gnetAdapter := NewStructuredGnetAdapter(b.logger) + fasthttpAdapter := NewFastHTTPAdapter(b.logger) + + return gnetAdapter, fasthttpAdapter, nil +} + +// GetLogger returns the underlying logger for direct access +func (b *Builder) GetLogger() *log.Logger { + return b.logger +} + +// Example usage functions + +// ConfigureGnetServer configures a gnet server with the logger +func ConfigureGnetServer(adapter *GnetAdapter, opts ...gnet.Option) []gnet.Option { + return append(opts, gnet.WithLogger(adapter)) +} + +// ConfigureFastHTTPServer configures a fasthttp server with the logger +func ConfigureFastHTTPServer(adapter *FastHTTPAdapter, server *fasthttp.Server) { + server.Logger = adapter +} \ No newline at end of file diff --git a/compat/fasthttp.go b/compat/fasthttp.go new file mode 100644 index 0000000..b6a6952 --- /dev/null +++ b/compat/fasthttp.go @@ -0,0 +1,103 @@ +// FILE: compat/fasthttp.go +package compat + +import ( + "fmt" + "strings" + + "github.com/lixenwraith/log" +) + +// FastHTTPAdapter wraps lixenwraith/log.Logger to implement fasthttp's Logger interface +type FastHTTPAdapter struct { + logger *log.Logger + defaultLevel int64 + levelDetector func(string) int64 // Function to detect log level from message +} + +// NewFastHTTPAdapter creates a new fasthttp-compatible logger adapter +func NewFastHTTPAdapter(logger *log.Logger, opts ...FastHTTPOption) *FastHTTPAdapter { + adapter := &FastHTTPAdapter{ + logger: logger, + defaultLevel: log.LevelInfo, + levelDetector: DetectLogLevel, // Default level detection + } + + for _, opt := range opts { + opt(adapter) + } + + return adapter +} + +// FastHTTPOption allows customizing adapter behavior +type FastHTTPOption func(*FastHTTPAdapter) + +// WithDefaultLevel sets the default log level for Printf calls +func WithDefaultLevel(level int64) FastHTTPOption { + return func(a *FastHTTPAdapter) { + a.defaultLevel = level + } +} + +// WithLevelDetector sets a custom function to detect log level from message content +func WithLevelDetector(detector func(string) int64) FastHTTPOption { + return func(a *FastHTTPAdapter) { + a.levelDetector = detector + } +} + +// Printf implements fasthttp's Logger interface +func (a *FastHTTPAdapter) Printf(format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + + // Detect log level from message content + level := a.defaultLevel + if a.levelDetector != nil { + detected := a.levelDetector(msg) + if detected != 0 { + level = detected + } + } + + // Log with appropriate level + switch level { + case log.LevelDebug: + a.logger.Debug("msg", msg, "source", "fasthttp") + case log.LevelWarn: + a.logger.Warn("msg", msg, "source", "fasthttp") + case log.LevelError: + a.logger.Error("msg", msg, "source", "fasthttp") + default: + a.logger.Info("msg", msg, "source", "fasthttp") + } +} + +// DetectLogLevel attempts to detect log level from message content +func DetectLogLevel(msg string) int64 { + msgLower := strings.ToLower(msg) + + // Check for error indicators + if strings.Contains(msgLower, "error") || + strings.Contains(msgLower, "failed") || + strings.Contains(msgLower, "fatal") || + strings.Contains(msgLower, "panic") { + return log.LevelError + } + + // Check for warning indicators + if strings.Contains(msgLower, "warn") || + strings.Contains(msgLower, "warning") || + strings.Contains(msgLower, "deprecated") { + return log.LevelWarn + } + + // Check for debug indicators + if strings.Contains(msgLower, "debug") || + strings.Contains(msgLower, "trace") { + return log.LevelDebug + } + + // Default to info level + return log.LevelInfo +} \ No newline at end of file diff --git a/compat/gnet.go b/compat/gnet.go new file mode 100644 index 0000000..786eccf --- /dev/null +++ b/compat/gnet.go @@ -0,0 +1,79 @@ +// FILE: compat/gnet.go +package compat + +import ( + "fmt" + "os" + "time" + + "github.com/lixenwraith/log" +) + +// GnetAdapter wraps lixenwraith/log.Logger to implement gnet's logging.Logger interface +type GnetAdapter struct { + logger *log.Logger + fatalHandler func(msg string) // Customizable fatal behavior +} + +// NewGnetAdapter creates a new gnet-compatible logger adapter +func NewGnetAdapter(logger *log.Logger, opts ...GnetOption) *GnetAdapter { + adapter := &GnetAdapter{ + logger: logger, + fatalHandler: func(msg string) { + os.Exit(1) // Default behavior matches gnet expectations + }, + } + + for _, opt := range opts { + opt(adapter) + } + + return adapter +} + +// GnetOption allows customizing adapter behavior +type GnetOption func(*GnetAdapter) + +// WithFatalHandler sets a custom fatal handler +func WithFatalHandler(handler func(string)) GnetOption { + return func(a *GnetAdapter) { + a.fatalHandler = handler + } +} + +// Debugf logs at debug level with printf-style formatting +func (a *GnetAdapter) Debugf(format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + a.logger.Debug("msg", msg, "source", "gnet") +} + +// Infof logs at info level with printf-style formatting +func (a *GnetAdapter) Infof(format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + a.logger.Info("msg", msg, "source", "gnet") +} + +// Warnf logs at warn level with printf-style formatting +func (a *GnetAdapter) Warnf(format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + a.logger.Warn("msg", msg, "source", "gnet") +} + +// Errorf logs at error level with printf-style formatting +func (a *GnetAdapter) Errorf(format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + a.logger.Error("msg", msg, "source", "gnet") +} + +// Fatalf logs at error level and triggers fatal handler +func (a *GnetAdapter) Fatalf(format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + a.logger.Error("msg", msg, "source", "gnet", "fatal", true) + + // Ensure log is flushed before exit + _ = a.logger.Flush(100 * time.Millisecond) + + if a.fatalHandler != nil { + a.fatalHandler(msg) + } +} \ No newline at end of file diff --git a/compat/structured.go b/compat/structured.go new file mode 100644 index 0000000..d6731b9 --- /dev/null +++ b/compat/structured.go @@ -0,0 +1,131 @@ +// FILE: compat/structured.go +package compat + +import ( + "fmt" + "regexp" + "strings" + + "github.com/lixenwraith/log" +) + +// parseFormat attempts to extract structured fields from printf-style format strings +// This is useful for preserving structured logging semantics +func parseFormat(format string, args []interface{}) []interface{} { + // Pattern to detect common structured patterns like "key=%v" or "key: %v" + keyValuePattern := regexp.MustCompile(`(\w+)\s*[:=]\s*%[vsdqxXeEfFgGpbcU]`) + + matches := keyValuePattern.FindAllStringSubmatchIndex(format, -1) + if len(matches) == 0 || len(matches) > len(args) { + // Fallback to simple message if pattern doesn't match + return []interface{}{"msg", fmt.Sprintf(format, args...)} + } + + // Build structured fields + fields := make([]interface{}, 0, len(matches)*2+2) + lastEnd := 0 + argIndex := 0 + + for _, match := range matches { + // Add any text before this match as part of the message + if match[0] > lastEnd { + prefix := format[lastEnd:match[0]] + if strings.TrimSpace(prefix) != "" { + if len(fields) == 0 { + fields = append(fields, "msg", strings.TrimSpace(prefix)) + } + } + } + + // Extract key name + keyStart := match[2] + keyEnd := match[3] + key := format[keyStart:keyEnd] + + // Get corresponding value + if argIndex < len(args) { + fields = append(fields, key, args[argIndex]) + argIndex++ + } + + lastEnd = match[1] + } + + // Handle remaining format string and args + if lastEnd < len(format) { + remainingFormat := format[lastEnd:] + remainingArgs := args[argIndex:] + if len(remainingArgs) > 0 { + remaining := fmt.Sprintf(remainingFormat, remainingArgs...) + if strings.TrimSpace(remaining) != "" { + if len(fields) == 0 { + fields = append(fields, "msg", strings.TrimSpace(remaining)) + } else { + // Append to existing message + for i := 0; i < len(fields); i += 2 { + if fields[i] == "msg" { + fields[i+1] = fmt.Sprintf("%v %s", fields[i+1], strings.TrimSpace(remaining)) + break + } + } + } + } + } + } + + return fields +} + +// StructuredGnetAdapter provides enhanced structured logging for gnet +type StructuredGnetAdapter struct { + *GnetAdapter + extractFields bool +} + +// NewStructuredGnetAdapter creates a gnet adapter with structured field extraction +func NewStructuredGnetAdapter(logger *log.Logger, opts ...GnetOption) *StructuredGnetAdapter { + return &StructuredGnetAdapter{ + GnetAdapter: NewGnetAdapter(logger, opts...), + extractFields: true, + } +} + +// Debugf logs with structured field extraction +func (a *StructuredGnetAdapter) Debugf(format string, args ...interface{}) { + if a.extractFields { + fields := parseFormat(format, args) + a.logger.Debug(append(fields, "source", "gnet")...) + } else { + a.GnetAdapter.Debugf(format, args...) + } +} + +// Infof logs with structured field extraction +func (a *StructuredGnetAdapter) Infof(format string, args ...interface{}) { + if a.extractFields { + fields := parseFormat(format, args) + a.logger.Info(append(fields, "source", "gnet")...) + } else { + a.GnetAdapter.Infof(format, args...) + } +} + +// Warnf logs with structured field extraction +func (a *StructuredGnetAdapter) Warnf(format string, args ...interface{}) { + if a.extractFields { + fields := parseFormat(format, args) + a.logger.Warn(append(fields, "source", "gnet")...) + } else { + a.GnetAdapter.Warnf(format, args...) + } +} + +// Errorf logs with structured field extraction +func (a *StructuredGnetAdapter) Errorf(format string, args ...interface{}) { + if a.extractFields { + fields := parseFormat(format, args) + a.logger.Error(append(fields, "source", "gnet")...) + } else { + a.GnetAdapter.Errorf(format, args...) + } +} \ No newline at end of file diff --git a/config.go b/config.go index a22cd62..ba0911c 100644 --- a/config.go +++ b/config.go @@ -1,4 +1,4 @@ -// --- File: config.go --- +// FILE: config.go package log import ( diff --git a/example/fasthttp/main.go b/example/fasthttp/main.go new file mode 100644 index 0000000..3a6fda4 --- /dev/null +++ b/example/fasthttp/main.go @@ -0,0 +1,75 @@ +// FILE: examples/fasthttp/main.go +package main + +import ( + "fmt" + "strings" + "time" + + "github.com/lixenwraith/log" + "github.com/lixenwraith/log/compat" + "github.com/valyala/fasthttp" +) + +func main() { + // Create and configure logger + logger := log.NewLogger() + err := logger.InitWithDefaults( + "directory=/var/log/fasthttp", + "level=0", + "format=txt", + "buffer_size=2048", + ) + if err != nil { + panic(err) + } + defer logger.Shutdown() + + // Create fasthttp adapter with custom level detection + fasthttpAdapter := compat.NewFastHTTPAdapter( + logger, + compat.WithDefaultLevel(log.LevelInfo), + compat.WithLevelDetector(customLevelDetector), + ) + + // Configure fasthttp server + server := &fasthttp.Server{ + Handler: requestHandler, + Logger: fasthttpAdapter, + + // Other server settings + Name: "MyServer", + Concurrency: fasthttp.DefaultConcurrency, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 120 * time.Second, + TCPKeepalive: true, + ReduceMemoryUsage: true, + } + + // Start server + fmt.Println("Starting server on :8080") + if err := server.ListenAndServe(":8080"); err != nil { + panic(err) + } +} + +func requestHandler(ctx *fasthttp.RequestCtx) { + ctx.SetContentType("text/plain") + fmt.Fprintf(ctx, "Hello, world! Path: %s\n", ctx.Path()) +} + +func customLevelDetector(msg string) int64 { + // Custom logic to detect log levels + // Can inspect specific fasthttp message patterns + + if strings.Contains(msg, "connection cannot be served") { + return log.LevelWarn + } + if strings.Contains(msg, "error when serving connection") { + return log.LevelError + } + + // Use default detection + return compat.detectLogLevel(msg) +} \ No newline at end of file diff --git a/example/gnet/main.go b/example/gnet/main.go new file mode 100644 index 0000000..372a809 --- /dev/null +++ b/example/gnet/main.go @@ -0,0 +1,47 @@ +// FILE: example/gnet/main.go +package main + +import ( + "github.com/lixenwraith/log" + "github.com/lixenwraith/log/compat" + "github.com/panjf2000/gnet/v2" +) + +// Example gnet event handler +type echoServer struct { + gnet.BuiltinEventEngine +} + +func (es *echoServer) OnTraffic(c gnet.Conn) gnet.Action { + buf, _ := c.Next(-1) + c.Write(buf) + return gnet.None +} + +func main() { + // Method 1: Simple adapter + logger := log.NewLogger() + err := logger.InitWithDefaults( + "directory=/var/log/gnet", + "level=-4", // Debug level + "format=json", + ) + if err != nil { + panic(err) + } + defer logger.Shutdown() + + gnetAdapter := compat.NewGnetAdapter(logger) + + // Configure gnet server with the logger + err = gnet.Run( + &echoServer{}, + "tcp://127.0.0.1:9000", + gnet.WithMulticore(true), + gnet.WithLogger(gnetAdapter), + gnet.WithReusePort(true), + ) + if err != nil { + panic(err) + } +} \ No newline at end of file diff --git a/cmd/heartbeat/main.go b/example/heartbeat/main.go similarity index 97% rename from cmd/heartbeat/main.go rename to example/heartbeat/main.go index 4edec7d..cf13a3e 100644 --- a/cmd/heartbeat/main.go +++ b/example/heartbeat/main.go @@ -1,3 +1,4 @@ +// FILE: example/heartbeat/main.go package main import ( @@ -5,7 +6,7 @@ import ( "os" "time" - "github.com/LixenWraith/log" + "github.com/lixenwraith/log" ) func main() { diff --git a/cmd/reconfig/main.go b/example/reconfig/main.go similarity index 94% rename from cmd/reconfig/main.go rename to example/reconfig/main.go index 1027d72..1a16d0c 100644 --- a/cmd/reconfig/main.go +++ b/example/reconfig/main.go @@ -1,3 +1,4 @@ +// FILE: example/reconfig/main.go package main import ( @@ -5,7 +6,7 @@ import ( "sync/atomic" "time" - "github.com/LixenWraith/log" + "github.com/lixenwraith/log" ) // Simulate rapid reconfiguration diff --git a/cmd/simple/main.go b/example/simple/main.go similarity index 95% rename from cmd/simple/main.go rename to example/simple/main.go index 8bdd5ac..7ec34ca 100644 --- a/cmd/simple/main.go +++ b/example/simple/main.go @@ -1,3 +1,4 @@ +// FILE: example/simple/main.go package main import ( @@ -6,8 +7,8 @@ import ( "sync" "time" - "github.com/LixenWraith/config" - "github.com/LixenWraith/log" + "github.com/lixenwraith/config" + "github.com/lixenwraith/log" ) const configFile = "simple_config.toml" @@ -51,7 +52,7 @@ func main() { // Load config from file (and potentially CLI args - none provided here) // The log package will register its keys during Init - _, err = cfg.Load(configFile, nil) // os.Args[1:] could be used here + err = cfg.Load(configFile, nil) // os.Args[1:] could be used here if err != nil { fmt.Fprintf(os.Stderr, "Failed to load config: %v. Using defaults.\n", err) // Proceeding, log.Init will use registered defaults diff --git a/cmd/stress/main.go b/example/stress/main.go similarity index 97% rename from cmd/stress/main.go rename to example/stress/main.go index d134a50..71bfd1f 100644 --- a/cmd/stress/main.go +++ b/example/stress/main.go @@ -1,3 +1,4 @@ +// FILE: example/stress/main.go package main import ( @@ -11,8 +12,8 @@ import ( "syscall" "time" - "github.com/LixenWraith/config" - "github.com/LixenWraith/log" + "github.com/lixenwraith/config" + "github.com/lixenwraith/log" ) const ( @@ -121,7 +122,7 @@ func main() { // defer os.RemoveAll(logsDir) // Remove to keep the log directory cfg := config.New() - _, err = cfg.Load(configFile, nil) + err = cfg.Load(configFile, nil) if err != nil { fmt.Fprintf(os.Stderr, "Failed to load config: %v.\n", err) os.Exit(1) diff --git a/format.go b/format.go index 2c83583..aae8ee1 100644 --- a/format.go +++ b/format.go @@ -1,4 +1,4 @@ -// --- File: format.go --- +// FILE: format.go package log import ( diff --git a/go.mod b/go.mod index b6cfc15..2c9f4ea 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,23 @@ -module github.com/LixenWraith/log +module github.com/lixenwraith/log -go 1.24.2 +go 1.24.4 -require github.com/LixenWraith/config v0.0.0-20250426061518-532233ac282c +require ( + github.com/lixenwraith/config v0.0.0-20250701170607-8515fa0543b6 + github.com/panjf2000/gnet/v2 v2.9.1 + github.com/valyala/fasthttp v1.63.0 +) require ( github.com/BurntSushi/toml v1.5.0 // indirect + github.com/andybalholm/brotli v1.2.0 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/panjf2000/ants/v2 v2.11.3 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/sys v0.33.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect ) diff --git a/go.sum b/go.sum index 0f538b5..0e750ea 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,40 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/LixenWraith/config v0.0.0-20250426061518-532233ac282c h1:3JcYZVGF+OOfm72eOE2LLFHU9ERYSKs76jJOxpB/4FQ= -github.com/LixenWraith/config v0.0.0-20250426061518-532233ac282c/go.mod h1:3cBfqRthYrMGIkea2GXyMVPNxVWSYt2FkeWG1Zyv2Ow= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/lixenwraith/config v0.0.0-20250701170607-8515fa0543b6 h1:qE4SpAJWFaLkdRyE0FjTPBBRYE7LOvcmRCB5p86W73Q= +github.com/lixenwraith/config v0.0.0-20250701170607-8515fa0543b6/go.mod h1:4wPJ3HnLrYrtUwTinngCsBgtdIXsnxkLa7q4KAIbwY8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg= +github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek= +github.com/panjf2000/gnet/v2 v2.9.1 h1:bKewICy/0xnQ9PMzNaswpe/Ah14w1TrRk91LHTcbIlA= +github.com/panjf2000/gnet/v2 v2.9.1/go.mod h1:WQTxDWYuQ/hz3eccH0FN32IVuvZ19HewEWx0l62fx7E= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.63.0 h1:DisIL8OjB7ul2d7cBaMRcKTQDYnrGy56R4FCiuDP0Ns= +github.com/valyala/fasthttp v1.63.0/go.mod h1:REc4IeW+cAEyLrRPa5A81MIjvz0QE1laoTX2EaPHKJM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/interface.go b/interface.go index 428724d..93f92b2 100644 --- a/interface.go +++ b/interface.go @@ -1,4 +1,4 @@ -// --- File: interface.go --- +// FILE: interface.go package log import ( diff --git a/logger.go b/logger.go index 288c2d4..2810ad9 100644 --- a/logger.go +++ b/logger.go @@ -1,4 +1,4 @@ -// --- File: logger.go --- +// FILE: logger.go package log import ( @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/LixenWraith/config" + "github.com/lixenwraith/config" ) // Logger is the core struct that encapsulates all logger functionality diff --git a/processor.go b/processor.go index ceb7ede..57623bb 100644 --- a/processor.go +++ b/processor.go @@ -1,4 +1,4 @@ -// --- File: processor.go --- +// FILE: processor.go package log import ( diff --git a/state.go b/state.go index 85cfb70..d059487 100644 --- a/state.go +++ b/state.go @@ -1,4 +1,4 @@ -// --- File: state.go --- +// FILE: state.go package log import ( @@ -9,7 +9,7 @@ import ( "sync/atomic" "time" - "github.com/LixenWraith/config" + "github.com/lixenwraith/config" ) // State encapsulates the runtime state of the logger @@ -220,4 +220,4 @@ func (l *Logger) Flush(timeout time.Duration) error { case <-time.After(timeout): return fmtErrorf("timeout waiting for flush confirmation (%v)", timeout) } -} \ No newline at end of file +} diff --git a/storage.go b/storage.go index 752bf57..234eefa 100644 --- a/storage.go +++ b/storage.go @@ -1,3 +1,4 @@ +// FILE: storage.go package log import ( diff --git a/utility.go b/utility.go index 36d1928..9338014 100644 --- a/utility.go +++ b/utility.go @@ -1,4 +1,4 @@ -// --- File: utility.go --- +// FILE: utility.go package log import (