logger/slog: backport default logger keys from master #311
@ -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"))))
|
||||
|
@ -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
|
||||
@ -30,18 +43,29 @@ type Options struct {
|
||||
// NewOptions creates new options struct
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Level: DefaultLevel,
|
||||
Fields: make([]interface{}, 0, 6),
|
||||
Out: os.Stderr,
|
||||
CallerSkipCount: DefaultCallerSkipCount,
|
||||
Context: context.Background(),
|
||||
Level: DefaultLevel,
|
||||
Fields: make([]interface{}, 0, 6),
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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
|
||||
@ -69,14 +62,10 @@ 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
|
||||
slog *slog.Logger
|
||||
leveler *slog.LevelVar
|
||||
opts logger.Options
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *slogLogger) Clone(opts ...logger.Option) logger.Logger {
|
||||
@ -88,24 +77,7 @@ 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
|
||||
opts: options,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@ -399,24 +373,9 @@ 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
|
||||
opts: logger.NewOptions(opts...),
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user