logger/slog: backport default logger keys from master #311

Merged
vtolstov merged 1 commits from v3-logger into v3 2024-03-05 01:54:19 +03:00
4 changed files with 108 additions and 108 deletions

View File

@ -6,6 +6,10 @@ import (
"os"
)
type ContextAttrFunc func(ctx context.Context) []interface{}
var DefaultContextAttrFuncs []ContextAttrFunc
var (
// DefaultLogger variable
DefaultLogger = NewLogger(WithLevel(ParseLevel(os.Getenv("MICRO_LOG_LEVEL"))))

View File

@ -3,6 +3,7 @@ package logger
import (
"context"
"io"
"log/slog"
"os"
)
@ -21,6 +22,18 @@ type Options struct {
Fields []interface{}
// CallerSkipCount number of frmaes to skip
CallerSkipCount int
// ContextAttrFuncs contains funcs that executed before log func on context
ContextAttrFuncs []ContextAttrFunc
// TimeKey is the key used for the time of the log call
TimeKey string
// LevelKey is the key used for the level of the log call
LevelKey string
// MessageKey is the key used for the message of the log call
MessageKey string
// SourceKey is the key used for the source file and line of the log call
SourceKey string
// StacktraceKey is the key used for the stacktrace
StacktraceKey string
// Stacktrace controls writing of stacktaces on error
Stacktrace bool
// The logging level the logger should log
@ -35,13 +48,24 @@ func NewOptions(opts ...Option) Options {
Out: os.Stderr,
CallerSkipCount: DefaultCallerSkipCount,
Context: context.Background(),
ContextAttrFuncs: DefaultContextAttrFuncs,
}
WithMicroKeys()(&options)
for _, o := range opts {
o(&options)
}
return options
}
// WithContextAttrFuncs appends default funcs for the context arrts filler
func WithContextAttrFuncs(fncs ...ContextAttrFunc) Option {
return func(o *Options) {
o.ContextAttrFuncs = append(o.ContextAttrFuncs, fncs...)
}
}
// WithFields set default fields for the logger
func WithFields(fields ...interface{}) Option {
return func(o *Options) {
@ -90,3 +114,43 @@ func WithName(n string) Option {
o.Name = n
}
}
func WithZapKeys() Option {
return func(o *Options) {
o.TimeKey = "@timestamp"
o.LevelKey = "level"
o.MessageKey = "msg"
o.SourceKey = "caller"
o.StacktraceKey = "stacktrace"
}
}
func WithZerologKeys() Option {
return func(o *Options) {
o.TimeKey = "time"
o.LevelKey = "level"
o.MessageKey = "message"
o.SourceKey = "caller"
o.StacktraceKey = "stacktrace"
}
}
func WithSlogKeys() Option {
return func(o *Options) {
o.TimeKey = slog.TimeKey
o.LevelKey = slog.LevelKey
o.MessageKey = slog.MessageKey
o.SourceKey = slog.SourceKey
o.StacktraceKey = "stacktrace"
}
}
func WithMicroKeys() Option {
return func(o *Options) {
o.TimeKey = "timestamp"
o.LevelKey = "level"
o.MessageKey = "msg"
o.SourceKey = "caller"
o.StacktraceKey = "stacktrace"
}
}

View File

@ -1,27 +0,0 @@
package slog
import "go.unistack.org/micro/v3/logger"
type sourceKey struct{}
func WithSourceKey(v string) logger.Option {
return logger.SetOption(sourceKey{}, v)
}
type timeKey struct{}
func WithTimeKey(v string) logger.Option {
return logger.SetOption(timeKey{}, v)
}
type messageKey struct{}
func WithMessageKey(v string) logger.Option {
return logger.SetOption(messageKey{}, v)
}
type levelKey struct{}
func WithLevelKey(v string) logger.Option {
return logger.SetOption(levelKey{}, v)
}

View File

@ -17,13 +17,6 @@ import (
var reTrace = regexp.MustCompile(`.*/slog/logger\.go.*\n`)
var (
DefaultSourceKey = slog.SourceKey
DefaultTimeKey = slog.TimeKey
DefaultMessageKey = slog.MessageKey
DefaultLevelKey = slog.LevelKey
)
var (
traceValue = slog.StringValue("trace")
debugValue = slog.StringValue("debug")
@ -38,15 +31,15 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
case slog.SourceKey:
source := a.Value.Any().(*slog.Source)
a.Value = slog.StringValue(source.File + ":" + strconv.Itoa(source.Line))
a.Key = s.sourceKey
a.Key = s.opts.SourceKey
case slog.TimeKey:
a.Key = s.timeKey
a.Key = s.opts.TimeKey
case slog.MessageKey:
a.Key = s.messageKey
a.Key = s.opts.MessageKey
case slog.LevelKey:
level := a.Value.Any().(slog.Level)
lvl := slogToLoggerLevel(level)
a.Key = s.levelKey
a.Key = s.opts.LevelKey
switch {
case lvl < logger.DebugLevel:
a.Value = traceValue
@ -71,10 +64,6 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
type slogLogger struct {
slog *slog.Logger
leveler *slog.LevelVar
levelKey string
messageKey string
sourceKey string
timeKey string
opts logger.Options
mu sync.RWMutex
}
@ -89,23 +78,6 @@ func (s *slogLogger) Clone(opts ...logger.Option) logger.Logger {
l := &slogLogger{
opts: options,
levelKey: s.levelKey,
messageKey: s.messageKey,
sourceKey: s.sourceKey,
timeKey: s.timeKey,
}
if v, ok := l.opts.Context.Value(levelKey{}).(string); ok && v != "" {
l.levelKey = v
}
if v, ok := l.opts.Context.Value(messageKey{}).(string); ok && v != "" {
l.messageKey = v
}
if v, ok := l.opts.Context.Value(sourceKey{}).(string); ok && v != "" {
l.sourceKey = v
}
if v, ok := l.opts.Context.Value(timeKey{}).(string); ok && v != "" {
l.timeKey = v
}
l.leveler = new(slog.LevelVar)
@ -137,13 +109,7 @@ func (s *slogLogger) Options() logger.Options {
func (s *slogLogger) Fields(attrs ...interface{}) logger.Logger {
s.mu.RLock()
nl := &slogLogger{
opts: s.opts,
levelKey: s.levelKey,
messageKey: s.messageKey,
sourceKey: s.sourceKey,
timeKey: s.timeKey,
}
nl := &slogLogger{opts: s.opts}
nl.leveler = new(slog.LevelVar)
nl.leveler.Set(s.leveler.Level())
@ -163,21 +129,13 @@ func (s *slogLogger) Fields(attrs ...interface{}) logger.Logger {
func (s *slogLogger) Init(opts ...logger.Option) error {
s.mu.Lock()
for _, o := range opts {
o(&s.opts)
if len(s.opts.ContextAttrFuncs) == 0 {
s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs
}
if v, ok := s.opts.Context.Value(levelKey{}).(string); ok && v != "" {
s.levelKey = v
}
if v, ok := s.opts.Context.Value(messageKey{}).(string); ok && v != "" {
s.messageKey = v
}
if v, ok := s.opts.Context.Value(sourceKey{}).(string); ok && v != "" {
s.sourceKey = v
}
if v, ok := s.opts.Context.Value(timeKey{}).(string); ok && v != "" {
s.timeKey = v
for _, o := range opts {
o(&s.opts)
}
s.leveler = new(slog.LevelVar)
@ -190,8 +148,6 @@ func (s *slogLogger) Init(opts ...logger.Option) error {
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
s.slog = slog.New(handler).With(s.opts.Fields...)
slog.SetDefault(s.slog)
s.mu.Unlock()
return nil
@ -204,6 +160,15 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, attrs ...interfa
var pcs [1]uintptr
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), loggerToSlogLevel(lvl), fmt.Sprintf("%s", attrs[0]), pcs[0])
if s.opts.Stacktrace && lvl == logger.ErrorLevel {
stackInfo := make([]byte, 1024*1024)
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
if len(traceLines) != 0 {
r.AddAttrs(slog.String(s.opts.StacktraceKey, traceLines[len(traceLines)-1]))
}
}
}
// r.Add(attrs[1:]...)
_ = s.slog.Handler().Handle(ctx, r)
}
@ -215,6 +180,15 @@ func (s *slogLogger) Logf(ctx context.Context, lvl logger.Level, msg string, att
var pcs [1]uintptr
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
r := slog.NewRecord(time.Now(), loggerToSlogLevel(lvl), fmt.Sprintf(msg, attrs...), pcs[0])
if s.opts.Stacktrace && lvl == logger.ErrorLevel {
stackInfo := make([]byte, 1024*1024)
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
if len(traceLines) != 0 {
r.AddAttrs(slog.String(s.opts.StacktraceKey, traceLines[len(traceLines)-1]))
}
}
}
// r.Add(attrs...)
_ = s.slog.Handler().Handle(ctx, r)
}
@ -400,23 +374,8 @@ func (s *slogLogger) String() string {
func NewLogger(opts ...logger.Option) logger.Logger {
s := &slogLogger{
opts: logger.NewOptions(opts...),
sourceKey: DefaultSourceKey,
timeKey: DefaultTimeKey,
messageKey: DefaultMessageKey,
levelKey: DefaultLevelKey,
}
if v, ok := s.opts.Context.Value(levelKey{}).(string); ok && v != "" {
s.levelKey = v
}
if v, ok := s.opts.Context.Value(messageKey{}).(string); ok && v != "" {
s.messageKey = v
}
if v, ok := s.opts.Context.Value(sourceKey{}).(string); ok && v != "" {
s.sourceKey = v
}
if v, ok := s.opts.Context.Value(timeKey{}).(string); ok && v != "" {
s.timeKey = v
}
return s
}