Skip to content

Commit

Permalink
add totem formatting options
Browse files Browse the repository at this point in the history
  • Loading branch information
Janelle Law committed Oct 13, 2023
1 parent 645bb3e commit db29905
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 41 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ require (
github.com/kralicky/gpkg v0.0.0-20220311205216-0d8ea9557555
github.com/kralicky/kmatch v0.0.0-20230301203314-20f658a0e56c
github.com/kralicky/ragu v1.0.11-0.20230627162951-2dd00e0cbbf3
github.com/kralicky/totem v1.2.1
github.com/kralicky/totem v1.2.2-0.20231013192319-ab56f5483c40
github.com/kralicky/yaml/v3 v3.0.0-20220520012407-b0e7050bd81d
github.com/lestrrat-go/backoff/v2 v2.0.8
github.com/lestrrat-go/jwx v1.2.26
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,8 @@ github.com/ionos-cloud/sdk-go/v6 v6.0.4 h1:4LoWeM7WtcDqYDjlntqQ3fD6XaENlCw2YqiVW
github.com/ionos-cloud/sdk-go/v6 v6.0.4/go.mod h1:UE3V/2DjnqD5doOqtjYqzJRMpI1RiwrvuuSEPX1pdnk=
github.com/jan-law/opentelemetry-collector-contrib/pkg/stanza v0.0.0-20231011183323-1da8f0d6468b h1:FS3nr4khTxuxKEgmbfbsK6s9+ZJ6dvrPr7C/3sSprfY=
github.com/jan-law/opentelemetry-collector-contrib/pkg/stanza v0.0.0-20231011183323-1da8f0d6468b/go.mod h1:N2K2atD+Oc1jFamDAe/H1EhtWQ+x8GBxsgHYn0JPN0I=
github.com/jan-law/slog-sampling v0.0.0-20231013170129-ef692b2d04c4 h1:05hLE3ki21Fnkh0vxNBjW1hgv4aKK222Cu4tutU1rNY=
github.com/jan-law/slog-sampling v0.0.0-20231013170129-ef692b2d04c4/go.mod h1:ZcJuHhGp3oTkGnOyl+ePWSci8XzCWQENC6JxkrE75EM=
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
Expand Down Expand Up @@ -1652,8 +1654,8 @@ github.com/kralicky/kmatch v0.0.0-20230301203314-20f658a0e56c h1:1kKbyl5GtGk/D+6
github.com/kralicky/kmatch v0.0.0-20230301203314-20f658a0e56c/go.mod h1:GXnSgs1TGXa8aX1hO9SUE1o3pLfggl5hkBMXdVWD8dc=
github.com/kralicky/ragu v1.0.11-0.20230627162951-2dd00e0cbbf3 h1:UB8Fk6c8Ait8DLtemgT/ItRdUpxJQHMDntqFopFt6/Q=
github.com/kralicky/ragu v1.0.11-0.20230627162951-2dd00e0cbbf3/go.mod h1:njQGnwU5IHm4Qx6/oOY0ll7Z6WA0apfP0ClpVA0M27Q=
github.com/kralicky/totem v1.2.1 h1:ayd+IHbmmWhgFXJfzTHg0mJ2mr/IYHCh/nDqYyd6yCk=
github.com/kralicky/totem v1.2.1/go.mod h1:DFlQM6o5n1AWrU/+wd3hjLKoKZ+a0TPRUQxnCQvGKyY=
github.com/kralicky/totem v1.2.2-0.20231013192319-ab56f5483c40 h1:Q7acvQcPTlse5kIOziWMmwcCk2GjVMe9lCOPOO/bjEM=
github.com/kralicky/totem v1.2.2-0.20231013192319-ab56f5483c40/go.mod h1:EmT24IweS2gIdMcQOZuhppvfs3cVs22pIos9RzFTHsQ=
github.com/kralicky/yaml/v3 v3.0.0-20220520012407-b0e7050bd81d h1:kLfaaFdmCHKZCvL4DzQ7T9YsAVSBqZez34zaegldkls=
github.com/kralicky/yaml/v3 v3.0.0-20220520012407-b0e7050bd81d/go.mod h1:z4cKsjE0B5RlhFSbWcZNh70UEjtwrj8fpG1QXyU2KuI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
Expand Down Expand Up @@ -2171,8 +2173,6 @@ github.com/samber/lo v1.36.1-0.20230320154156-56ef8fe8a306 h1:9kOF1vK0pvroiAnPkM
github.com/samber/lo v1.36.1-0.20230320154156-56ef8fe8a306/go.mod h1:kV0TUY2yeRZLmppP/VYD1MhUfBK78z2xFcmv/X2uyvE=
github.com/samber/slog-multi v1.0.1 h1:Owf7RnxBZokPuGuuecKH8bEX1iRepjJJgmXd5BTxvl8=
github.com/samber/slog-multi v1.0.1/go.mod h1:uLAvHpGqbYgX4FSL0p1ZwoLuveIAJvBECtE07XmYvFo=
github.com/samber/slog-sampling v1.0.0 h1:k+pPKId9RXYwHE8MK3m0sP1xTI5I/swpSi89dBjzBoM=
github.com/samber/slog-sampling v1.0.0/go.mod h1:S138KhbzB59zvOLeAAf6MesTpOwAsoXASPb50Zdto2g=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 h1:TToq11gyfNlrMFZiYujSekIsPd9AmsA2Bj/iv+s4JHE=
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
Expand Down
8 changes: 7 additions & 1 deletion pkg/logger/color_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type colorHandler struct {
attrsPrefix string // attrs started from With
groups []string // all groups started from WithGroup
groupPrefix string // groups started from Group
appendName bool
mu sync.Mutex
w io.Writer
}
Expand All @@ -53,6 +54,8 @@ func newColorHandler(w io.Writer, opts *LoggerOptions) slog.Handler {
Level: DefaultLogLevel,
AddSource: true,
ColorEnabled: ColorEnabled(),
AppendName: true,
TimeFormat: DefaultTimeFormat,
}
}

