Skip to content

0ceanSlim/cslog

Repository files navigation

cslog (Component Slog)

cslog logo

cslog is a component-based logging library for Go, built on the standard log/slog. Zero dependencies, sensible defaults, and a small surface area.


✨ Key Features

  • 🧩 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.Context to inject trace_id.

📦 Installation

go get github.com/0ceanslim/cslog

Requires Go 1.24+.


🚀 Quick Start

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)
}

What you get on stdout

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

What lands in the file

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}

🛠️ Advanced Usage

📁 Application Integration (YAML/JSON)

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
    )
}

🎛️ Per-Component Level Control

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),
)

🏷️ Custom Component Keys

cslog.Initialize(
    cslog.WithComponentKey("module"),
)

log := cslog.Get("auth") // Logs will include module=auth

📦 Production Storage

cslog.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
)

🔍 Trace IDs from Context

ctx := cslog.WithTraceID(r.Context(), requestID)
cslog.Get("api").InfoContext(ctx, "request received") // includes trace_id

🧪 Testing

Use 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 in

📄 License

MIT License. See LICENSE for details.

About

Component-Based Structured Logging

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages