github.com/livekit/protocol@v1.39.3/logger/slog.go (about)

     1  // Copyright 2023 LiveKit, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package logger
    16  
    17  import (
    18  	"context"
    19  	"log/slog"
    20  
    21  	"github.com/go-logr/logr"
    22  	"go.uber.org/zap/exp/zapslog"
    23  )
    24  
    25  // NewSlogDiscard creates a slog.Handler that discards all logs.
    26  func NewSlogDiscard() slog.Handler {
    27  	return slogDiscard{}
    28  }
    29  
    30  // ToSlogHandler converts Logger to slog.Handler.
    31  func ToSlogHandler(log Logger) slog.Handler {
    32  	switch log := log.(type) {
    33  	case ZapLogger:
    34  		zlog := log.ToZap().Desugar()
    35  		return zapslog.NewHandler(zlog.Core())
    36  	case LogRLogger:
    37  		return logr.ToSlogHandler(log.toLogr())
    38  	}
    39  	return slogHandler{log, ""}
    40  }
    41  
    42  type slogDiscard struct{}
    43  
    44  func (slogDiscard) Enabled(ctx context.Context, level slog.Level) bool {
    45  	return false
    46  }
    47  
    48  func (slogDiscard) Handle(ctx context.Context, record slog.Record) error {
    49  	return nil
    50  }
    51  
    52  func (l slogDiscard) WithAttrs(attrs []slog.Attr) slog.Handler {
    53  	return l
    54  }
    55  
    56  func (l slogDiscard) WithGroup(name string) slog.Handler {
    57  	return l
    58  }
    59  
    60  type slogHandler struct {
    61  	log   Logger
    62  	group string
    63  }
    64  
    65  func (l slogHandler) Enabled(ctx context.Context, level slog.Level) bool {
    66  	return true // so such method on Logger
    67  }
    68  
    69  func (l slogHandler) getGroup() string {
    70  	group := l.group
    71  	if group != "" {
    72  		group = group + "."
    73  	}
    74  	return group
    75  }
    76  
    77  func (l slogHandler) Handle(ctx context.Context, r slog.Record) error {
    78  	keysAndValues := make([]any, 0, r.NumAttrs()*2)
    79  	group := l.getGroup()
    80  	r.Attrs(func(attr slog.Attr) bool {
    81  		keysAndValues = append(keysAndValues, group+attr.Key, attr.Value.Resolve().Any())
    82  		return true
    83  	})
    84  	switch r.Level {
    85  	case slog.LevelDebug:
    86  		l.log.Debugw(r.Message, keysAndValues...)
    87  	default:
    88  		fallthrough
    89  	case slog.LevelInfo:
    90  		l.log.Infow(r.Message, keysAndValues...)
    91  	case slog.LevelWarn:
    92  		l.log.Warnw(r.Message, nil, keysAndValues...)
    93  	case slog.LevelError:
    94  		l.log.Errorw(r.Message, nil, keysAndValues...)
    95  	}
    96  	return nil
    97  }
    98  
    99  func (l slogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
   100  	log := l.log
   101  	keysAndValues := make([]any, 0, len(attrs)*2)
   102  	group := l.getGroup()
   103  	for _, attr := range attrs {
   104  		keysAndValues = append(keysAndValues, group+attr.Key, attr.Value.Resolve().Any())
   105  	}
   106  	log = log.WithValues(keysAndValues...)
   107  	return slogHandler{log, l.group}
   108  }
   109  
   110  func (l slogHandler) WithGroup(name string) slog.Handler {
   111  	group := name
   112  	if l.group != "" {
   113  		group = l.group + "." + name
   114  	}
   115  	return slogHandler{l.log, group}
   116  }