In this simple example we are going to introduce two custom log levels (TRACE and PANIC) using Golang's Slog package. An example usage in the code is: slog.Log(ctx, logger.LevelPanic, ...


package logger

import (
"log/slog"
"os"
"time"
)

const (
// Auto assigns `DEBUG-4` as label.
LevelTrace = slog.Level(-8)
// Auto assigns `ERROR+4` as label.
LevelPanic = slog.Level(12)
)

var levels = map[slog.Leveler]string{
LevelTrace: "TRACE",
LevelPanic: "PANIC",
}

func Configure(severity string) {
for level, label := range levels {
if label == severity {
severity = level.Level().String()

break
}
}

var level slog.Level
if err := level.UnmarshalText([]byte(severity)); err != nil {
level = slog.LevelError
}

slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
Level: level,
ReplaceAttr: func(groups []string, attr slog.Attr) slog.Attr {
if attr.Key == slog.TimeKey {
attr.Value = slog.StringValue(attr.Value.Time().Format(time.RFC3339))
}

if attr.Key == slog.MessageKey {
attr.Key = "message"
}

if attr.Key == slog.LevelKey {
level := attr.Value.Any().(slog.Level)
label, ok := levels[level]
if !ok {
label = level.String()
}

attr.Value = slog.StringValue(label)
}

return attr
},
})))
}

$ go run -race main.go 
{"time":"2024-08-30T19:00:28+01:00","level":"TRACE","message":"trace msg"}
{"time":"2024-08-30T19:00:28+01:00","level":"DEBUG","message":"debug msg"}
{"time":"2024-08-30T19:00:28+01:00","level":"INFO","message":"info msg"}
{"time":"2024-08-30T19:00:28+01:00","level":"WARN","message":"warn msg"}
{"time":"2024-08-30T19:00:28+01:00","level":"ERROR","message":"error msg"}
{"time":"2024-08-30T19:00:28+01:00","level":"PANIC","message":"panic msg"}