github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/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 = append(l.b, l.Logger.Labels()...) 73 74 l.b = l.AppendBreak(l.b) 75 76 _, err := l.Writer.Write(l.b) 77 78 return err 79 } 80 81 func (l *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { 82 if len(attrs) == 0 { 83 return l 84 } 85 86 defer l.Unlock() 87 l.Lock() 88 89 b := l.b 90 l.b = append([]byte{}, l.prefix...) 91 92 for _, a := range attrs { 93 l.attr(a) 94 } 95 96 p := l.b 97 l.b = b 98 99 return &Handler{ 100 Logger: l.Logger, 101 Level: l.Level, 102 prefix: p, 103 depth: l.depth, 104 } 105 } 106 107 func (l *Handler) WithGroup(name string) slog.Handler { 108 if name == "" { 109 return l 110 } 111 112 p := append([]byte{}, l.prefix...) 113 114 p = l.AppendKey(p, name) 115 p = l.AppendMap(p, -1) 116 117 return &Handler{ 118 Logger: l.Logger, 119 Level: l.Level, 120 prefix: p, 121 depth: l.depth + 1, 122 } 123 } 124 125 func (l *Handler) attr(a slog.Attr) bool { 126 kind := a.Value.Kind() 127 128 if a.Key == "" && kind != slog.KindGroup { 129 return true 130 } 131 132 val := a.Value.Resolve() 133 134 if kind != slog.KindGroup { 135 l.b = l.AppendKey(l.b, a.Key) 136 l.b = l.AppendValue(l.b, val.Any()) 137 138 return true 139 } 140 141 gr := val.Group() 142 143 if len(gr) == 0 { 144 return true 145 } 146 147 if a.Key != "" { 148 l.b = l.AppendKey(l.b, a.Key) 149 l.b = l.AppendMap(l.b, len(gr)) 150 } 151 152 for _, a := range gr { 153 ok := l.attr(a) 154 if !ok { 155 return false 156 } 157 } 158 159 return true 160 } 161 162 func level(lvl slog.Level) tlog.LogLevel { 163 return tlog.LogLevel(lvl / 4) 164 }