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  }