tstor/pkg/rlog/rlog.go

143 lines
3.1 KiB
Go
Raw Permalink Normal View History

2024-03-19 21:30:37 +00:00
package rlog
import (
2024-04-17 08:36:14 +00:00
"context"
2024-03-19 21:30:37 +00:00
"log/slog"
"os"
2024-04-17 08:36:14 +00:00
"runtime"
"strings"
"time"
2024-03-19 21:30:37 +00:00
"github.com/rs/zerolog"
slogmulti "github.com/samber/slog-multi"
slogzerolog "github.com/samber/slog-zerolog"
)
2024-04-17 08:36:14 +00:00
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)
)
2024-03-19 21:30:37 +00:00
func init() {
slog.SetDefault(defaultLogger)
}
func AddHandler(nh slog.Handler) {
handlers = append(handlers, nh)
2024-04-17 08:36:14 +00:00
handler = slogmulti.Fanout(handlers...)
defaultLogger = slog.New(handler)
2024-03-19 21:30:37 +00:00
slog.SetDefault(defaultLogger)
}
2024-04-17 08:36:14 +00:00
type Logger struct {
2024-07-07 20:09:13 +00:00
handler slog.Handler
callNesting int
component []string
2024-04-17 08:36:14 +00:00
}
const functionKey = "function"
2024-07-07 20:09:13 +00:00
const componentKey = "component"
const componentSep = "."
2024-04-17 08:36:14 +00:00
func (l *Logger) log(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) {
var pcs [1]uintptr
2024-07-07 20:09:13 +00:00
runtime.Callers(3+l.callNesting, pcs[:])
2024-04-17 08:36:14 +00:00
pc := pcs[0]
f := runtime.FuncForPC(pc)
2024-07-07 20:09:13 +00:00
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)))
}
2024-04-17 08:36:14 +00:00
r := slog.NewRecord(time.Now(), level, msg, pc)
r.AddAttrs(attrs...)
if ctx == nil {
ctx = context.Background()
}
2024-07-07 20:09:13 +00:00
2024-04-17 08:36:14 +00:00
_ = 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...)
2024-03-19 21:30:37 +00:00
}
2024-04-17 08:36:14 +00:00
func (l *Logger) Error(ctx context.Context, msg string, attrs ...slog.Attr) {
l.log(ctx, slog.LevelError, msg, attrs...)
2024-03-19 21:30:37 +00:00
}
2024-04-17 08:36:14 +00:00
func (log *Logger) WithComponent(name string) *Logger {
return &Logger{
2024-07-07 20:09:13 +00:00
handler: log.handler,
component: append(log.component, name),
2024-04-17 08:36:14 +00:00
}
2024-03-19 21:30:37 +00:00
}
2024-04-17 08:36:14 +00:00
func (l *Logger) With(attrs ...slog.Attr) *Logger {
return &Logger{
handler: l.handler.WithAttrs(attrs),
component: l.component,
}
2024-03-19 21:30:37 +00:00
}
2024-07-07 20:09:13 +00:00
func (l *Logger) Nested(callNesting int) *Logger {
return &Logger{
handler: l.handler,
component: l.component,
callNesting: callNesting,
}
}
2024-06-14 22:14:44 +00:00
// 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)
}
2024-04-17 08:36:14 +00:00
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
2024-03-19 21:30:37 +00:00
// does not implement interface { StackTrace() errors.StackTrace }, the "trace"
// key is omitted.
2024-04-17 08:36:14 +00:00
func errValue(err error) slog.Value {
2024-03-19 21:30:37 +00:00
if err == nil {
return slog.AnyValue(nil)
}
var groupValues []slog.Attr
2024-04-17 08:36:14 +00:00
groupValues = append(groupValues,
slog.String("msg", err.Error()),
slog.Any("value", err),
)
2024-03-19 21:30:37 +00:00
return slog.GroupValue(groupValues...)
}
2024-04-17 08:36:14 +00:00
2024-06-14 22:14:44 +00:00
func Component(name ...string) *Logger {
2024-04-17 08:36:14 +00:00
return &Logger{
handler: handler,
2024-06-14 22:14:44 +00:00
component: name,
2024-04-17 08:36:14 +00:00
}
}