155 lines
2.8 KiB
Go
155 lines
2.8 KiB
Go
package logger
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type _key string
|
|
|
|
//nolint:gochecknoglobals // ...
|
|
var loggerKey _key = "_core_logger"
|
|
|
|
type LoggerOpt func(p *loggerParams)
|
|
|
|
func NewLoggerContext(ctx context.Context, opts ...LoggerOpt) context.Context {
|
|
p := new(loggerParams)
|
|
|
|
for _, o := range opts {
|
|
o(p)
|
|
}
|
|
|
|
log := p.build()
|
|
|
|
return context.WithValue(ctx, loggerKey, log)
|
|
}
|
|
|
|
type loggerParams struct {
|
|
local bool
|
|
addSource bool
|
|
lvl slog.Level
|
|
writers []io.Writer
|
|
}
|
|
|
|
func WithWriter(w io.Writer) LoggerOpt {
|
|
return func(p *loggerParams) {
|
|
p.writers = append(p.writers, w)
|
|
}
|
|
}
|
|
|
|
func WithLevel(l slog.Level) LoggerOpt {
|
|
return func(p *loggerParams) {
|
|
p.lvl = l
|
|
}
|
|
}
|
|
|
|
func Local() LoggerOpt {
|
|
return func(p *loggerParams) {
|
|
p.local = true
|
|
}
|
|
}
|
|
|
|
func WithSource() LoggerOpt {
|
|
return func(p *loggerParams) {
|
|
p.addSource = true
|
|
}
|
|
}
|
|
|
|
func Err(err error) slog.Attr {
|
|
return slog.Attr{
|
|
Key: "error",
|
|
Value: slog.StringValue(err.Error()),
|
|
}
|
|
}
|
|
|
|
func MapLevel(lvl string) slog.Level {
|
|
switch strings.ToLower(lvl) {
|
|
case "debug":
|
|
return LevelDebug
|
|
case "info":
|
|
return LevelInfo
|
|
case "notice":
|
|
return LevelNotice
|
|
case "warn":
|
|
return LevelWarn
|
|
case "error":
|
|
return LevelError
|
|
case "critical":
|
|
return LevelCritial
|
|
case "alert":
|
|
return LevelAlert
|
|
case "emergency":
|
|
return LevelEmergency
|
|
default:
|
|
return LevelInfo
|
|
}
|
|
}
|
|
|
|
func (b *loggerParams) build() *slog.Logger {
|
|
if len(b.writers) == 0 {
|
|
b.writers = append(b.writers, os.Stdout)
|
|
}
|
|
|
|
w := io.MultiWriter(b.writers...)
|
|
|
|
if b.local {
|
|
opts := prettyHandlerOptions{
|
|
SlogOpts: &slog.HandlerOptions{
|
|
Level: b.lvl,
|
|
AddSource: b.addSource,
|
|
},
|
|
}
|
|
|
|
handler := opts.newPrettyHandler(w)
|
|
|
|
return slog.New(handler)
|
|
}
|
|
|
|
return newLogger(b.lvl, w)
|
|
}
|
|
|
|
func newLogger(lvl slog.Level, w io.Writer) *slog.Logger {
|
|
return slog.New(
|
|
slog.NewJSONHandler(w, &slog.HandlerOptions{
|
|
Level: lvl,
|
|
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
|
|
if a.Key == slog.LevelKey {
|
|
level := a.Value.Any().(slog.Level)
|
|
|
|
switch {
|
|
case level < LevelInfo:
|
|
a.Value = slog.StringValue("DEBUG")
|
|
case level < LevelNotice:
|
|
a.Value = slog.StringValue("INFO")
|
|
case level < LevelWarn:
|
|
a.Value = slog.StringValue("NOTICE")
|
|
case level < LevelError:
|
|
a.Value = slog.StringValue("WARNING")
|
|
case level < LevelCritial:
|
|
a.Value = slog.StringValue("ERROR")
|
|
case level < LevelAlert:
|
|
a.Value = slog.StringValue("CRITICAL")
|
|
case level < LevelEmergency:
|
|
a.Value = slog.StringValue("ALERT")
|
|
default:
|
|
a.Value = slog.StringValue("EMERGENCY")
|
|
}
|
|
}
|
|
|
|
return a
|
|
},
|
|
}),
|
|
)
|
|
}
|
|
|
|
func loggerFromCtx(ctx context.Context) *slog.Logger {
|
|
if l, ok := ctx.Value(loggerKey).(*slog.Logger); ok {
|
|
return l
|
|
}
|
|
|
|
return globalLogger
|
|
}
|