146 lines
2.6 KiB
Go
146 lines
2.6 KiB
Go
package logging
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
func (f *FormattedHandler) newState(sb *bytes.Buffer) state {
|
|
s := state{
|
|
fh: f,
|
|
buf: sb,
|
|
}
|
|
if f.opts.ReplaceAttr != nil {
|
|
s.groups = groupPool.Get().(*[]string)
|
|
*s.groups = append(*s.groups, f.groups[:f.groupLvl]...)
|
|
}
|
|
return s
|
|
}
|
|
|
|
type state struct {
|
|
buf *bytes.Buffer
|
|
fh *FormattedHandler
|
|
groups *[]string
|
|
}
|
|
|
|
func (s *state) startGroups() {
|
|
for _, n := range s.fh.groups[s.fh.groupLvl:] {
|
|
s.startGroup(n)
|
|
}
|
|
}
|
|
|
|
func (s *state) startGroup(name string) {
|
|
s.buf.WriteByte('\n')
|
|
if s.groups != nil {
|
|
*s.groups = append(*s.groups, name)
|
|
}
|
|
}
|
|
|
|
func (s *state) endGroup() {
|
|
if s.groups != nil {
|
|
*s.groups = (*s.groups)[:len(*s.groups)-1]
|
|
}
|
|
}
|
|
|
|
func (s *state) appendAttr(a slog.Attr) bool {
|
|
a.Value = a.Value.Resolve()
|
|
if rep := s.fh.opts.ReplaceAttr; rep != nil && a.Value.Kind() != slog.KindGroup {
|
|
var gs []string
|
|
if s.groups != nil {
|
|
gs = *s.groups
|
|
}
|
|
a = rep(gs, a)
|
|
a.Value = a.Value.Resolve()
|
|
}
|
|
if a.Equal(slog.Attr{}) ||
|
|
hasBuiltInKey(a) ||
|
|
a.Key == slog.LevelKey {
|
|
return false
|
|
}
|
|
if a.Value.Kind() == slog.KindGroup {
|
|
pos := s.buf.Len()
|
|
attrs := a.Value.Group()
|
|
if len(attrs) > 0 {
|
|
if a.Key != "" {
|
|
s.startGroup(a.Key)
|
|
}
|
|
if !s.appendAttrs(attrs) {
|
|
s.buf.Truncate(pos)
|
|
return false
|
|
}
|
|
if a.Key != "" {
|
|
s.endGroup()
|
|
}
|
|
}
|
|
} else {
|
|
s.writeAttr(a)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (s *state) appendAttrs(as []slog.Attr) bool {
|
|
nonEmpty := false
|
|
for _, a := range as {
|
|
if s.appendAttr(a) {
|
|
nonEmpty = true
|
|
}
|
|
}
|
|
return nonEmpty
|
|
}
|
|
|
|
func (s *state) writeAttr(a slog.Attr) {
|
|
if s.buf.Len() > 0 {
|
|
s.buf.WriteString(";")
|
|
}
|
|
if len(*s.groups) > 0 {
|
|
s.buf.WriteString(fmt.Sprintf("%*s", len(*s.groups)*2, ""))
|
|
s.buf.WriteString(strings.Join(*s.groups, "."))
|
|
s.buf.WriteString(".")
|
|
}
|
|
s.buf.WriteString(a.Key)
|
|
s.buf.WriteString("=")
|
|
switch a.Value.Kind() {
|
|
case slog.KindDuration:
|
|
s.buf.WriteString(a.Value.Duration().String())
|
|
case slog.KindTime:
|
|
s.buf.WriteString(a.Value.Time().Format(time.RFC3339Nano))
|
|
default:
|
|
s.buf.WriteString(fmt.Sprintf("%+v", a.Value.Any()))
|
|
}
|
|
}
|
|
|
|
func (s *state) begin(r slog.Record) {
|
|
if r.NumAttrs() > 0 {
|
|
pos := s.buf.Len()
|
|
s.startGroups()
|
|
empty := true
|
|
r.Attrs(func(a slog.Attr) bool {
|
|
isBuiltIn := hasBuiltInKey(a) || a.Key == slog.LevelKey
|
|
if !isBuiltIn && s.appendAttr(a) {
|
|
empty = false
|
|
}
|
|
return true
|
|
})
|
|
if empty {
|
|
s.buf.Truncate(pos)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *state) free() {
|
|
if gs := s.groups; gs != nil {
|
|
*gs = (*gs)[:0]
|
|
groupPool.Put(gs)
|
|
}
|
|
s.buf.Reset()
|
|
}
|
|
|
|
var groupPool = sync.Pool{New: func() any {
|
|
s := make([]string, 0, 10)
|
|
return &s
|
|
}}
|