xlog is a thin wrapper around the standard library's log/slog
package. It trades a little of slog's flexibility for a small, opinionated
API that is quick to wire up in applications and easy to stub out in tests.
It was originally developed as part of digineo/texd and extracted into its own module for reuse.
- A minimal
Loggerinterface withDebug/Info/Warn/Error/FatalandWithmethods. - Functional options for configuration (
New(...Option)). - Text or JSON output using the standard library's handlers — the core module has no third-party dependencies.
- A pluggable handler backend (
UseHandler): opt into a richer handler without the core module depending on it. A colorized text backend is shipped as the optionalxlog/slogorsub-module. - Convenience attribute constructors (
String,Int,Error, …) so you don't need to importlog/slogalongsidexlog. - Test helpers: a no-op
Discardlogger and aMockClockoption for deterministic timestamps.
go get github.com/digineo/xlogRequires Go 1.26 or later.
package main
import (
"log/slog"
"github.com/digineo/xlog"
)
func main() {
log, err := xlog.New(
xlog.AsText(),
xlog.Leveled(slog.LevelDebug),
)
if err != nil {
panic(err)
}
log.Info("service started", xlog.String("addr", ":8080"))
if err := run(); err != nil {
log.Error("service failed", xlog.Error(err))
}
}| Option | Effect |
|---|---|
WriteTo(w) |
Write log output to w (default: os.Stdout). |
Leveled(l) |
Set the minimum log level from a slog.Level. |
LeveledString(s) |
Set the level from a string ("debug", "info", …). |
AsText() |
Emit human-readable key=value lines (stdlib text handler). |
AsJSON() |
Emit one JSON object per log record. |
WithSource() |
Include source file and line in each record. |
Discard() |
Mute the logger entirely. |
MockClock(t) |
Use a fixed timestamp — handy in tests. |
UseHandler(kind, f) |
Install a custom slog.Handler backend (see below). |
Exactly one handler option (AsText(), AsJSON(), Discard(), or a
custom UseHandler) selects the output format; New returns an error if
none is given, or if two options request different kinds — e.g. passing
both AsText() and AsJSON() is a conflict.
The core module intentionally ships without a colorized handler so it stays
dependency-free. Colorized, human-friendly text output lives in the
optional xlog/slogor sub-module, backed by slogor:
import (
"log/slog"
"github.com/digineo/xlog"
"github.com/digineo/xlog/slogor"
)
log, err := xlog.New(
slogor.Colorized(),
xlog.Leveled(slog.LevelInfo),
)slogor.Colorized() produces text output, so it implies xlog.AsText()
and conflicts with xlog.AsJSON(). Install it with:
go get github.com/digineo/xlog/slogorBecause it is a separate module, projects that don't use it never pull in
the slogor or go-isatty dependencies. The same UseHandler extension point
lets you wire up any other slog.Handler backend.
Use NewDiscard() to obtain a logger that swallows everything, or combine
MockClock with WriteTo to assert on deterministic output:
var buf bytes.Buffer
log, _ := xlog.New(
xlog.AsText(),
xlog.WriteTo(&buf),
xlog.MockClock(time.Unix(1650000000, 0).UTC()),
)
log.Info("hello", xlog.String("who", "world"))
// buf now holds a line with a fixed timestampMIT — see LICENSE.