tstor/pkg/rlog/rlog.go
royalcat e9df8925d1
Some checks failed
docker / build-docker (linux/amd64) (push) Failing after 18s
docker / build-docker (linux/386) (push) Successful in 1m57s
docker / build-docker (linux/arm64) (push) Successful in 7m22s
docker / build-docker (linux/arm/v7) (push) Successful in 7m53s
docker / build-docker (linux/arm64/v8) (push) Failing after 3h2m18s
storage rework
2024-06-15 01:14:44 +03:00

140 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
component []string
}
const functionKey = "function"
func (l *Logger) log(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) {
var pcs [1]uintptr
runtime.Callers(3, pcs[:])
pc := pcs[0]
f := runtime.FuncForPC(pc)
attrs = append(attrs, slog.String(functionKey, f.Name()))
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...)
}
const componentKey = "component"
const componentSep = "."
func (log *Logger) WithComponent(name string) *Logger {
c := append(log.component, name)
return &Logger{
handler: log.handler.WithAttrs([]slog.Attr{
slog.String(componentKey, strings.Join(c, componentSep)),
}),
component: c,
}
}
func (l *Logger) With(attrs ...slog.Attr) *Logger {
return &Logger{
handler: l.handler.WithAttrs(attrs),
component: l.component,
}
}
// 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 endpointKey = "endpoint"
func (l *Logger) WithEndpoint(name string) *Logger {
return &Logger{
handler: l.handler.WithAttrs([]slog.Attr{
slog.String(endpointKey, name),
}),
component: l.component,
}
}
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,
}
}