royalcat
5591f145a9
All checks were successful
docker / build-docker (linux/amd64) (push) Successful in 2m17s
docker / build-docker (linux/386) (push) Successful in 2m22s
docker / build-docker (linux/arm64/v8) (push) Successful in 8m12s
docker / build-docker (linux/arm64) (push) Successful in 8m22s
docker / build-docker (linux/arm/v7) (push) Successful in 8m48s
134 lines
2.9 KiB
Go
134 lines
2.9 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,
|
|
}
|
|
}
|
|
|
|
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: []string{name},
|
|
}
|
|
}
|