Serilog-inspired structured logging with message templates,
rich formatting, and native Seq support.
log.Info("User {UserId} logged in from {IP}", userId, ip)
log.Info("Order {@Order} created", order)
log.Info("Processing time: {Duration:F2}ms", 123.456)
Properties are extracted from templates and preserved throughout the pipeline. Templates serve as both human-readable messages and event types.
userLogger := mtlog.ForType[User](logger)
userLogger.Info("User created")
// SourceContext: "User"
orderLogger := mtlog.ForType[OrderService](logger)
// Automatic categorization by type
Automatic source context from Go types. No more string constants. Perfect for service-oriented architectures.
// Simple logging: 0 allocations
log.Info("Application started")
// Below minimum level: 0 allocations
log.Debug("This won't allocate")
Carefully optimized for the common path. Simple messages and filtered events allocate zero bytes.
// Works with slog
slogger := mtlog.NewSlogLogger(...)
slog.SetDefault(slogger)
// Works with logr (Kubernetes)
import mtlogr "github.com/willibrandon/mtlog/adapters/logr"
logrLogger := mtlogr.NewLogger(...)
Drop-in adapters for Go's standard slog and Kubernetes logr. Use mtlog's power with existing code.
Carefully optimized for the common path with zero allocations for simple operations.
Benchmarked with go test -bench . -benchmem
on AMD Ryzen 9 9950X, Go 1.23
go get mtlog.dev
package main
import (
"mtlog.dev"
"mtlog.dev/core"
)
func main() {
// Create a logger with console output
log := mtlog.New(
mtlog.WithConsole(),
mtlog.WithMinimumLevel(core.InformationLevel),
)
// Simple logging
log.Info("Application started")
// Message templates with properties
userId := 123
log.Info("User {UserId} logged in", userId)
// Type-based logging
userLogger := mtlog.ForType[User](log)
userLogger.Info("User operation completed")
}