mirror of
https://github.com/hanzoai/log.git
synced 2026-10-30 18:29:00 +00:00
High-performance zero-allocation structured logging library for the Hanzo ecosystem. Module path: github.com/hanzoai/log
158 lines
5.4 KiB
Plaintext
158 lines
5.4 KiB
Plaintext
// PROPOSAL: Unified Logger Interface Design
|
|
//
|
|
// Problem: Two incompatible Logger types causing type mismatches across the codebase
|
|
// Solution: Single interface-based design with internal implementations
|
|
|
|
package log
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
)
|
|
|
|
// =============================================================================
|
|
// PUBLIC INTERFACE - What consumers use
|
|
// =============================================================================
|
|
|
|
// Logger is the primary logging interface used throughout the codebase.
|
|
// All logging implementations satisfy this interface.
|
|
type Logger interface {
|
|
// Logging methods (geth-style variadic)
|
|
Trace(msg string, args ...any)
|
|
Debug(msg string, args ...any)
|
|
Info(msg string, args ...any)
|
|
Warn(msg string, args ...any)
|
|
Error(msg string, args ...any)
|
|
Fatal(msg string, args ...any)
|
|
Crit(msg string, args ...any) // Alias for Fatal
|
|
|
|
// Context/child loggers
|
|
With(args ...any) Logger
|
|
New(ctx ...any) Logger // Alias for With (geth compat)
|
|
|
|
// Level control
|
|
Level(lvl Level) Logger
|
|
GetLevel() Level
|
|
Enabled(ctx context.Context, level Level) bool
|
|
|
|
// Zero-allocation event-based logging (optional, for hot paths)
|
|
TraceEvent() *Event
|
|
DebugEvent() *Event
|
|
InfoEvent() *Event
|
|
WarnEvent() *Event
|
|
ErrorEvent() *Event
|
|
}
|
|
|
|
// =============================================================================
|
|
// CONSTRUCTORS - Simple, clear API
|
|
// =============================================================================
|
|
|
|
// Noop is a disabled logger - use for optional logger parameters
|
|
var Noop Logger = &noopLogger{}
|
|
|
|
// New creates a new logger with optional context fields
|
|
// Usage: log.New("component", "api", "version", "1.0")
|
|
func New(ctx ...any) Logger {
|
|
return newZeroLogger(ctx...)
|
|
}
|
|
|
|
// NewWithOutput creates a logger writing to a specific output
|
|
func NewWithOutput(w io.Writer, ctx ...any) Logger {
|
|
return newZeroLoggerWithOutput(w, ctx...)
|
|
}
|
|
|
|
// NewWithConfig creates a logger from configuration
|
|
func NewWithConfig(cfg Config) Logger {
|
|
return newZeroLoggerWithConfig(cfg)
|
|
}
|
|
|
|
// =============================================================================
|
|
// INTERNAL IMPLEMENTATIONS - Private, users don't see these
|
|
// =============================================================================
|
|
|
|
// zeroLogger is the high-performance zerolog-based implementation
|
|
type zeroLogger struct {
|
|
w LevelWriter
|
|
level Level
|
|
context []byte
|
|
hooks []Hook
|
|
}
|
|
|
|
func newZeroLogger(ctx ...any) Logger {
|
|
// ... implementation
|
|
return &zeroLogger{}
|
|
}
|
|
|
|
// noopLogger is a no-op implementation
|
|
type noopLogger struct{}
|
|
|
|
func (noopLogger) Trace(string, ...any) {}
|
|
func (noopLogger) Debug(string, ...any) {}
|
|
func (noopLogger) Info(string, ...any) {}
|
|
func (noopLogger) Warn(string, ...any) {}
|
|
func (noopLogger) Error(string, ...any) {}
|
|
func (noopLogger) Fatal(string, ...any) {}
|
|
func (noopLogger) Crit(string, ...any) {}
|
|
func (n noopLogger) With(...any) Logger { return n }
|
|
func (n noopLogger) New(...any) Logger { return n }
|
|
func (n noopLogger) Level(Level) Logger { return n }
|
|
func (noopLogger) GetLevel() Level { return Disabled }
|
|
func (noopLogger) Enabled(context.Context, Level) bool { return false }
|
|
func (noopLogger) TraceEvent() *Event { return nil }
|
|
func (noopLogger) DebugEvent() *Event { return nil }
|
|
func (noopLogger) InfoEvent() *Event { return nil }
|
|
func (noopLogger) WarnEvent() *Event { return nil }
|
|
func (noopLogger) ErrorEvent() *Event { return nil }
|
|
|
|
// =============================================================================
|
|
// USAGE EXAMPLES
|
|
// =============================================================================
|
|
|
|
/*
|
|
// Simple usage - interface everywhere, nil checks work naturally
|
|
func DoSomething(logger log.Logger) {
|
|
if logger == nil {
|
|
logger = log.Noop // Simple!
|
|
}
|
|
logger.Info("doing something", "key", "value")
|
|
}
|
|
|
|
// Optional logger in struct
|
|
type Service struct {
|
|
Logger log.Logger // Interface type, can be nil
|
|
}
|
|
|
|
func (s *Service) Run() {
|
|
if s.Logger != nil {
|
|
s.Logger.Info("service started")
|
|
}
|
|
}
|
|
|
|
// Creating loggers
|
|
appLogger := log.New("app", "myservice")
|
|
dbLogger := appLogger.With("component", "database")
|
|
*/
|
|
|
|
// =============================================================================
|
|
// BENEFITS
|
|
// =============================================================================
|
|
//
|
|
// 1. Single Logger type - no confusion between struct/interface
|
|
// 2. Can use == nil checks - no IsZero() needed
|
|
// 3. Noop is a simple variable - no function call needed
|
|
// 4. Internal implementations are hidden - can swap zerolog for slog later
|
|
// 5. No subpackage needed - everything in one place
|
|
// 6. Generics not needed - interfaces solve the problem cleanly
|
|
//
|
|
|
|
// =============================================================================
|
|
// MIGRATION PATH
|
|
// =============================================================================
|
|
//
|
|
// 1. Add Logger interface alongside existing struct
|
|
// 2. Make existing struct implement interface
|
|
// 3. Change exported functions to return interface
|
|
// 4. Update consumers one package at a time
|
|
// 5. Eventually remove struct export, keep only interface
|
|
//
|