A Go linter that catches slog key-value pairs split across lines.
Go formatters like gofmt, gofumpt, and golines aren't slog-aware. They'll happily break your key-value pairs across lines, making log calls harder to read:
// This is what happens after golines gets its hands on your code
slog.Info("request completed",
"method",
r.Method,
"status",
code,
"duration",
elapsed,
)
// This is what you actually wanted
slog.Info("request completed",
"method", r.Method,
"status", code,
"duration", elapsed,
)slogfmt finds these splits and fixes them.
go install github.com/tomarrell/slogfmt/cmd/slogfmt@latest# Check for split pairs
slogfmt ./...
# Fix them automatically
slogfmt -fix ./...
# Optionally enforce closing paren placement
slogfmt -closingparen=newline ./... # ) on its own line
slogfmt -closingparen=sameline ./... # ) on last arg lineWith -closingparen=newline:
// flagged
slog.Info("msg",
"method", r.Method,
"status", code)
// fixed
slog.Info("msg",
"method", r.Method,
"status", code,
)With -closingparen=sameline:
// flagged
slog.Info("msg",
"method", r.Method,
"status", code,
)
// fixed
slog.Info("msg",
"method", r.Method,
"status", code)slog.Info,slog.Warn,slog.Error,slog.Debugand theirContextvariantsslog.Log,slog.With,slog.Group- Method calls on
*slog.Logger(e.g.logger.Info(...))
slog.Attr arguments like slog.String("key", "val") are skipped — those are single values, not key-value pairs.
sloglint (available in golangci-lint) handles slog call structure: one pair per line, no mixed args, key naming conventions, etc.
It won't catch a key split from its value though. golines doesn't know that "method" and r.Method belong together, so it puts them on separate lines. sloglint doesn't flag that. slogfmt does.
If you use both, run slogfmt -fix after golines in your pipeline.
Built on Go's analysis framework. It uses type information to identify slog calls (not just name matching), then checks whether each key and its value are on the same line. When they aren't, it reports a diagnostic with a suggested fix.
The fix collapses everything between the end of the key and the start of the value into , . Comments between key and value get removed. The value's own formatting (multiline maps, struct literals, etc.) is left alone.
MIT