diff --git a/README.md b/README.md index 0b48be0..07157e1 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,22 @@ [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/phsym/zeroslog) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/phsym/zeroslog/master/LICENSE) [![Build](https://github.com/phsym/zeroslog/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/phsym/zeroslog/actions/workflows/go.yml) A zerolog handler for slog + +## Example +```go +package main + +import ( + "log/slog" + "github.com/phsym/zeroslog" +) + +func main() { + logger := slog.New( + zeroslog.NewJsonHandler(os.Stderr, &zeroslog.HandlerOptions{Level: slog.LevelDebug}) + ) + slog.SetDefault(logger) + slog.Info("Hello world!", "foo", "bar") +} + +``` \ No newline at end of file diff --git a/bench_test.go b/bench_test.go index de5d973..41fd34d 100644 --- a/bench_test.go +++ b/bench_test.go @@ -21,7 +21,7 @@ var ( handlers = map[string]slog.Handler{ "std-text": slog.NewTextHandler(io.Discard, &slog.HandlerOptions{Level: slog.LevelDebug}), "std-json": slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{Level: slog.LevelDebug}), - "zerolog": NewZerologJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug}), + "zerolog": NewJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug}), "dummy": &DummyHandler{}, } diff --git a/internal_bench_test.go b/internal_bench_test.go index 8c7e9ea..738bc82 100644 --- a/internal_bench_test.go +++ b/internal_bench_test.go @@ -38,7 +38,7 @@ func BenchmarkDummy(b *testing.B) { func BenchmarkSlogZerolog(b *testing.B) { ctx := context.Background() - l := slog.New(NewZerologJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug})) + l := slog.New(NewJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug})) l = l.With("foo", "bar") b.ResetTimer() f := func(b *testing.B) { @@ -59,7 +59,7 @@ func BenchmarkSlogZerolog(b *testing.B) { func BenchmarkSlogZerolog_HandlerWithRec(b *testing.B) { ctx := context.Background() - h := slog.Handler(NewZerologJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug})) + h := slog.Handler(NewJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug})) h = h.WithAttrs([]slog.Attr{slog.String("foo", "bar")}) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -71,7 +71,7 @@ func BenchmarkSlogZerolog_HandlerWithRec(b *testing.B) { func BenchmarkSlogZerolog_HandlerWithRecAndCaller(b *testing.B) { ctx := context.Background() - h := slog.Handler(NewZerologJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug})) + h := slog.Handler(NewJsonHandler(io.Discard, &HandlerOptions{Level: slog.LevelDebug})) h = h.WithAttrs([]slog.Attr{slog.String("foo", "bar")}) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/zerolog.go b/zerolog.go index e695ef9..d0a8049 100644 --- a/zerolog.go +++ b/zerolog.go @@ -37,48 +37,48 @@ type zerologHandler interface { handleGroup(group string, rec *slog.Record, e *zerolog.Event) } -// ZerologHandler is an slog.Handler implementation that uses zerolog to process slog.Record. -type ZerologHandler struct { +// Handler is an slog.Handler implementation that uses zerolog to process slog.Record. +type Handler struct { opts *HandlerOptions logger zerolog.Logger } -var _ zerologHandler = (*ZerologHandler)(nil) +var _ zerologHandler = (*Handler)(nil) -// NewZerologHandler creates a *ZerologHandler implementing slog.Handler. +// NewHandler creates a *ZerologHandler implementing slog.Handler. // It wraps a zerolog.Logger to which log records will be sent. // // Unlesse opts.Level is not nil, the logger level is used to filter out records, otherwise // opts.Level is used. // // The provided logger instance must be configured to not send timestamps or caller information. -func NewZerologHandler(logger zerolog.Logger, opts *HandlerOptions) *ZerologHandler { +func NewHandler(logger zerolog.Logger, opts *HandlerOptions) *Handler { if opts == nil { opts = new(HandlerOptions) } - return &ZerologHandler{ + return &Handler{ opts: opts, logger: logger, } } -// NewZerologJsonHandler is a shortcut to calling +// NewJsonHandler is a shortcut to calling // -// NewZerologHandler(zerolog.New(out).Level(zerolog.InfoLevel), opts) -func NewZerologJsonHandler(out io.Writer, opts *HandlerOptions) *ZerologHandler { - return NewZerologHandler(zerolog.New(out).Level(zerolog.InfoLevel), opts) +// NewHandler(zerolog.New(out).Level(zerolog.InfoLevel), opts) +func NewJsonHandler(out io.Writer, opts *HandlerOptions) *Handler { + return NewHandler(zerolog.New(out).Level(zerolog.InfoLevel), opts) } -// NewZerologConsoleHandler creates a new zerolog handler, wrapping out into a zerolog.ConsoleWriter. +// NewConsoleHandler creates a new zerolog handler, wrapping out into a zerolog.ConsoleWriter. // It's a shortcut to calling // -// NewZerologHandler(zerolog.New(&zerolog.ConsoleWriter{Out: out, TimeFormat: time.DateTime}).Level(zerolog.InfoLevel), opts) -func NewZerologConsoleHandler(out io.Writer, opts *HandlerOptions) *ZerologHandler { - return NewZerologJsonHandler(&zerolog.ConsoleWriter{Out: out, TimeFormat: time.DateTime}, opts) +// NewHandler(zerolog.New(&zerolog.ConsoleWriter{Out: out, TimeFormat: time.DateTime}).Level(zerolog.InfoLevel), opts) +func NewConsoleHandler(out io.Writer, opts *HandlerOptions) *Handler { + return NewJsonHandler(&zerolog.ConsoleWriter{Out: out, TimeFormat: time.DateTime}, opts) } // Enabled implements slog.Handler. -func (h *ZerologHandler) Enabled(_ context.Context, lvl slog.Level) bool { +func (h *Handler) Enabled(_ context.Context, lvl slog.Level) bool { if h.opts.Level != nil { return lvl >= h.opts.Level.Level() } @@ -86,7 +86,7 @@ func (h *ZerologHandler) Enabled(_ context.Context, lvl slog.Level) bool { } // startLog creates a new logging event at the given level. -func (h *ZerologHandler) startLog(lvl slog.Level) *zerolog.Event { +func (h *Handler) startLog(lvl slog.Level) *zerolog.Event { logger := h.logger if h.opts.Level != nil { logger = h.logger.Level(zerologLevel(h.opts.Level.Level())) @@ -95,7 +95,7 @@ func (h *ZerologHandler) startLog(lvl slog.Level) *zerolog.Event { } // endLog finalize the log event by appending record source, timestamp and message before sending it. -func (h *ZerologHandler) endLog(rec *slog.Record, evt *zerolog.Event) { +func (h *Handler) endLog(rec *slog.Record, evt *zerolog.Event) { if h.opts.AddSource && rec.PC > 0 { frame, _ := runtime.CallersFrames([]uintptr{rec.PC}).Next() evt.Str(zerolog.CallerFieldName, fmt.Sprintf("%s:%d", frame.File, frame.Line)) @@ -106,14 +106,14 @@ func (h *ZerologHandler) endLog(rec *slog.Record, evt *zerolog.Event) { } // handleGroup handles records comming from a child group. -func (h *ZerologHandler) handleGroup(group string, rec *slog.Record, dict *zerolog.Event) { +func (h *Handler) handleGroup(group string, rec *slog.Record, dict *zerolog.Event) { evt := h.startLog(rec.Level) evt.Dict(group, dict) h.endLog(rec, evt) } // Handle implements slog.Handler. -func (h *ZerologHandler) Handle(_ context.Context, rec slog.Record) error { +func (h *Handler) Handle(_ context.Context, rec slog.Record) error { evt := h.startLog(rec.Level) rec.Attrs(func(a slog.Attr) bool { mapAttr(evt, a) @@ -124,15 +124,15 @@ func (h *ZerologHandler) Handle(_ context.Context, rec slog.Record) error { } // WithAttrs implements slog.Handler. -func (h *ZerologHandler) WithAttrs(attrs []slog.Attr) slog.Handler { - return &ZerologHandler{ +func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { + return &Handler{ opts: h.opts, logger: mapAttrs(h.logger.With(), attrs...).Logger(), } } // WithGroup implements slog.Handler. -func (h *ZerologHandler) WithGroup(name string) slog.Handler { +func (h *Handler) WithGroup(name string) slog.Handler { return &groupHandler{ parent: h, ctx: zerolog.Context{}, diff --git a/zerolog_test.go b/zerolog_test.go index 2d4bc2b..7b03197 100644 --- a/zerolog_test.go +++ b/zerolog_test.go @@ -112,7 +112,7 @@ func TestZerolog_Levels(t *testing.T) { out := bytes.Buffer{} for _, lvl := range levels { t.Run(lvl.slvl.String(), func(t *testing.T) { - hdl := NewZerologJsonHandler(&out, &HandlerOptions{Level: lvl.slvl}) + hdl := NewJsonHandler(&out, &HandlerOptions{Level: lvl.slvl}) for _, l := range levels { enabled := l.slvl >= lvl.slvl if hdl.Enabled(nil, l.slvl) != enabled { @@ -138,7 +138,7 @@ func TestZerolog_Levels_NoOption(t *testing.T) { out := bytes.Buffer{} for _, lvl := range levels { t.Run(lvl.slvl.String(), func(t *testing.T) { - hdl := NewZerologHandler(zerolog.New(&out).Level(lvl.zlvl), nil) + hdl := NewHandler(zerolog.New(&out).Level(lvl.zlvl), nil) for _, l := range levels { enabled := l.zlvl >= lvl.zlvl if hdl.Enabled(nil, l.slvl) != enabled { @@ -167,7 +167,7 @@ func TestZerolog_Levels_NoOption(t *testing.T) { func TestZerolog_NoGroup(t *testing.T) { out := bytes.Buffer{} - hdl := NewZerologJsonHandler(&out, nil). + hdl := NewJsonHandler(&out, nil). WithAttrs([]slog.Attr{slog.String("attr", "the attr")}) if !hdl.Enabled(nil, slog.LevelError) { @@ -198,7 +198,7 @@ func TestZerolog_NoGroup(t *testing.T) { func TestZerolog_Group(t *testing.T) { out := bytes.Buffer{} - hdl := NewZerologJsonHandler(&out, nil). + hdl := NewJsonHandler(&out, nil). WithAttrs([]slog.Attr{slog.String("attr", "the attr")}). WithGroup("testgroup"). WithAttrs([]slog.Attr{slog.String("attr", "the attr")}). @@ -237,7 +237,7 @@ func TestZerolog_Group(t *testing.T) { func TestZerolog_AddSource(t *testing.T) { out := bytes.Buffer{} - hdl := NewZerologJsonHandler(&out, &HandlerOptions{AddSource: true}) + hdl := NewJsonHandler(&out, &HandlerOptions{AddSource: true}) pc, file, line, _ := runtime.Caller(0) hdl.Handle(context.Background(), slog.NewRecord(time.Now(), slog.LevelInfo, "foobar", pc)) m := map[string]any{} @@ -251,7 +251,7 @@ func TestZerolog_AddSource(t *testing.T) { func TestZerolog_ConsoleHandler(t *testing.T) { out := bytes.Buffer{} - hdl := NewZerologConsoleHandler(&out, nil) + hdl := NewConsoleHandler(&out, nil) hdl.Handle(context.Background(), slog.NewRecord(time.Now(), slog.LevelInfo, "foobar", 0)) txt := out.String() if !strings.Contains(txt, "foobar") || !strings.Contains(txt, "INF") { @@ -264,7 +264,7 @@ func TestZerolog_ConsoleHandler(t *testing.T) { func TestHandler(t *testing.T) { out := bytes.Buffer{} dec := json.NewDecoder(&out) - hdl := NewZerologJsonHandler(&out, &HandlerOptions{Level: slog.LevelDebug}) + hdl := NewJsonHandler(&out, &HandlerOptions{Level: slog.LevelDebug}) err := slogtest.TestHandler(hdl, func() []map[string]any { results := []map[string]any{} m := map[string]any{}