Files
simplelog/json_handler.go
T
sneak f22461fe25
check / check (push) Successful in 36s
check / check (pull_request) Successful in 35s
Emit slog attributes from every handler (closes #19)
Handle never read the record's attributes, and WithAttrs and WithGroup
returned the receiver unchanged. The JSON and webhook handlers also marshaled
slog.Record itself, whose attributes are unexported.

Each handler now carries a handlerAttrs value, copied rather than mutated, so
sibling loggers cannot leak attributes into each other. JSON and webhook
output nest groups as objects; the console appends key=value pairs with dotted
group keys, quoted as slog.NewTextHandler quotes them. Logged values are never
written to. In JSON the record's own fields win a key collision, and a
repeated key keeps its last value unless both are groups, which merge; the
README documents both.

Deviation: a key containing invalid UTF-8 stays unquoted, unlike the stdlib:
#24.

Model: opus-5-5 (rebase, this message)
2026-09-28 10:34:46 +00:00

59 lines
1.4 KiB
Go

package simplelog
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"os"
)
// JSONHandler writes each log record to stdout as a JSON document.
type JSONHandler struct {
attrs handlerAttrs
}
// NewJSONHandler returns a new JSONHandler.
func NewJSONHandler() *JSONHandler {
return &JSONHandler{}
}
// Handle marshals the record, with its attributes, to one JSON object and
// writes it to stdout.
func (j *JSONHandler) Handle(_ context.Context, record slog.Record) error {
jsonData, err := json.Marshal(recordToMap(record, j.attrs))
if err != nil {
return err
}
_, _ = fmt.Fprintln(os.Stdout, string(jsonData))
return nil
}
// Enabled reports whether the handler processes records at the given
// level; it always returns true.
func (j *JSONHandler) Enabled(_ context.Context, _ slog.Level) bool {
return true
}
// WithAttrs returns a new handler that also emits attrs, qualified by the
// groups open now. The receiver is not modified.
func (j *JSONHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
if len(attrs) == 0 {
return j
}
return &JSONHandler{attrs: j.attrs.withAttrs(attrs)}
}
// WithGroup returns a new handler that nests later attributes in an
// object named after the group. An empty name returns the receiver.
func (j *JSONHandler) WithGroup(name string) slog.Handler {
if name == "" {
return j
}
return &JSONHandler{attrs: j.attrs.withGroup(name)}
}