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  }