finalized tests, made .With() work to create sub-loggers (#2)

Co-authored-by: Thomas von Dein <tom@vondein.org>
This commit is contained in:
T.v.Dein
2024-01-19 13:40:00 +01:00
committed by GitHub
parent 9547dccc7f
commit a993959de7
3 changed files with 152 additions and 23 deletions

View File

@@ -6,6 +6,8 @@
#
# no need to modify anything below
VERSION = $(shell grep VERSION handler.go | head -1 | cut -d '"' -f2)
all: buildlocal
buildlocal:
@@ -30,3 +32,6 @@ goupdate:
lint:
golangci-lint run -p bugs -p unused
release: buildlocal test
@echo gh release create v$(VERSION) --generate-notes releases/*

View File

@@ -15,18 +15,23 @@ import (
"github.com/fatih/color"
)
const VERSION = "0.1.0"
// We use RFC datestring by default
const DefaultTimeFormat = "2006-01-02T03:04.05 MST"
// Default log level is INFO:
const defaultLevel = slog.LevelInfo
// holds attributes added with logger.With()
type attributes map[string]interface{}
type Handler struct {
writer io.Writer
mu *sync.Mutex
level slog.Leveler
groups []string
attrs string
attrs attributes
timeFormat string
replaceAttr func(groups []string, a slog.Attr) slog.Attr
addSource bool
@@ -49,6 +54,7 @@ type Options struct {
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
TimeFormat string
AddSource bool
NoColor bool
}
func (h *Handler) Handle(ctx context.Context, r slog.Record) error {
@@ -71,7 +77,15 @@ func (h *Handler) Handle(ctx context.Context, r slog.Record) error {
return true
})
tree := h.attrs
tree := ""
if len(h.attrs) > 0 {
bytetree, err := yaml.Marshal(h.attrs)
if err != nil {
return err
}
tree = h.Postprocess(bytetree)
}
if len(fields) > 0 {
bytetree, err := yaml.Marshal(&fields)
@@ -79,7 +93,7 @@ func (h *Handler) Handle(ctx context.Context, r slog.Record) error {
return err
}
tree = h.Postprocess(bytetree)
tree += h.Postprocess(bytetree)
}
timeStr := ""
@@ -144,6 +158,10 @@ func NewHandler(out io.Writer, opts *Options) *Handler {
h.timeFormat = DefaultTimeFormat
}
if opts.NoColor {
color.NoColor = true
}
return h
}
@@ -153,24 +171,59 @@ func (h *Handler) Enabled(_ context.Context, l slog.Level) bool {
}
// attributes plus attrs.
func (h *Handler) appendAttr(wa map[string]interface{}, a slog.Attr) {
a.Value = a.Value.Resolve()
if a.Value.Kind() == slog.KindGroup {
attrs := a.Value.Group()
name := ""
if len(attrs) == 0 {
return
}
if a.Key != "" {
name = a.Key
h.groups = append(h.groups, a.Key)
}
innerwa := make(map[string]interface{})
for _, a := range attrs {
h.appendAttr(innerwa, a)
}
wa[name] = innerwa
if a.Key != "" {
h.groups = h.groups[:len(h.groups)-1]
}
return
}
if h.replaceAttr != nil {
a = h.replaceAttr(h.groups, a)
}
if !a.Equal(slog.Attr{}) {
wa[a.Key] = a.Value.Any()
}
}
// sub logger is to be created, possibly with attrs, add them to h.attrs
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
if len(attrs) == 0 {
return h
}
fields := make(map[string]interface{}, len(attrs))
for _, a := range attrs {
fields[a.Key] = a.Value.Any()
}
bytetree, err := yaml.Marshal(&fields)
if err != nil {
panic(err)
}
h2 := h.clone()
h2.attrs += string(bytetree)
wa := make(map[string]interface{})
for _, a := range attrs {
h2.appendAttr(wa, a)
}
h2.attrs = wa
return h2
}

View File

@@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/fatih/color"
"github.com/tlinden/yadu"
)
@@ -31,7 +32,9 @@ type Tests struct {
name string
want string
negate bool
opts *yadu.Options
opts yadu.Options
with slog.Attr
haswith bool
}
const testTimeFormat = "03:04.05"
@@ -65,7 +68,7 @@ var tests = []Tests{
{
name: "has-no-time",
want: time.Now().Format(yadu.DefaultTimeFormat),
opts: &yadu.Options{
opts: yadu.Options{
ReplaceAttr: removeTime,
},
negate: true,
@@ -73,12 +76,60 @@ var tests = []Tests{
{
name: "has-custom-time",
want: time.Now().Format(testTimeFormat),
opts: &yadu.Options{
opts: yadu.Options{
TimeFormat: testTimeFormat,
},
negate: false,
},
// FIXME: add WithGroup + WithAttr tests
{
name: "with-group",
want: "pid:",
negate: false,
with: slog.Group("program_info",
slog.Int("pid", 1923),
slog.Bool("alive", true),
),
haswith: true,
},
{
name: "has-debug",
want: "DEBUG",
negate: false,
opts: yadu.Options{
Level: slog.LevelDebug,
},
},
{
name: "has-warn",
want: "WARN",
negate: false,
opts: yadu.Options{
Level: slog.LevelWarn,
},
},
{
name: "has-error",
want: "ERROR",
negate: false,
opts: yadu.Options{
Level: slog.LevelError,
},
},
{
// check if output is NOT colored when disabling it
name: "disable-color",
want: "\x1b[0m",
negate: true,
opts: yadu.Options{
NoColor: true,
},
},
{
// check if output is colored
name: "enable-color",
want: "\x1b[0m",
negate: false,
},
}
func GetEnemy() *Enemy {
@@ -101,9 +152,29 @@ func Test(t *testing.T) {
for _, tt := range tests {
var buf bytes.Buffer
logger := slog.New(yadu.NewHandler(&buf, tt.opts))
logger := slog.New(yadu.NewHandler(&buf, &tt.opts))
if !tt.with.Equal(slog.Attr{}) {
logger = logger.With(tt.with)
}
if !tt.opts.NoColor {
color.NoColor = false
}
slog.SetDefault(logger)
switch tt.opts.Level {
case slog.LevelDebug:
logger.Debug("attack", "enemy", GetEnemy())
case slog.LevelWarn:
logger.Warn("attack", "enemy", GetEnemy())
case slog.LevelError:
logger.Error("attack", "enemy", GetEnemy())
default:
logger.Info("attack", "enemy", GetEnemy())
}
got := buf.String()
if strings.Contains(got, tt.want) == tt.negate {