loggie π§ β‘οΈ β Context-Aware Logger for Go
Context-aware, pluggable logger for Go web applications.
No more passing logger through every function β just use context.Context.
π What is loggie?
loggie helps you embed a structured logger inside context.Context, so you can log from any layer β service, repository, or handler β with a consistent trace_id, user_id, or any custom field.
It supports Zap, Logrus (new!), and is ready for OpenTelemetry (OTEL).
β¨ Features
β
Structured logging via context.Context
β
Auto-generated trace_id per request
β
OTEL-compatible (detects trace_id from OpenTelemetry spans)
β
Custom fields (e.g. user_id, order_id)
β
Middleware for Fiber / Gin / Echo
β
Pluggable backends: Zap, Logrus, Slog (soon)
β
Fallback logger included (safe anywhere)
β
Works with Fx lifecycle & context.WithTimeout
π¦ Installation
go get github.com/ditthkr/loggie
π§± Architecture
ββββββββββββββββββββββ
β context.Context β
ββββββββββ¬ββββββββββββ
β
βββββββββΌβββββββββ
β loggie.Logger ββββ (interface)
βββββββββ¬βββββββββ
β
βββββββββββββββββΌβββββββββββββββββ
βΌ βΌ βΌ
ZapLogger LogrusLogger SlogLogger
(β
ready) (β
ready) (π planned)
π Logger Interface
type Logger interface {
Info(msg string, fields ...any)
Error(msg string, fields ...any)
With(fields ...any) Logger
}
You can plug any logger backend by implementing this interface.
βοΈ Middleware Usage
Fiber + Zap
import (
"github.com/ditthkr/loggie"
"github.com/ditthkr/loggie/middleware/fiberlog"
"go.uber.org/zap"
"github.com/gofiber/fiber/v3"
)
func main() {
rawLogger, _ := zap.NewProduction()
defer rawLogger.Sync()
adapter := &loggie.ZapLogger{L: rawLogger}
app := fiber.New()
app.Use(fiberlog.Middleware(adapter))
app.Get("/ping", func(c *fiber.Ctx) error {
log := loggie.FromContext(c.UserContext())
log.Info("Ping received", "path", c.Path())
return c.SendString("pong")
})
app.Listen(":8080")
}
Fiber + Logrus
import (
"github.com/sirupsen/logrus"
"github.com/ditthkr/loggie/logruslogger"
"github.com/ditthkr/loggie/middleware/fiberlog"
)
func main() {
logger := logrus.New()
adapter := &logruslogger.LogrusLogger{L: logrus.NewEntry(logger)}
app := fiber.New()
app.Use(fiberlog.Middleware(adapter))
app.Get("/ping", func(c *fiber.Ctx) error {
log := loggie.FromContext(c.UserContext())
log.Info("Ping received", "path", c.Path())
return c.SendString("pong")
})
app.Listen(":8080")
}
π OTEL Support (OpenTelemetry)
If you're using OpenTelemetry, loggie will automatically extract trace_id from span context
via go.opentelemetry.io/otel/trace.
No config required β just pass the OTEL-injected context.Context.
ctx := r.Context() // contains OTEL span
log := loggie.FromContext(ctx)
log.Info("Received payment webhook")
// trace_id will match what's in OTEL system (Jaeger, Tempo, etc)
βοΈ Custom Fields
ctx = loggie.WithCustomField(ctx, "user_id", 42)
log := loggie.FromContext(ctx)
log.Info("Order created")
π€ Output:
{
"msg": "Order created",
"trace_id": "abc-xyz",
"user_id": 42
}
π§° Utilities
| Function |
Purpose |
FromContext(ctx) |
Retrieves logger from context |
WithLogger(ctx, logger) |
Injects a logger |
WithTraceID(ctx) |
Adds trace_id to context |
TraceID(ctx) |
Retrieves trace_id (OTEL-aware) |
WithCustomField(ctx, key, val) |
Adds structured field |
DefaultLogger() |
No-op fallback logger |
π Middleware Support
| Framework |
Import Path |
Function |
| Fiber |
github.com/ditthkr/loggie/middleware/fiberlog |
fiberlog.Middleware() |
| Gin |
github.com/ditthkr/loggie/middleware/ginlog |
ginlog.Middleware() |
| Echo |
github.com/ditthkr/loggie/middleware/echolog |
echolog.Middleware() |
All middlewares are generic and support any loggie.Logger.
π Logger Adapters
| Logger |
Status |
Package |
| Zap |
β
Supported |
loggie.ZapLogger |
| Logrus |
β
Supported |
loggie/logruslogger |
| Slog |
π Planned |
loggie/slogger (coming soon) |
π§ͺ Testing & Fallbacks
Even without injecting a logger, loggie will still work with a safe no-op fallback:
log := loggie.FromContext(context.Background())
log.Info("This is safe even without a logger")
π License
MIT Β© 2025 @ditthkr