github.com/nikandfor/tlog@v0.21.3/ext/tlslog/slog.go (about) 1 package tlslog 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/nikandfor/loc" 8 "golang.org/x/exp/slog" 9 10 "github.com/nikandfor/tlog" 11 ) 12 13 type ( 14 Handler struct { 15 *tlog.Logger 16 Level slog.Level 17 18 b []byte 19 20 prefix []byte 21 depth int 22 } 23 ) 24 25 var _ slog.Handler = &Handler{} 26 27 func Wrap(l *tlog.Logger) *Handler { 28 return &Handler{Logger: l} 29 } 30 31 func (l *Handler) Enabled(ctx context.Context, lvl slog.Level) bool { 32 return l != nil && l.Logger != nil && lvl >= l.Level 33 } 34 35 func (l *Handler) Handle(ctx context.Context, r slog.Record) error { //nolint:gocritic 36 if l == nil { 37 return nil 38 } 39 40 defer l.Unlock() 41 l.Lock() 42 43 l.b = l.AppendMap(l.b[:0], -1) 44 45 if r.Time != (time.Time{}) { 46 l.b = l.AppendString(l.b, tlog.KeyTimestamp) 47 l.b = l.AppendTime(l.b, r.Time) 48 } 49 50 if r.PC != 0 { 51 l.b = l.AppendKey(l.b, tlog.KeyCaller) 52 l.b = l.AppendCaller(l.b, loc.PC(r.PC)) 53 } 54 55 l.b = l.AppendKey(l.b, tlog.KeyMessage) 56 l.b = l.AppendSemantic(l.b, tlog.WireMessage) 57 l.b = l.Encoder.AppendString(l.b, r.Message) 58 59 if r.Level != 0 { 60 l.b = l.AppendKey(l.b, tlog.KeyLogLevel) 61 l.b = level(r.Level).TlogAppend(l.b) 62 } 63 64 l.b = append(l.b, l.prefix...) 65 66 r.Attrs(l.attr) 67 68 for i := 0; i < l.depth; i++ { 69 l.b = l.AppendBreak(l.b) 70 } 71 72 l.b = l.AppendBreak(l.b) 73 74 _, err := l.Writer.Write(l.b) 75 76 return err 77 } 78 79 func (l *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { 80 if len(attrs) == 0 { 81 return l 82 } 83 84 defer l.Unlock() 85 l.Lock() 86 87 b := l.b 88 l.b = append([]byte{}, l.prefix...) 89 90 for _, a := range attrs { 91 l.attr(a) 92 } 93 94 p := l.b 95 l.b = b 96 97 return &Handler{ 98 Logger: l.Logger, 99 Level: l.Level, 100 prefix: p, 101 depth: l.depth, 102 } 103 } 104 105 func (l *Handler) WithGroup(name string) slog.Handler { 106 if name == "" { 107 return l 108 } 109 110 p := append([]byte{}, l.prefix...) 111 112 p = l.AppendKey(p, name) 113 p = l.AppendMap(p, -1) 114 115 return &Handler{ 116 Logger: l.Logger, 117 Level: l.Level, 118 prefix: p, 119 depth: l.depth + 1, 120 } 121 } 122 123 func (l *Handler) attr(a slog.Attr) bool { 124 kind := a.Value.Kind() 125 126 if a.Key == "" && kind != slog.KindGroup { 127 return true 128 } 129 130 val := a.Value.Resolve() 131 132 if kind != slog.KindGroup { 133 l.b = l.AppendKey(l.b, a.Key) 134 l.b = l.AppendValue(l.b, val.Any()) 135 136 return true 137 } 138 139 gr := val.Group() 140 141 if len(gr) == 0 { 142 return true 143 } 144 145 if a.Key != "" { 146 l.b = l.AppendKey(l.b, a.Key) 147 l.b = l.AppendMap(l.b, len(gr)) 148 } 149 150 for _, a := range gr { 151 ok := l.attr(a) 152 if !ok { 153 return false 154 } 155 } 156 157 return true 158 } 159 160 func level(lvl slog.Level) tlog.LogLevel { 161 return tlog.LogLevel(lvl / 4) 162 }