Expand All @@ -66,6 +69,7 @@ func newColorHandler(w io.Writer, opts *LoggerOptions) slog.Handler {
replaceAttr: opts.ReplaceAttr,
colorEnabled: opts.ColorEnabled,
timeFormat: opts.TimeFormat,
appendName: opts.AppendName,
w: w,
}
}
Expand Down Expand Up @@ -133,7 +137,9 @@ func (h *colorHandler) Handle(_ context.Context, r slog.Record) error {
buf.WriteByte(' ')
}

h.writeGroups(buf, h.groups)
if h.appendName {
h.writeGroups(buf, h.groups)
}

if h.addSource {
h.writeSource(buf, r.PC)
Expand Down
93 changes: 58 additions & 35 deletions pkg/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ func AsciiLogo() string {
}

type LoggerOptions struct {
Level slog.Level
AddSource bool
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
Writer io.Writer
ColorEnabled bool
Sampling *slogsampling.ThresholdSamplingOption
TimeFormat string
Level slog.Level
AddSource bool
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
Writer io.Writer
ColorEnabled bool
Sampling *slogsampling.ThresholdSamplingOption
TimeFormat string
TotemFormatEnabled bool
AppendName bool
}

func ParseLevel(lvl string) slog.Level {
Expand Down Expand Up @@ -104,12 +106,34 @@ func WithTimeFormat(format string) LoggerOption {
func WithSampling(cfg *slogsampling.ThresholdSamplingOption) LoggerOption {
return func(o *LoggerOptions) {
o.Sampling = &slogsampling.ThresholdSamplingOption{
Tick: cfg.Tick,
Threshold: cfg.Threshold,
Rate: cfg.Rate,
OnDropped: logSampler.onDroppedHook,
OnAccepted: logSampler.onAcceptedHook,
Tick: cfg.Tick,
Threshold: cfg.Threshold,
Rate: cfg.Rate,
OnDropped: logSampler.onDroppedHook,
}
o.ReplaceAttr = func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.MessageKey {
msg := a.Value.String()
count, _ := logSampler.dropped.Load(msg)
if count > 0 {
numDropped, _ := logSampler.dropped.LoadAndDelete(msg)
a.Value = slog.StringValue(fmt.Sprintf("x%d %s", numDropped+1, msg))
}
}
return a
}
}
}

func WithTotemFormat(enable bool) LoggerOption {
return func(o *LoggerOptions) {
o.TotemFormatEnabled = enable
}
}

func WithAppendName(enable bool) LoggerOption {
return func(o *LoggerOptions) {
o.AppendName = enable
}
}

Expand All @@ -120,6 +144,7 @@ func colorHandlerWithOptions(opts ...LoggerOption) slog.Handler {
Level: DefaultLogLevel,
AddSource: DefaultAddSource,
TimeFormat: DefaultTimeFormat,
AppendName: true,
}

options.apply(opts...)
Expand All @@ -128,13 +153,30 @@ func colorHandlerWithOptions(opts ...LoggerOption) slog.Handler {
DefaultWriter = os.Stdout
}

var middlewares []slogmulti.Middleware
if options.TotemFormatEnabled {
options.AppendName = false
options.Writer = os.Stderr
middlewares = append(middlewares, newTotemNameMiddleware())
}
if options.Sampling != nil {
middlewares = append(middlewares, options.Sampling.NewMiddleware())
}
var chain *slogmulti.PipeBuilder
for i, middleware := range middlewares {
if i == 0 {
chain = slogmulti.Pipe(middleware)
} else {
chain = chain.Pipe(middleware)
}
}

handler := newColorHandler(options.Writer, options)

if options.Sampling != nil {
return slogmulti.
Pipe(options.Sampling.NewMiddleware()).
Handler(handler)
if chain != nil {
handler = chain.Handler(handler)
}

return handler
}

Expand Down Expand Up @@ -163,22 +205,3 @@ func (s *sampler) onDroppedHook(_ context.Context, r slog.Record) {
count, _ := s.dropped.LoadOrStore(key, 0)
s.dropped.Store(key, count+1)
}

func (s *sampler) onAcceptedHook(_ context.Context, r slog.Record) {
attrs := []slog.Attr{}

msg := r.Message
count, _ := s.dropped.Load(msg)
if count > 0 {
numDropped, _ := s.dropped.LoadAndDelete(msg)
msg = fmt.Sprintf("x%d %s", numDropped+1, msg)
}

r.Attrs(func(attr slog.Attr) bool {
attrs = append(attrs, attr)
return true
})

r = slog.NewRecord(r.Time, r.Level, msg, r.PC)
r.AddAttrs(attrs...)
}
95 changes: 95 additions & 0 deletions pkg/logger/totem_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package logger

import (
"context"
"fmt"
"log/slog"
"math"
"math/rand"
"strings"

"github.com/charmbracelet/lipgloss"
gsync "github.com/kralicky/gpkg/sync"
slogmulti "github.com/samber/slog-multi"
)

var (
colorCache gsync.Map[string, lipgloss.Style]
)

func init() {
colorCache.Store("totem", lipgloss.NewStyle().Background(lipgloss.Color("15")).Foreground(lipgloss.Color("0")))

}

func newRandomForegroundStyle() lipgloss.Style {
r := math.Round(rand.Float64()*127) + 127
g := math.Round(rand.Float64()*127) + 127
b := math.Round(rand.Float64()*127) + 127
return lipgloss.NewStyle().Foreground(lipgloss.Color(fmt.Sprintf("#%02x%02x%02x", int(r), int(g), int(b))))
}

func newTotemNameMiddleware() slogmulti.Middleware {
return func(next slog.Handler) slog.Handler {
return &totemNameMiddleware{
next: next,
}
}
}

type totemNameMiddleware struct {
next slog.Handler
groups []string
}

func (h *totemNameMiddleware) Enabled(ctx context.Context, level slog.Level) bool {
return h.next.Enabled(ctx, level)
}

func (h *totemNameMiddleware) Handle(ctx context.Context, record slog.Record) error {
attrs := []slog.Attr{}

record.Attrs(func(attr slog.Attr) bool {
attrs = append(attrs, attr)
return true
})

sb := strings.Builder{}
for i, part := range h.groups {
if c, ok := colorCache.Load(part); !ok {
newStyle := newRandomForegroundStyle()
colorCache.Store(part, newStyle)
sb.WriteString(newStyle.Render(part))
} else {
sb.WriteString(c.Render(part))
}
if i < len(h.groups)-1 {
sb.WriteString(".")
} else {
sb.WriteByte(' ')
}
}

// insert logger name before message
sb.WriteString(record.Message)

record = slog.NewRecord(record.Time, record.Level, sb.String(), record.PC)
record.AddAttrs(attrs...)

return h.next.Handle(ctx, record)
}

func (h *totemNameMiddleware) WithAttrs(attrs []slog.Attr) slog.Handler {

return &totemNameMiddleware{
next: h.next.WithAttrs(attrs),
groups: h.groups,
}
}

func (h *totemNameMiddleware) WithGroup(name string) slog.Handler {
return &totemNameMiddleware{
next: h.next.WithGroup(name),
groups: append(h.groups, name),
}
}

0 comments on commit db29905

Please sign in to comment.