Every developer has been there:
You’re on-call, an alert fires at 2 AM, and you’re staring at a wall of logs that look like this:
The Evolution of Logging 🧭
Logging in software has evolved a lot — but not every project has kept up:
1. Print Statements (the Stone Age): Just fmt.Println(“something happened”)
. Quick and dirty, but useless at scale.
2. Plain Logs with Timestamps (basic survival): Go’s log.Println
gives you a timestamp, but everything else is left to you. Debugging across services? Forget it.
3. Leveled Logging (finding your voice): Tools like INFO
, WARN
, and ERROR
levels made logs less noisy. You could finally filter out debug spam in production. But still no structure.
4. Structured Logging (the turning point): Instead of dumping plain text, logs became key–value pairs in JSON. Now you can query logs like data:
{ “severity”: “error”, “user_id”: 12345, “message”: “login failed” }
5. Context-Aware & Observability-Ready (where we are now): Modern systems aren’t just about logs — they’re about traces
, spans
, request IDs
, and correlating everything in your observability stack. If your logger doesn’t integrate with context.Context
, you’re already missing half the picture.
The Problem With Go’s Default Logging
Go’s built-in log package is fine for “hello world” projects, but once you’re in microservices land:
- It doesn’t support structured fields.
- It doesn’t know about
context.Context
. - It won’t give you trace IDs, caller info, or stack traces.
That gap inspired me to build something better. 🚀
Introducing the Logger Package 🎉
That’s where my Logger package comes in.
It’s a structured, context-aware logging solution for Go, built on top of Logrus, designed for production environments.
Think of it as logging upgraded for the cloud-native era:
- JSON logs out of the box.
- Automatic context propagation (
trace_id
,span_id
). - Caller + stack trace included when you need it.
- Customizable formatters and outputs.
- Clean API that feels natural in Go.
How It Works ⚙️
The Logger package is designed to feel simple but powerful. Here’s how you can bring it into your project.
1. Install
go get github.com/kittipat1413/go-common/framework/logger
2. Create a Logger
You can start with the default production-ready logger:
log := logger.NewDefaultLogger()
log.Info(context.Background(), "Application started", nil)
Or configure it yourself using the Config struct:
logConfig := logger.Config{
Level: logger.INFO,
Formatter: &logger.StructuredJSONFormatter{
TimestampFormat: time.RFC3339,
// PrettyPrint
// - true = pretty-printed JSON (indented, easier for humans to read)
// - false = compact JSON (single line, no indentation)
PrettyPrint: false,
},
Environment: "production",
ServiceName: "order-service",
}
log, _ := logger.NewLogger(logConfig)
3. Structured JSON Formatter
By default, logs are emitted in structured JSON:
4. Customize Keys and Metadata
Don’t like the default field names in your logs?
You can redefine field names using a FieldKeyFormatter
:
formatter := &logger.StructuredJSONFormatter{
TimestampFormat: time.RFC3339,
FieldKeyFormatter: func(key string) string {
switch key {
case logger.DefaultEnvironmentKey:
return "env"
case logger.DefaultServiceNameKey:
return "service"
default:
return key
}
},
}
Now your logs use env
and service
instead of the defaults.
5. Context-Aware Logging
Pass in a context.Context
with tracing info, and the logger automatically enriches logs with trace_id
and span_id
.
ctx, span := tracer.Start(context.Background(), "checkout")
defer span.End()
log.Info(ctx, "Processing checkout request", logger.Fields{
"user_id": 42,
})
Log output:
6. Error Logging with Stack Traces
When logging errors, the logger automatically includes stack traces for quick debugging:
err := errors.New("database connection failed")
log.Error(ctx, "Failed to query user", err, logger.Fields{
"query": "SELECT * FROM users",
})
Log output:
Final Thoughts ✨
This logger has already helped me a lot in my own projects — from cleaning up noisy logs to making debugging at 2 AM way less painful. That’s why I decided to share it with the community.
If you give it a try and it makes your life easier too, that’s a win.
And if you have suggestions, ideas, or improvements, I’d love to hear them. Open an issue or drop a comment — feedback is always welcome.
👉 Explore the examples.
👉 Or check out the documentation on pkg.go.dev.
Top comments (0)