Getting Started
go-logger keeps the main logging API intentionally small while allowing sinks to adapt entries to different outputs.
Core pieces
logger.Newcreates a logger with a JSON console sink by default.
logger.Withderives a logger with additional bound fields.
logger.RegisterSinkattaches new sinks at runtime.
logger.SetLevelchanges the minimum emitted log level.
Included sinks
ConsoleSinkwrites compact JSON lines.
CLEFSinkwrites Compact Log Event Format (CLEF) JSON lines, compatible with Serilog’sRenderedCompactJsonFormatter. Useful when Go services share a log pipeline with C# services and field names must be consistent across both.
RotatingFileSinkwrites JSON lines to rolling log files.
PrometheusSinktracks counts by level and exposes a scrape handler.
TelegramSinkforwards selected log entries to a Telegram chat.
CLEF sink
CLEFSink outputs one JSON object per line using the CLEF field conventions:
| Field | Description |
|---|---|
@t |
Timestamp in RFC3339Nano (UTC) |
@l |
Level string — omitted for Information per the CLEF specification |
@m |
Rendered message |
| others | Structured fields flattened at root level |
Level mapping: debug → Debug, warn → Warning, error → Error. Information produces no @l field.
sink := logger.NewCLEFSink(nil) // nil → os.Stdout
lg := logger.New(logger.WithSink(sink))
lg.Warn("disk space low", logger.Field{Key: "free_gb", Value: 2})
// {"@t":"2026-03-13T10:00:00Z","@l":"Warning","@m":"disk space low","free_gb":2}
lg.Info("request handled", logger.Field{Key: "status", Value: 200})
// {"@t":"2026-03-13T10:00:01Z","@m":"request handled","status":200}
Operational note
The logger itself keeps sink delivery best-effort. Sinks still return errors so callers and tests can validate integration behavior when needed.
Custom-sink-only logger
By default logger.New adds a ConsoleSink (JSON lines to stdout). When a service uses a different sink as its sole output — e.g. CLEFSink for Grafana Alloy — the default sink produces duplicate output in a different format.
Use WithoutDefaultSink() before WithSink to start from a clean slate:
// CLEF-only output (e.g., for Grafana Alloy)
lg := logger.New(
logger.WithoutDefaultSink(),
logger.WithSink(logger.NewCLEFConsoleSink()),
)