tstor/pkg/rlog/rlog.go
royalcat 199a82ff0c
All checks were successful
docker / build-docker (linux/amd64) (push) Successful in 2m16s
docker / build-docker (linux/arm64) (push) Successful in 2m14s
torrent priority and piece state fix
2024-07-07 23:09:13 +03:00

142 lines
3.1 KiB
Go

package rlog
import (
"context"
"log/slog"
"os"
"runtime"
"strings"
"time"
"github.com/rs/zerolog"
slogmulti "github.com/samber/slog-multi"
slogzerolog "github.com/samber/slog-zerolog"
)
var (
zl = zerolog.New(&zerolog.ConsoleWriter{Out: os.Stderr})
handlers = []slog.Handler{
slogzerolog.Option{Logger: &zl}.NewZerologHandler(),
}
handler = slogmulti.Fanout(handlers...)
defaultLogger = slog.New(handler)
)
func init() {
slog.SetDefault(defaultLogger)
}
func AddHandler(nh slog.Handler) {
handlers = append(handlers, nh)
handler = slogmulti.Fanout(handlers...)
defaultLogger = slog.New(handler)
slog.SetDefault(defaultLogger)
}
type Logger struct {
handler slog.Handler
callNesting int
component []string
}
const functionKey = "function"
const componentKey = "component"
const componentSep = "."
func (l *Logger) log(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) {
var pcs [1]uintptr
runtime.Callers(3+l.callNesting, pcs[:])
pc := pcs[0]
f := runtime.FuncForPC(pc)
if f != nil {
attrs = append(attrs, slog.String(functionKey, f.Name()))
}
if len(l.component) > 0 {
attrs = append(attrs, slog.String(componentKey, strings.Join(l.component, componentSep)))
}
r := slog.NewRecord(time.Now(), level, msg, pc)
r.AddAttrs(attrs...)
if ctx == nil {
ctx = context.Background()
}
_ = l.handler.Handle(ctx, r)
}
func (l *Logger) Debug(ctx context.Context, msg string, attrs ...slog.Attr) {
l.log(ctx, slog.LevelDebug, msg, attrs...)
}
func (l *Logger) Info(ctx context.Context, msg string, attrs ...slog.Attr) {
l.log(ctx, slog.LevelInfo, msg, attrs...)
}
func (l *Logger) Warn(ctx context.Context, msg string, attrs ...slog.Attr) {
l.log(ctx, slog.LevelWarn, msg, attrs...)
}
func (l *Logger) Error(ctx context.Context, msg string, attrs ...slog.Attr) {
l.log(ctx, slog.LevelError, msg, attrs...)
}
func (log *Logger) WithComponent(name string) *Logger {
return &Logger{
handler: log.handler,
component: append(log.component, name),
}
}
func (l *Logger) With(attrs ...slog.Attr) *Logger {
return &Logger{
handler: l.handler.WithAttrs(attrs),
component: l.component,
}
}
func (l *Logger) Nested(callNesting int) *Logger {
return &Logger{
handler: l.handler,
component: l.component,
callNesting: callNesting,
}
}
// returns a new slog logger with the same attribures as the original logger
// TODO currently not logging function name
func (l *Logger) Slog() *slog.Logger {
return slog.New(l.handler)
}
const errKey = "error"
func Error(err error) slog.Attr {
return slog.Attr{Key: errKey, Value: errValue(err)}
}
// errValue returns a slog.GroupValue with keys "msg" and "trace". If the error
// does not implement interface { StackTrace() errors.StackTrace }, the "trace"
// key is omitted.
func errValue(err error) slog.Value {
if err == nil {
return slog.AnyValue(nil)
}
var groupValues []slog.Attr
groupValues = append(groupValues,
slog.String("msg", err.Error()),
slog.Any("value", err),
)
return slog.GroupValue(groupValues...)
}
func Component(name ...string) *Logger {
return &Logger{
handler: handler,
component: name,
}
}