4 Commits

Author SHA1 Message Date
5c0aadd54a fix #6: support LogValuer() attributes 2024-01-22 13:59:51 +01:00
33798bddb3 Fix #7: implement AddSource flag, add as message 2024-01-22 13:59:51 +01:00
T.v.Dein
d53c1db7d0 added ref badge (#5) 2024-01-19 18:48:42 +01:00
T.v.Dein
1c65084c37 Develop (#4)
* finalized tests, made .With() work to create sub-loggers
2024-01-19 13:45:25 +01:00
5 changed files with 70 additions and 7 deletions

View File

@@ -34,5 +34,6 @@ lint:
golangci-lint run -p bugs -p unused golangci-lint run -p bugs -p unused
release: buildlocal test release: buildlocal test
gh release create v$(VERSION) --generate-notes releases/* gh release create v$(VERSION) --generate-notes

View File

@@ -2,6 +2,7 @@
[![Actions](https://github.com/tlinden/yadu/actions/workflows/ci.yaml/badge.svg)](https://github.com/tlinden/yadu/actions) [![Actions](https://github.com/tlinden/yadu/actions/workflows/ci.yaml/badge.svg)](https://github.com/tlinden/yadu/actions)
[![Go Coverage](https://github.com/tlinden/yadu/wiki/coverage.svg)](https://raw.githack.com/wiki/tlinden/yadu/coverage.html) [![Go Coverage](https://github.com/tlinden/yadu/wiki/coverage.svg)](https://raw.githack.com/wiki/tlinden/yadu/coverage.html)
![GitHub License](https://img.shields.io/github/license/tlinden/yadu) ![GitHub License](https://img.shields.io/github/license/tlinden/yadu)
[![GoDoc](https://godoc.org/github.com/tlinden/yadu?status.svg)](https://godoc.org/github.com/tlinden/yadu)
# yadu - a human readable yaml based slog.Handler # yadu - a human readable yaml based slog.Handler

View File

@@ -16,6 +16,12 @@ type Ammo struct {
Range int Range int
} }
func (a *Ammo) LogValue() slog.Value {
return slog.GroupValue(
slog.String("Forweapon", a.Forweapon),
)
}
type Enemy struct { type Enemy struct {
Alive bool Alive bool
Health int Health int
@@ -24,6 +30,12 @@ type Enemy struct {
Ammo []Ammo Ammo []Ammo
} }
func (e *Enemy) LogValue() slog.Value {
return slog.GroupValue(
slog.String("name", e.Name),
)
}
func removeTime(_ []string, a slog.Attr) slog.Attr { func removeTime(_ []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey { if a.Key == slog.TimeKey {
return slog.Attr{} return slog.Attr{}
@@ -35,6 +47,7 @@ func main() {
opts := &yadu.Options{ opts := &yadu.Options{
Level: slog.LevelDebug, Level: slog.LevelDebug,
ReplaceAttr: removeTime, ReplaceAttr: removeTime,
AddSource: true,
} }
logger := slog.New(yadu.NewHandler(os.Stdout, opts)) logger := slog.New(yadu.NewHandler(os.Stdout, opts))
@@ -46,6 +59,7 @@ func main() {
} }
slog.Info("info", "enemy", e, "spawn", 199) slog.Info("info", "enemy", e, "spawn", 199)
slog.Info("info", "ammo", &Ammo{Forweapon: "axe", Impact: 1})
slog.Info("connecting", "enemies", 100, "players", 2, "world", "600x800") slog.Info("connecting", "enemies", 100, "players", 2, "world", "600x800")
slog.Debug("debug text") slog.Debug("debug text")
slog.Error("error") slog.Error("error")

View File

@@ -3,9 +3,11 @@ package yadu
import ( import (
"bytes" "bytes"
"context" "context"
"fmt"
"io" "io"
"log/slog" "log/slog"
"regexp" "regexp"
"runtime"
"slices" "slices"
"strings" "strings"
"sync" "sync"
@@ -15,7 +17,7 @@ import (
"github.com/fatih/color" "github.com/fatih/color"
) )
const VERSION = "0.1.0" const VERSION = "0.1.1"
// We use RFC datestring by default // We use RFC datestring by default
const DefaultTimeFormat = "2006-01-02T03:04.05 MST" const DefaultTimeFormat = "2006-01-02T03:04.05 MST"
@@ -73,11 +75,20 @@ func (h *Handler) Handle(ctx context.Context, r slog.Record) error {
fields := make(map[string]interface{}, r.NumAttrs()) fields := make(map[string]interface{}, r.NumAttrs())
r.Attrs(func(a slog.Attr) bool { r.Attrs(func(a slog.Attr) bool {
fields[a.Key] = a.Value.Any() //fields[a.Key] = a.Value.Any()
a.Value = a.Value.Resolve()
wa := make(map[string]interface{})
h.appendAttr(wa, a)
fields[a.Key] = wa[a.Key]
return true return true
}) })
tree := "" tree := ""
source := ""
if h.addSource && r.PC != 0 {
source = h.getSource(r.PC)
}
if len(h.attrs) > 0 { if len(h.attrs) > 0 {
bytetree, err := yaml.Marshal(h.attrs) bytetree, err := yaml.Marshal(h.attrs)
@@ -119,6 +130,8 @@ func (h *Handler) Handle(ctx context.Context, r slog.Record) error {
buf.WriteString(" ") buf.WriteString(" ")
buf.WriteString(msg) buf.WriteString(msg)
buf.WriteString(" ") buf.WriteString(" ")
buf.WriteString(source)
buf.WriteString(" ")
buf.WriteString(color.WhiteString(tree)) buf.WriteString(color.WhiteString(tree))
buf.WriteString("\n") buf.WriteString("\n")
@@ -129,6 +142,13 @@ func (h *Handler) Handle(ctx context.Context, r slog.Record) error {
return err return err
} }
// report caller source+line as yaml string
func (h *Handler) getSource(pc uintptr) string {
fs := runtime.CallersFrames([]uintptr{pc})
source, _ := fs.Next()
return fmt.Sprintf("%s: %d", source.File, source.Line)
}
func (h *Handler) Postprocess(yamlstr []byte) string { func (h *Handler) Postprocess(yamlstr []byte) string {
return "\n " + strings.TrimSpace(h.indenter.ReplaceAllString(string(yamlstr), " ")) return "\n " + strings.TrimSpace(h.indenter.ReplaceAllString(string(yamlstr), " "))
} }

View File

@@ -20,6 +20,12 @@ type Ammo struct {
Range float32 Range float32
} }
func (a *Ammo) LogValue() slog.Value {
return slog.GroupValue(
slog.String("Forweapon", "Use weapon: "+a.Forweapon),
)
}
type Enemy struct { type Enemy struct {
Alive bool Alive bool
Health int Health int
@@ -50,6 +56,16 @@ var tests = []Tests{
want: "ammo:", want: "ammo:",
negate: false, negate: false,
}, },
{
name: "has-ammo-logvaluer",
want: "Use weapon: Axe",
negate: false,
},
{
name: "has-ammo-logvaluer-does-resolve",
want: "impact: 50", // should NOT appear
negate: true,
},
{ {
name: "has-alive", name: "has-alive",
want: "alive: true", want: "alive: true",
@@ -115,6 +131,14 @@ var tests = []Tests{
Level: slog.LevelError, Level: slog.LevelError,
}, },
}, },
{
name: "has-source",
want: "handler_test.go",
negate: false,
opts: yadu.Options{
AddSource: true,
},
},
{ {
// check if output is NOT colored when disabling it // check if output is NOT colored when disabling it
name: "disable-color", name: "disable-color",
@@ -136,7 +160,10 @@ func GetEnemy() *Enemy {
return &Enemy{Alive: true, Health: 10, Name: "Bodo", Body: "body\nbody\n", return &Enemy{Alive: true, Health: 10, Name: "Bodo", Body: "body\nbody\n",
Ammo: []Ammo{{Forweapon: "Railgun", Range: 400, Impact: 100, Cost: 100000}}, Ammo: []Ammo{{Forweapon: "Railgun", Range: 400, Impact: 100, Cost: 100000}},
} }
}
func GetAmmo() *Ammo {
return &Ammo{Forweapon: "Axe", Range: 50, Impact: 1, Cost: 50}
} }
func removeTime(_ []string, a slog.Attr) slog.Attr { func removeTime(_ []string, a slog.Attr) slog.Attr {
@@ -166,13 +193,13 @@ func Test(t *testing.T) {
switch tt.opts.Level { switch tt.opts.Level {
case slog.LevelDebug: case slog.LevelDebug:
logger.Debug("attack", "enemy", GetEnemy()) logger.Debug("attack", "enemy", GetEnemy(), "ammo", GetAmmo())
case slog.LevelWarn: case slog.LevelWarn:
logger.Warn("attack", "enemy", GetEnemy()) logger.Warn("attack", "enemy", GetEnemy(), "ammo", GetAmmo())
case slog.LevelError: case slog.LevelError:
logger.Error("attack", "enemy", GetEnemy()) logger.Error("attack", "enemy", GetEnemy(), "ammo", GetAmmo())
default: default:
logger.Info("attack", "enemy", GetEnemy()) logger.Info("attack", "enemy", GetEnemy(), "ammo", GetAmmo())
} }
got := buf.String() got := buf.String()