go-chainedlog
A unified interface for common method-chaining log patterns in Go libraries.
Write your logging code once using a fluent, zerolog-style API and swap the underlying backend — zerolog, zap, or log/slog — without changing a single line of application code.
Installation
go get github.com/FDK0901/go-chainedlog
Supported Backends
| Package |
Backend |
Import Path |
chainedzerolog |
rs/zerolog |
github.com/FDK0901/go-chainedlog/impl/chainedzerolog |
chainedzap |
uber-go/zap |
github.com/FDK0901/go-chainedlog/impl/chainedzap |
chainedslog |
log/slog (stdlib) |
github.com/FDK0901/go-chainedlog/impl/chainedslog |
Quick Start
package main
import (
chainedlog "github.com/FDK0901/go-chainedlog"
"github.com/FDK0901/go-chainedlog/impl/chainedzerolog"
// or: "github.com/FDK0901/go-chainedlog/impl/chainedzap"
// or: "github.com/FDK0901/go-chainedlog/impl/chainedslog"
)
func main() {
// Pick one backend — the rest of your code stays the same.
var log chainedlog.Logger
// zerolog
log = chainedzerolog.NewZerolog(chainedzerolog.NewZerologBase())
// zap
// log = chainedzap.NewZap(chainedzap.NewZapBase())
// slog
// log = chainedslog.NewSlog(chainedslog.NewSlogBase())
log.Info().
String("service", "api").
Int("port", 8080).
Msg("server started")
}
Core Interfaces
Logger
Logger is the main entry point. It exposes leveled methods that return an Event builder.
type Logger interface {
Trace() Event
Debug() Event
Info() Event
Warn() Event
Error() Event
Panic() Event
Fatal() Event
With() Context
WithLevel(level Level) Event
SetWriters(ws ...io.Writer)
}
Event
Event is a fluent builder for a single log entry. Chain typed field methods and finalize with Msg, Msgf, or Send.
log.Error().
Err(err).
String("path", "/users").
Int("status", 500).
Msg("request failed")
Supported field types:
| Method |
Value Type |
Any |
any |
String |
string |
Int |
int |
Int64 |
int64 |
Uint64 |
uint64 |
Float64 |
float64 |
Bool |
bool |
Time |
time.Time |
Duration |
time.Duration |
Err |
error |
Stringer |
fmt.Stringer |
Strs |
[]string |
Ints |
[]int |
Dict |
map[string]any |
Context
Context creates a sub-logger with pre-set fields that are included in every subsequent log entry.
reqLog := log.With().
String("request_id", "abc-123").
String("user", "alice").
Logger()
reqLog.Info().Msg("processing request") // includes request_id and user
reqLog.Debug().Msg("fetching from cache") // includes request_id and user
Log Levels
Seven levels are provided, ordered from least to most severe:
| Level |
Constant |
| Trace |
chainedlog.TraceLevel |
| Debug |
chainedlog.DebugLevel |
| Info |
chainedlog.InfoLevel |
| Warn |
chainedlog.WarnLevel |
| Error |
chainedlog.ErrorLevel |
| Panic |
chainedlog.PanicLevel |
| Fatal |
chainedlog.FatalLevel |
Use WithLevel to emit a log entry at a dynamically chosen level:
log.WithLevel(chainedlog.WarnLevel).Msg("dynamic level warning")
Multi-Writer Support
Direct log output to multiple destinations using SetWriters. The console writer is always included by default.
f, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
log.SetWriters(f)
// Logs now go to both the console and app.log
Using Your Own Backend Instance
Each adapter accepts a pre-configured backend instance, giving you full control over the underlying logger's settings.
// zerolog — custom instance
zl := zerolog.New(os.Stdout).With().Timestamp().Logger().Level(zerolog.InfoLevel)
log := chainedzerolog.NewZerolog(zl)
// zap — custom instance
cfg := zap.NewProductionConfig()
zl, _ := cfg.Build()
log := chainedzap.NewZap(zl)
// slog — custom instance
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})
log := chainedslog.NewSlog(slog.New(handler))
License
Apache License 2.0 — see LICENSE for details.