Skip to content

Commit

Permalink
support slog group
Browse files Browse the repository at this point in the history
  • Loading branch information
phuslu committed Apr 28, 2024
1 parent 50d8eae commit 7ae607a
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 93 deletions.
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# phuslog - High performance structured logging
# phuslog - Fastest structured logging

[![godoc][godoc-img]][godoc]
[![goreport][report-img]][report]
Expand Down Expand Up @@ -272,7 +272,7 @@ func (l *Glog) Errorf(fmt string, a ...any) { l.Logger.Error().Msgf(fmt, a...) }

var glog = &Glog{log.Logger{
Level: log.InfoLevel,
Caller: 1,
Caller: 2,
TimeFormat: "0102 15:04:05.999999",
Writer: &log.ConsoleWriter{Formatter: func(w io.Writer, a *log.FormatterArgs) (int, error) {
return fmt.Fprintf(w, "%c%s %s %s] %s\n%s", a.Level[0]-32, a.Time, a.Goid, a.Caller, a.Message, a.Stack)
Expand Down Expand Up @@ -691,9 +691,9 @@ func main() {
}
```

### log/slog Adapter
### slog Adapter

Using wrapped loggers for log/slog. [![playground][play-slog-img]][play-slog]
Using wrapped loggers for slog. [![playground][play-slog-img]][play-slog]

```go
package main
Expand All @@ -705,18 +705,18 @@ import (
)

func main() {
slog.SetDefault((&log.Logger{
var logger *slog.Logger = (&log.Logger{
Level: log.InfoLevel,
TimeField: "date",
TimeFormat: "2006-01-02",
Caller: 1,
Context: log.NewContext(nil).Str("logger", "my_slog").Int("myid", 42).Value(),
}).Slog())
}).Slog()

slog.Debug("hello from slog Info")
slog.Info("hello from slog Info")
slog.Warn("hello from slog Warn")
slog.Error("hello from slog Error")
logger = logger.With("logger", "a_test_slog").With("everything", 42)

logger.Info("hello from slog Info")
logger.Warn("hello from slog Warn")
logger.Error("hello from slog Error")
}
```

Expand Down Expand Up @@ -1158,7 +1158,7 @@ This log is heavily inspired by [zerolog][zerolog], [glog][glog], [gjson][gjson]
[report]: https://goreportcard.com/report/github.com/phuslu/log
[build-img]: https://github.com/phuslu/log/workflows/build/badge.svg
[build]: https://github.com/phuslu/log/actions
[stability-img]: https://img.shields.io/badge/stability-maintenance-green.svg
[stability-img]: https://img.shields.io/badge/stability-stable-green.svg
[high-performance]: https://github.com/phuslu/log?tab=readme-ov-file#high-performance
[play-simple-img]: https://img.shields.io/badge/playground-NGV25aBKmYH-29BEB0?style=flat&logo=go
[play-simple]: https://go.dev/play/p/NGV25aBKmYH
Expand All @@ -1173,8 +1173,8 @@ This log is heavily inspired by [zerolog][zerolog], [glog][glog], [gjson][gjson]
[play-pretty-img]: https://img.shields.io/badge/playground-SCcXG33esvI-29BEB0?style=flat&logo=go
[play-pretty]: https://go.dev/play/p/SCcXG33esvI
[pretty-img]: https://user-images.githubusercontent.com/195836/101993218-cda82380-3cf3-11eb-9aa2-b8b1c832a72e.png
[play-glog-img]: https://img.shields.io/badge/playground-6pEThv3WO7W-29BEB0?style=flat&logo=go
[play-glog]: https://go.dev/play/p/6pEThv3WO7W
[play-glog-img]: https://img.shields.io/badge/playground-oxSyv3ra5W5-29BEB0?style=flat&logo=go
[play-glog]: https://go.dev/play/p/oxSyv3ra5W5
[play-logfmt-img]: https://img.shields.io/badge/playground-7aSa--rxHmqw-29BEB0?style=flat&logo=go
[play-logfmt]: https://go.dev/play/p/7aSa-rxHmqw
[play-context-img]: https://img.shields.io/badge/playground-oAVAo302faf-29BEB0?style=flat&logo=go
Expand All @@ -1185,8 +1185,8 @@ This log is heavily inspired by [zerolog][zerolog], [glog][glog], [gjson][gjson]
[play-marshal]: https://go.dev/play/p/SoQdwQOaQR2
[play-stdlog]: https://go.dev/play/p/DnKyE92LEEm
[play-stdlog-img]: https://img.shields.io/badge/playground-DnKyE92LEEm-29BEB0?style=flat&logo=go
[play-slog]: https://go.dev/play/p/ez_yIPOXBQF
[play-slog-img]: https://img.shields.io/badge/playground-ez__yIPOXBQF-29BEB0?style=flat&logo=go
[play-slog]: https://go.dev/play/p/JW3Ts6FcB40
[play-slog-img]: https://img.shields.io/badge/playground-JW3Ts6FcB40-29BEB0?style=flat&logo=go
[benchmark]: https://github.com/phuslu/log/actions?query=workflow%3Abenchmark
[zerolog]: https://github.com/rs/zerolog
[glog]: https://github.com/golang/glog
Expand Down
77 changes: 0 additions & 77 deletions logger_go1.21.go

This file was deleted.

File renamed without changes.
File renamed without changes.
113 changes: 113 additions & 0 deletions logger_slog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//go:build go1.21
// +build go1.21

package log

import (
"context"
"log/slog"
)

type slogHandler struct {
Logger

attrs []any // *slog.Attr or *slogGroup
}

type slogGroup struct {
name string
attrs []any // *slog.Attr or *slogGroup
}

func isSlogGroup(v any) bool { _, ok := v.(*slogGroup); return ok }

func (h *slogHandler) Enabled(_ context.Context, level slog.Level) bool {
switch level {
case slog.LevelDebug:
return h.Logger.Level <= DebugLevel
case slog.LevelInfo:
return h.Logger.Level <= InfoLevel
case slog.LevelWarn:
return h.Logger.Level <= WarnLevel
case slog.LevelError:
return h.Logger.Level <= ErrorLevel
}
return false
}

func (h *slogHandler) Handle(_ context.Context, r slog.Record) error {
var e *Entry
switch r.Level {
case slog.LevelDebug:
e = h.Logger.Debug()
case slog.LevelInfo:
e = h.Logger.Info()
case slog.LevelWarn:
e = h.Logger.Warn()
case slog.LevelError:
e = h.Logger.Error()
default:
e = h.Logger.Log()
}
e = h.output(e, h.attrs)
r.Attrs(func(attr slog.Attr) bool {
e = e.Any(attr.Key, attr.Value)
return true
})
e.Msg(r.Message)
return nil
}

func (h *slogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
if len(h.attrs) != 0 && isSlogGroup(h.attrs[len(h.attrs)-1]) {
h.withAttrs(h.attrs[len(h.attrs)-1].(*slogGroup), attrs)
} else {
for _, attr := range attrs {
h.attrs = append(h.attrs, &attr)
}
}
return h
}

func (h *slogHandler) withAttrs(group *slogGroup, attrs []slog.Attr) {
if len(group.attrs) != 0 && isSlogGroup(group.attrs[len(group.attrs)-1]) {
h.withAttrs(group.attrs[len(group.attrs)-1].(*slogGroup), attrs)
} else {
for _, attr := range attrs {
group.attrs = append(group.attrs, &attr)
}
}
}

func (h *slogHandler) WithGroup(name string) slog.Handler {
if len(h.attrs) != 0 && isSlogGroup(h.attrs[len(h.attrs)-1]) {
group := h.attrs[len(h.attrs)-1].(*slogGroup)
group.attrs = append(group.attrs, &slogGroup{name: name})
} else {
h.attrs = append(h.attrs, &slogGroup{name: name})
}
return h
}

func (h *slogHandler) output(e *Entry, attrs []any) *Entry {
for _, v := range attrs {
if group, ok := v.(*slogGroup); ok && group.name != "" {
e.Dict(group.name, h.output(NewContext(nil), group.attrs).Value())
} else if attr, ok := v.(*slog.Attr); ok {
e = e.Any(attr.Key, attr.Value)
}
}
return e
}

// Slog wraps the Logger to provide *slog.Logger
func (l *Logger) Slog() *slog.Logger {
logger := *l
switch {
case logger.Caller > 0:
logger.Caller += 3
case logger.Caller < 0:
logger.Caller -= 3
}
return slog.New(&slogHandler{Logger: logger})
}
46 changes: 46 additions & 0 deletions logger_slog_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//go:build go1.21
// +build go1.21

package log

import (
"log/slog"
"testing"
)

func TestSlogNormal(t *testing.T) {
var logger *slog.Logger = (&Logger{
Level: InfoLevel,
TimeField: "date",
TimeFormat: "2006-01-02",
Caller: 1,
}).Slog()

logger.Info("hello from slog Info")
logger.Warn("hello from slog Warn")
logger.Error("hello from slog Error")
}

func TestSlogAttrs(t *testing.T) {
var logger *slog.Logger = (&Logger{
Level: InfoLevel,
TimeField: "date",
TimeFormat: "2006-01-02",
Caller: 1,
}).Slog()

sublogger := logger.With("logger", "attr_logger").With("everything", 42)
sublogger.Info("hello from attr slog")
}

func TestSlogGroup(t *testing.T) {
var logger *slog.Logger = (&Logger{
Level: InfoLevel,
TimeField: "date",
TimeFormat: "2006-01-02",
Caller: 1,
}).Slog()

sublogger := logger.WithGroup("g1").With("logger", "attr_logger").WithGroup("g2").With("foo", "bar")
sublogger.Info("hello from group slog")
}

0 comments on commit 7ae607a

Please sign in to comment.