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 (now), and is extensible to Logrus, Slog, and more.
β¨ Features
β
Structured logging with context.Context
β
Auto-generated trace_id per request
β
Custom fields via loggie.WithCustomField()
β
Middleware for Fiber / Gin / Echo
β
Pluggable backends (Zap, Logrus, Slog, etc.)
β
Fallback logger included (safe in any context)
β
Ready for Fx lifecycle and timeout-aware context.WithTimeout
π¦ Installation
go get github.com/ditthkr/loggie
π§± Architecture
ββββββββββββββββββββββ
β context.Context β
ββββββββββ¬ββββββββββββ
β
βββββββββΌβββββββββ
β loggie.Logger ββββ (interface)
βββββββββ¬βββββββββ
β
βββββββββββββββββΌβββββββββββββββββ
βΌ βΌ βΌ
ZapLogger LogrusLogger SlogLogger
(implemented) (planned) (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 (fully working)
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")
}
π§ͺ Sample Log Output:
{
"level": "info",
"msg": "Ping received",
"trace_id": "b4a3f5a0...",
"path": "/ping"
}
βοΈ Custom Fields (e.g. user_id)
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 |
WithCustomField(ctx, key, value) |
Adds any structured field |
DefaultLogger() |
Returns no-op fallback logger |
π Available Middleware
| 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 accept any loggie.Logger.
π Current and Planned Logger Adapters
| Logger |
Package / Status |
| Zap |
β
loggie.ZapLogger |
| Logrus |
π In progress |
| Slog |
π Planned for Go 1.21+ |
π§ͺ 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