Custom Handlers
Build your own log output.
Custom Handlers is a free Go Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
When Built-In Handlers Are Not Enough
Text and JSON handlers cover most needs, but sometimes you want custom output: colorized terminals, sending to a metrics system, or redacting secrets. You build a custom Handler.
The Handler Interface
A handler implements four methods:
Enabled(ctx, level) boolHandle(ctx, record) errorWithAttrs(attrs) HandlerWithGroup(name) Handler
type Handler interface {
Enabled(context.Context, slog.Level) bool
Handle(context.Context, slog.Record) error
WithAttrs(attrs []slog.Attr) slog.Handler
WithGroup(name string) slog.Handler
}Enabled Controls Filtering
Enabled is called before building a record. Returning false lets slog skip the work entirely, so use it for level checks.
func (h *MyHandler) Enabled(_ context.Context, l slog.Level) bool {
return l >= slog.LevelInfo
}Handle Does the Work
Handle receives a slog.Record with the time, level, message, and attributes. You format and write it however you like.
func (h *MyHandler) Handle(_ context.Context, r slog.Record) error {
fmt.Printf("[%s] %s\n", r.Level, r.Message)
return nil
}Iterating Attributes
A Record exposes its attributes through r.Attrs, which calls your function for each one.
r.Attrs(func(a slog.Attr) bool {
fmt.Printf(" %s=%v\n", a.Key, a.Value)
return true // keep going
})WithAttrs and WithGroup
These return a copy of your handler carrying preset attributes or a group prefix. They support logger.With and slog.Group. A minimal handler can store and replay them, or for learning, return itself.
Wrapping Instead of Building
Often you do not need a full handler; wrap an existing one and only override behavior, like adding a constant attribute or redacting keys.
type RedactHandler struct{ slog.Handler }
func (h RedactHandler) Handle(ctx context.Context, r slog.Record) error {
// mutate r here, then delegate
return h.Handler.Handle(ctx, r)
}Use Case: Redaction
A redacting handler can scan attributes for sensitive keys like password or token and replace the value before delegating to a JSON handler.
Use Case: Routing
A custom handler can route by level: send Error logs to stderr and an alerting webhook, while Info goes to stdout. This keeps routing logic out of every call site.
Performance Notes
Handle may run on hot paths. Avoid allocations, do level checks in Enabled, and reuse buffers. The standard handlers use a pooled buffer internally for this reason.
Runnable: A Minimal Custom Handler
This self-contained program defines a tiny handler that prints level, message, and attributes, then logs through it.
package main
import (
"context"
"fmt"
"log/slog"
)
type Mini struct{}
func (Mini) Enabled(context.Context, slog.Level) bool { return true }
func (Mini) WithAttrs(a []slog.Attr) slog.Handler { return Mini{} }
func (Mini) WithGroup(string) slog.Handler { return Mini{} }
func (Mini) Handle(_ context.Context, r slog.Record) error {
fmt.Printf("%s: %s", r.Level, r.Message)
r.Attrs(func(a slog.Attr) bool {
fmt.Printf(" %s=%v", a.Key, a.Value)
return true
})
fmt.Println()
return nil
}
func main() {
l := slog.New(Mini{})
l.Info("hello", "user", "ada", "id", 7)
}Quick Check
Test your understanding of custom handlers.
Recap
You learned to build custom handlers:
- Implement
Enabled,Handle,WithAttrs,WithGroup - Do level checks in
Enabledfor performance - Iterate attributes with
r.Attrs - Often it is easier to wrap an existing handler than build from scratch
Frequently asked questions
Is the “Custom Handlers” lesson free?
Yes — the full text of “Custom Handlers” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.
What will I learn in “Custom Handlers”?
Build your own log output. You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Go Academy?
No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Custom Handlers” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Go Academy lesson?
Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Why Structured Logs
- slog Handlers
- Log Levels and Attributes
- Custom Handlers