cslog is a component-based logging library for Go, built on the standard log/slog. Zero dependencies, sensible defaults, and a small surface area.
- 🧩 Component-First: Scoped loggers for every subsystem created on the fly.
- 🎛️ Granular Control: Set per-component log levels to precisely filter noise.
- 🏷️ Customizable Keys: Use any attribute key for your components (e.g.,
module,service). - 📁 App-Friendly: Easy integration with YAML/JSON configs and data directories.
- ⚡ Performance: High-throughput NDJSON (Newline Delimited JSON) file sink.
- 🎨 Pretty Terminal: ANSI color-coded output for human-friendly debugging.
- 🔄 Atomic Rotation: Size-based file rotation with configurable backup counts.
- 📦 Background Gzip: Backup logs are compressed in a background goroutine.
- 🧹 Auto-Retention: Automatically clean up logs older than a specific number of days.
- 🔍 Trace Integration: Native support for
context.Contextto injecttrace_id.
go get github.com/0ceanslim/cslogRequires Go 1.24+.
package main
import (
"log/slog"
"github.com/0ceanslim/cslog"
)
func main() {
cslog.Initialize(
cslog.WithLevel(slog.LevelDebug),
cslog.WithFile("logs/app.log"),
cslog.WithStdout(true),
)
auth := cslog.Get("auth")
db := cslog.Get("db")
auth.Info("user logged in", "user", "alice", "ip", "10.0.0.5")
db.Warn("slow query", "ms", 812, "query", "SELECT * FROM events")
db.Error("connection refused", "host", "primary", "attempt", 3)
// Scoped logger — attach attrs once, reuse across calls.
req := cslog.Get("api").With("request_id", "r-9f3", "user", "alice")
req.Info("request received", "path", "/users/42")
req.Info("request completed", "status", 200, "ms", 18)
}The pretty handler is colorized in real terminals; ANSI codes are stripped here for readability.
2026-05-08T20:50:16-04:00 [INFO] [auth] user logged in user=alice ip=10.0.0.5
2026-05-08T20:50:16-04:00 [WARN] [db] slow query ms=812 query=SELECT * FROM events
2026-05-08T20:50:16-04:00 [ERROR] [db] connection refused host=primary attempt=3
2026-05-08T20:50:16-04:00 [INFO] [api] request received request_id=r-9f3 user=alice path=/users/42
2026-05-08T20:50:16-04:00 [INFO] [api] request completed request_id=r-9f3 user=alice status=200 ms=18
By default the file sink uses the same pretty format. Flip WithStructured(true) and you get NDJSON — one record per line, ready for jq, Loki, Datadog, or anything else that ingests JSON logs:
{"time":"2026-05-08T20:50:33-04:00","level":"INFO","msg":"user logged in","component":"auth","user":"alice","ip":"10.0.0.5"}
{"time":"2026-05-08T20:50:33-04:00","level":"WARN","msg":"slow query","component":"db","ms":812,"query":"SELECT * FROM events"}
{"time":"2026-05-08T20:50:33-04:00","level":"ERROR","msg":"connection refused","component":"db","host":"primary","attempt":3}
{"time":"2026-05-08T20:50:33-04:00","level":"INFO","msg":"request received","component":"api","request_id":"r-9f3","user":"alice","path":"/users/42"}
{"time":"2026-05-08T20:50:33-04:00","level":"INFO","msg":"request completed","component":"api","request_id":"r-9f3","user":"alice","status":200,"ms":18}Embed cslog.Config directly into your app's configuration to bind settings from YAML, JSON, or Environment variables:
type AppConfig struct {
DataDir string `yaml:"data_dir"`
Logging cslog.Config `yaml:"logging"`
}
func main() {
// ... load your appCfg ...
cslog.Initialize(
cslog.WithConfig(appCfg.Logging),
cslog.WithBaseDir(appCfg.DataDir), // Relative log paths will join with DataDir
)
}Fine-tune your logs by setting specific levels for different parts of your application:
cslog.Initialize(
cslog.WithLevel(slog.LevelInfo),
// Auth is stable, only log Warnings and Errors
cslog.WithComponentLevel("auth", slog.LevelWarn),
// DB is acting up, enable full Debug logging
cslog.WithComponentLevel("database", slog.LevelDebug),
)cslog.Initialize(
cslog.WithComponentKey("module"),
)
log := cslog.Get("auth") // Logs will include module=authcslog.Initialize(
cslog.WithFile("logs/production.log"),
cslog.WithStructured(true), // NDJSON
cslog.WithRotation(100, 10), // 100MB per file, 10 backups
cslog.WithCompression(true), // gzip rotated backups
cslog.WithRetention(30), // delete backups older than 30 days
)ctx := cslog.WithTraceID(r.Context(), requestID)
cslog.Get("api").InfoContext(ctx, "request received") // includes trace_idUse handlers.TestHandler to assert on emitted log records in your own tests:
import "github.com/0ceanslim/cslog/handlers"
th := handlers.NewTestHandler()
logger := slog.New(th).With("component", "auth")
logger.Info("login", "user", "alice")
records := th.Records() // []slog.Record with attrs already merged inMIT License. See LICENSE for details.
