A Go linter that checks zerolog logging chains for missing context propagation.
zerologlintctx detects cases where a context.Context is available in function parameters but not properly passed to zerolog logging chains via .Ctx(ctx).
Go 1.27 or later. The analyzed code may target any Go version.
Using mise (macOS/Linux/Windows)
Recommended. zerologlintctx is installable directly from GitHub Releases via mise's github backend — no extra registry required, and no Go toolchain needed because the binaries are prebuilt:
mise use "github:mpyw/zerologlintctx@0.12.0"
zerologlintctx ./...Run it in the project root. It pins the version in the project's mise.toml, so every checkout and CI run the same one:
[tools]
"github:mpyw/zerologlintctx" = "0.12.0"Add -g to install it for every project on your machine instead.
Important
The go-based methods below build zerologlintctx from source, which requires Go 1.27 or later (see Requirements). go tool also needs Go 1.24+ on PATH, which is where tool directives were introduced.
Using go tool
# Add to go.mod as a tool dependency
go get -tool github.com/mpyw/zerologlintctx/cmd/zerologlintctx@latest
# Run via go tool
go tool zerologlintctx ./...Using go install
go install github.com/mpyw/zerologlintctx/cmd/zerologlintctx@latest
zerologlintctx ./...Using go vet
Since zerologlintctx has no custom flags, it can be run via go vet:
go install github.com/mpyw/zerologlintctx/cmd/zerologlintctx@latest
go vet -vettool=$(which zerologlintctx) ./...Using go run
go run github.com/mpyw/zerologlintctx/cmd/zerologlintctx@latest ./...Caution
To prevent supply chain attacks, pin to a specific version tag instead of @latest in CI/CD pipelines (e.g., @v0.9.0).
Downloading the tarball directly (macOS/Linux/Windows)
No package manager? Grab the archive for your platform from GitHub Releases:
export VERSION=0.0.0
export OS=linux # or darwin
export ARCH=amd64 # or arm64
export BASE_URL="https://github.com/mpyw/zerologlintctx/releases/download/v${VERSION}"
# Download the archive and the release's checksum list
curl -LO "${BASE_URL}/zerologlintctx_${VERSION}_${OS}_${ARCH}.tar.gz"
curl -LO "${BASE_URL}/checksums.txt"
# Verify before installing (use `shasum -a 256 -c` on macOS)
sha256sum --ignore-missing -c checksums.txt
tar xzf "zerologlintctx_${VERSION}_${OS}_${ARCH}.tar.gz"
sudo mv zerologlintctx /usr/local/bin/On Windows, download zerologlintctx_${VERSION}_windows_${ARCH}.zip and extract zerologlintctx.exe somewhere on your PATH.
Running inside golangci-lint
zerologlintctx is not bundled with golangci-lint. Build a golangci-lint binary that holds it as a module plugin. Write .custom-gcl.yml:
version: v2.13.1 # the golangci-lint release to build
plugins:
- module: github.com/mpyw/zerologlintctx
import: github.com/mpyw/zerologlintctx/plugin
version: v0.12.0Turn it on in .golangci.yml. It takes no settings, and any key under settings stops the run. To skip test files, use golangci-lint's run.tests: false instead of -test=false:
version: "2"
linters:
enable:
- zerologlintctx
settings:
custom:
zerologlintctx:
type: module
description: Checks that zerolog chains carry the context.Then build and run it:
golangci-lint custom # writes ./custom-gcl
./custom-gcl run ./...| Flag | Default | Description |
|---|---|---|
-test |
true |
Analyze test files (*_test.go) — built-in driver flag |
Generated files (containing // Code generated ... DO NOT EDIT.) are always excluded and cannot be opted in.
# Exclude test files from analysis
zerologlintctx -test=false ./...Detects zerolog logging chains missing .Ctx(ctx):
func handler(ctx context.Context, log zerolog.Logger) {
// Bad: missing .Ctx(ctx)
log.Info().Str("key", "value").Msg("hello")
// Good: includes .Ctx(ctx)
log.Info().Ctx(ctx).Str("key", "value").Msg("hello")
// Also good: context from log.Ctx() or zerolog.Ctx()
log.Ctx(ctx).Info().Str("key", "value").Msg("hello")
}Detects direct logging calls that bypass the Event chain and cannot propagate context:
func handler(ctx context.Context, log zerolog.Logger) {
// Bad: bypasses Event chain, context cannot be set
log.Print("hello")
log.Printf("hello %s", name)
}The analyzer uses SSA (Static Single Assignment) form to track Event values through variable assignments, conditionals, and closures, ensuring accurate detection even in complex code patterns.
Suppress warnings for a specific line:
func handler(ctx context.Context, log zerolog.Logger) {
//zerologlintctx:ignore // intentionally not passing context
log.Info().Msg("background task")
}The comment can be on the same line or the line above. Write a reason after //. A reason after - also works, for compatibility.
Any other comment that starts with zerologlintctx:, such as //zerologlintctx:bogus, does nothing and is reported. So is an ignore that suppresses nothing.
- Zero false positives - Prefer missing issues over false alarms
- Type-safe analysis - Uses
go/typesfor accurate detection - SSA-based tracking - Uses SSA form to track Event values through assignments and closures
- Nested function support - Correctly tracks context through closures
- Architecture - Internal design and detection logic
- AGENTS.md - Repository instructions for contributors and coding agents
- zerologlint - General zerolog linting rules
- contextcheck - Detects
context.Background()/context.TODO()usage and missing context parameters
zerologlintctx is complementary to these tools:
zerologlintprovides general zerolog best practicescontextcheckwarns about creating new contexts when one should be propagatedzerologlintctxspecifically warns about not using an available context in zerolog chains
MIT