110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package slogzerolog
|
|
|
|
import (
|
|
"context"
|
|
|
|
"log/slog"
|
|
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
slogcommon "github.com/samber/slog-common"
|
|
)
|
|
|
|
type Option struct {
|
|
// log level (default: debug)
|
|
// you can use ZeroLogLeveler to retrieve the level from the global zerolog instance or a custom one
|
|
Level slog.Leveler
|
|
|
|
// optional: zerolog logger (default: zerolog.Logger)
|
|
Logger *zerolog.Logger
|
|
// optional: don't add timestamp to record
|
|
NoTimestamp bool
|
|
|
|
// optional: customize json payload builder
|
|
Converter Converter
|
|
// optional: fetch attributes from context
|
|
AttrFromContext []func(ctx context.Context) []slog.Attr
|
|
|
|
// optional: see slog.HandlerOptions
|
|
AddSource bool
|
|
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
|
|
}
|
|
|
|
func (o Option) NewZerologHandler() slog.Handler {
|
|
if o.Level == nil {
|
|
o.Level = slog.LevelDebug
|
|
}
|
|
|
|
if o.Logger == nil {
|
|
// should be selected lazily ?
|
|
o.Logger = &log.Logger
|
|
}
|
|
|
|
if o.AttrFromContext == nil {
|
|
o.AttrFromContext = []func(ctx context.Context) []slog.Attr{}
|
|
}
|
|
|
|
return &ZerologHandler{
|
|
option: o,
|
|
attrs: []slog.Attr{},
|
|
groups: []string{},
|
|
}
|
|
}
|
|
|
|
var _ slog.Handler = (*ZerologHandler)(nil)
|
|
|
|
type ZerologHandler struct {
|
|
option Option
|
|
attrs []slog.Attr
|
|
groups []string
|
|
}
|
|
|
|
func (h *ZerologHandler) Enabled(_ context.Context, level slog.Level) bool {
|
|
return level >= h.option.Level.Level()
|
|
}
|
|
|
|
func (h *ZerologHandler) Handle(ctx context.Context, record slog.Record) error {
|
|
converter := DefaultConverter
|
|
if h.option.Converter != nil {
|
|
converter = h.option.Converter
|
|
}
|
|
|
|
level := LogLevels[record.Level]
|
|
fromContext := slogcommon.ContextExtractor(ctx, h.option.AttrFromContext)
|
|
args := converter(h.option.AddSource, h.option.ReplaceAttr, append(h.attrs, fromContext...), h.groups, &record)
|
|
|
|
event := h.option.Logger.
|
|
WithLevel(level).
|
|
Ctx(ctx).
|
|
CallerSkipFrame(3)
|
|
|
|
if !h.option.NoTimestamp {
|
|
event.Time(zerolog.TimestampFieldName, record.Time)
|
|
}
|
|
|
|
event.Fields(args).Msg(record.Message)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h *ZerologHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
return &ZerologHandler{
|
|
option: h.option,
|
|
attrs: slogcommon.AppendAttrsToGroup(h.groups, h.attrs, attrs...),
|
|
groups: h.groups,
|
|
}
|
|
}
|
|
|
|
func (h *ZerologHandler) WithGroup(name string) slog.Handler {
|
|
// https://cs.opensource.google/go/x/exp/+/46b07846:slog/handler.go;l=247
|
|
if name == "" {
|
|
return h
|
|
}
|
|
|
|
return &ZerologHandler{
|
|
option: h.option,
|
|
attrs: h.attrs,
|
|
groups: append(h.groups, name),
|
|
}
|
|
}
|