A drop-in replacement for logrus that uses Go's standard log/slog package under the hood. This library provides a migration path for projects that want to move from logrus to Go's structured logging without changing their existing code or to facilitate a gradual migration.
Note
Claude Code almost entirely created this project. It is an experiment to see how this might solve the migration problem. Using this I migrated the entire go-choria code base in less than a hour with no code changes.
- Zero code changes: Replace your logrus import and your code continues to work
- No external dependencies: Uses only Go's standard library
log/slog - Full API compatibility: Supports all logrus types, methods, and patterns
- Modern logging: Leverages Go 1.21+'s structured logging capabilities
- Performance: Benefits from slog's optimized implementation
go get github.com/choria-io/slogrusReplace your logrus import:
// Before
import "github.com/sirupsen/logrus"
// After
import "github.com/choria-io/slogrus"All your existing code continues to work:
slogrus.Info("Application started")
slogrus.WithField("user", "john").Info("User logged in")
slogrus.WithFields(slogrus.Fields{
"method": "GET",
"path": "/api/users",
"status": 200,
}).Info("Request completed")Create and configure custom loggers:
logger := slogrus.New()
logger.SetLevel(slogrus.DebugLevel)
logger.SetOutput(os.Stdout)
logger.Debug("Debug message")
logger.Info("Info message")
logger.Error("Error message")Use fields for structured logging:
log := slogrus.WithFields(slogrus.Fields{
"component": "database",
"operation": "query",
"table": "users",
})
log.Info("Query executed successfully")
log.WithField("duration", "45ms").Info("Query performance")Chain methods for building complex log entries:
slogrus.WithField("service", "api").
WithField("version", "1.2.3").
WithError(err).
Error("Service startup failed")Use context for request tracing:
ctx := context.WithValue(context.Background(), "requestID", "req-123")
slogrus.WithContext(ctx).Info("Processing request")All logrus levels are supported:
slogrus.Trace("Very detailed information")
slogrus.Debug("Debug information")
slogrus.Info("General information")
slogrus.Warn("Warning message")
slogrus.Error("Error occurred")
slogrus.Fatal("Fatal error - will exit") // Calls os.Exit(1)
slogrus.Panic("Panic error - will panic") // Calls panic()Support for formatted strings:
slogrus.Infof("User %s logged in", username)
slogrus.Errorf("Failed to connect to %s:%d", host, port)
// With fields
slogrus.WithField("component", "auth").
Warnf("Failed login attempt for user %s", username)Use slog handlers for advanced output formatting:
// JSON output
logger := slogrus.NewJSONLogger(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
// Text output with options
logger := slogrus.NewTextLogger(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
AddSource: true, // Include source file information
})
// Custom handler
handler := slog.NewJSONHandler(file, &slog.HandlerOptions{
Level: slog.LevelWarn,
})
logger := slogrus.NewWithHandler(handler)For mixed usage scenarios and gradual migration:
// Create from existing slog logger
existingSlog := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger := slogrus.FromSlogLogger(existingSlog)
// Use logrus-style API
logger.WithField("component", "auth").Info("User logged in")
// Access underlying slog logger for advanced features
slogger := logger.GetSlogLogger()
slogger.Info("Direct slog usage",
"user", "john",
"action", "login",
slog.Group("metadata",
"ip", "192.168.1.1",
"agent", "curl/7.68.0",
),
)Basic formatter compatibility for easier migration:
// Switch to JSON format
slogrus.SetFormatter(&slogrus.JSONFormatter{})
// Switch to text format
slogrus.SetFormatter(&slogrus.TextFormatter{
DisableColors: true,
FullTimestamp: true,
})// Set global level
slogrus.SetLevel(slogrus.WarnLevel)
// Check if level is enabled
if slogrus.StandardLogger().IsLevelEnabled(slogrus.DebugLevel) {
// Expensive debug operation
slogrus.Debug("Detailed debug info")
}
// Parse level from string
level, err := slogrus.ParseLevel("info")
if err != nil {
log.Fatal(err)
}
slogrus.SetLevel(level)// Replace this
import "github.com/sirupsen/logrus"
// With this
import "github.com/choria-io/slogrus"Run your tests to ensure everything works as expected. The API is fully compatible.
Consider leveraging slog-specific features:
// Take advantage of slog's structured logging
logger := slogrus.NewJSONLogger(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelInfo,
AddSource: true,
})This library implements the complete logrus API:
- Types:
Logger,Entry,Level,Fields - Levels:
PanicLevel,FatalLevel,ErrorLevel,WarnLevel,InfoLevel,DebugLevel,TraceLevel - Methods: All logging methods (
Info,Debug,Error, etc.) - Formatted methods:
Infof,Debugf,Errorf, etc. - Line methods:
Infoln,Debugln,Errorln, etc. - Entry methods:
WithField,WithFields,WithError,WithContext,WithTime - Global functions: All package-level logging functions
- Configuration:
SetLevel,SetOutput,SetFormatter,SetReportCaller
By using Go's standard log/slog, this library benefits from:
- Optimized structured logging implementation
- Efficient level checking
- Minimal allocations for disabled log levels
- Native JSON encoding
While maintaining API compatibility, there are some behavioral differences:
- Formatters: Formatter interfaces are implemented but actual formatting is handled by slog handlers
- Hooks: Hook system is not implemented (use slog handlers instead)
- Output types: Only
io.Writeroutputs are supported (not syslog, etc.)
- Go 1.23 or later (for
log/slogsupport)
See the test files for comprehensive usage examples:
slogrus_test.go- Basic functionality testslogger_test.go- Logger-specific testsentry_test.go- Entry and structured logging testsinit_test.go- Initialization and global function tests
This was written with a focus on performance and low allocations, extensive benchmarks are included:
| Benchmark | Iterations | Time per Op | Bytes per Op | Allocs per Op |
|---|---|---|---|---|
| LoggerInfo | 1,907,768 | 617.4 ns/op | 16 B/op | 1 allocs/op |
| LoggerInfof | 1,743,793 | 692.6 ns/op | 32 B/op | 1 allocs/op |
| LoggerInfoln | 1,906,810 | 639.4 ns/op | 16 B/op | 1 allocs/op |
| LoggerWithField | 1,000,000 | 1,014 ns/op | 528 B/op | 6 allocs/op |
| LoggerWithFieldf | 1,000,000 | 1,090 ns/op | 544 B/op | 7 allocs/op |
| LoggerWithFields | 930,514 | 1,269 ns/op | 608 B/op | 6 allocs/op |
| LoggerWithFieldChaining | 772,938 | 1,551 ns/op | 1,289 B/op | 11 allocs/op |
| LoggerDebugDisabled | 494,086,148 | 2.428 ns/op | 0 B/op | 0 allocs/op |
| LoggerWithFieldDebugDisabled | 6,154,128 | 202.3 ns/op | 464 B/op | 4 allocs/op |
| GlobalInfo | 1,899,432 | 633.5 ns/op | 16 B/op | 1 allocs/op |
| GlobalWithField | 1,000,000 | 1,073 ns/op | 528 B/op | 6 allocs/op |
| LoggerInfoJSON | 2,346,199 | 508.7 ns/op | 16 B/op | 1 allocs/op |
| LoggerWithFieldJSON | 1,336,527 | 888.2 ns/op | 528 B/op | 6 allocs/op |
| LoggerWithError | 931,095 | 1,225 ns/op | 544 B/op | 7 allocs/op |
| ComplexLogging | 586,546 | 1,962 ns/op | 881 B/op | 7 allocs/op |
| MemoryAllocation/DirectLog | 1,874,785 | 637.9 ns/op | 16 B/op | 1 allocs/op |
| MemoryAllocation/WithOneField | 1,000,000 | 1,072 ns/op | 536 B/op | 6 allocs/op |
| MemoryAllocation/WithThreeFields | 750,601 | 1,572 ns/op | 1,297 B/op | 10 allocs/op |
| MemoryAllocation/WithFieldsMap | 934,754 | 1,342 ns/op | 616 B/op | 6 allocs/op |
| Throughput | 1,874,892 | 607.6 ns/op | 750 B/op (1.65 MB/s) | 6 allocs/op |
| LevelCheck | 1,000,000,000 | 0.3733 ns/op | 0 B/op | 0 allocs/op |
| FromSlogLogger | 1,820,745 | 657.6 ns/op | 24 B/op | 1 allocs/op |
| GetSlogLogger | 2,019,850 | 597.1 ns/op | 0 B/op | 0 allocs/op |