logger/slog: backport default logger keys from master
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
de4418189d
commit
4af2b077dd
@ -6,6 +6,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ContextAttrFunc func(ctx context.Context) []interface{}
|
||||||
|
|
||||||
|
var DefaultContextAttrFuncs []ContextAttrFunc
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultLogger variable
|
// DefaultLogger variable
|
||||||
DefaultLogger = NewLogger(WithLevel(ParseLevel(os.Getenv("MICRO_LOG_LEVEL"))))
|
DefaultLogger = NewLogger(WithLevel(ParseLevel(os.Getenv("MICRO_LOG_LEVEL"))))
|
||||||
|
@ -3,6 +3,7 @@ package logger
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,6 +22,18 @@ type Options struct {
|
|||||||
Fields []interface{}
|
Fields []interface{}
|
||||||
// CallerSkipCount number of frmaes to skip
|
// CallerSkipCount number of frmaes to skip
|
||||||
CallerSkipCount int
|
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 controls writing of stacktaces on error
|
||||||
Stacktrace bool
|
Stacktrace bool
|
||||||
// The logging level the logger should log
|
// The logging level the logger should log
|
||||||
@ -30,18 +43,29 @@ type Options struct {
|
|||||||
// NewOptions creates new options struct
|
// NewOptions creates new options struct
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Level: DefaultLevel,
|
Level: DefaultLevel,
|
||||||
Fields: make([]interface{}, 0, 6),
|
Fields: make([]interface{}, 0, 6),
|
||||||
Out: os.Stderr,
|
Out: os.Stderr,
|
||||||
CallerSkipCount: DefaultCallerSkipCount,
|
CallerSkipCount: DefaultCallerSkipCount,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
|
ContextAttrFuncs: DefaultContextAttrFuncs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WithMicroKeys()(&options)
|
||||||
|
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
return 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
|
// WithFields set default fields for the logger
|
||||||
func WithFields(fields ...interface{}) Option {
|
func WithFields(fields ...interface{}) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
@ -90,3 +114,43 @@ func WithName(n string) Option {
|
|||||||
o.Name = n
|
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 reTrace = regexp.MustCompile(`.*/slog/logger\.go.*\n`)
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultSourceKey = slog.SourceKey
|
|
||||||
DefaultTimeKey = slog.TimeKey
|
|
||||||
DefaultMessageKey = slog.MessageKey
|
|
||||||
DefaultLevelKey = slog.LevelKey
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
traceValue = slog.StringValue("trace")
|
traceValue = slog.StringValue("trace")
|
||||||
debugValue = slog.StringValue("debug")
|
debugValue = slog.StringValue("debug")
|
||||||
@ -38,15 +31,15 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
|
|||||||
case slog.SourceKey:
|
case slog.SourceKey:
|
||||||
source := a.Value.Any().(*slog.Source)
|
source := a.Value.Any().(*slog.Source)
|
||||||
a.Value = slog.StringValue(source.File + ":" + strconv.Itoa(source.Line))
|
a.Value = slog.StringValue(source.File + ":" + strconv.Itoa(source.Line))
|
||||||
a.Key = s.sourceKey
|
a.Key = s.opts.SourceKey
|
||||||
case slog.TimeKey:
|
case slog.TimeKey:
|
||||||
a.Key = s.timeKey
|
a.Key = s.opts.TimeKey
|
||||||
case slog.MessageKey:
|
case slog.MessageKey:
|
||||||
a.Key = s.messageKey
|
a.Key = s.opts.MessageKey
|
||||||
case slog.LevelKey:
|
case slog.LevelKey:
|
||||||
level := a.Value.Any().(slog.Level)
|
level := a.Value.Any().(slog.Level)
|
||||||
lvl := slogToLoggerLevel(level)
|
lvl := slogToLoggerLevel(level)
|
||||||
a.Key = s.levelKey
|
a.Key = s.opts.LevelKey
|
||||||
switch {
|
switch {
|
||||||
case lvl < logger.DebugLevel:
|
case lvl < logger.DebugLevel:
|
||||||
a.Value = traceValue
|
a.Value = traceValue
|
||||||
@ -69,14 +62,10 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type slogLogger struct {
|
type slogLogger struct {
|
||||||
slog *slog.Logger
|
slog *slog.Logger
|
||||||
leveler *slog.LevelVar
|
leveler *slog.LevelVar
|
||||||
levelKey string
|
opts logger.Options
|
||||||
messageKey string
|
mu sync.RWMutex
|
||||||
sourceKey string
|
|
||||||
timeKey string
|
|
||||||
opts logger.Options
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Clone(opts ...logger.Option) logger.Logger {
|
func (s *slogLogger) Clone(opts ...logger.Option) logger.Logger {
|
||||||
@ -88,24 +77,7 @@ func (s *slogLogger) Clone(opts ...logger.Option) logger.Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l := &slogLogger{
|
l := &slogLogger{
|
||||||
opts: options,
|
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)
|
l.leveler = new(slog.LevelVar)
|
||||||
@ -137,13 +109,7 @@ func (s *slogLogger) Options() logger.Options {
|
|||||||
|
|
||||||
func (s *slogLogger) Fields(attrs ...interface{}) logger.Logger {
|
func (s *slogLogger) Fields(attrs ...interface{}) logger.Logger {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
nl := &slogLogger{
|
nl := &slogLogger{opts: s.opts}
|
||||||
opts: s.opts,
|
|
||||||
levelKey: s.levelKey,
|
|
||||||
messageKey: s.messageKey,
|
|
||||||
sourceKey: s.sourceKey,
|
|
||||||
timeKey: s.timeKey,
|
|
||||||
}
|
|
||||||
nl.leveler = new(slog.LevelVar)
|
nl.leveler = new(slog.LevelVar)
|
||||||
nl.leveler.Set(s.leveler.Level())
|
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 {
|
func (s *slogLogger) Init(opts ...logger.Option) error {
|
||||||
s.mu.Lock()
|
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 != "" {
|
for _, o := range opts {
|
||||||
s.levelKey = v
|
o(&s.opts)
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.leveler = new(slog.LevelVar)
|
s.leveler = new(slog.LevelVar)
|
||||||
@ -190,8 +148,6 @@ func (s *slogLogger) Init(opts ...logger.Option) error {
|
|||||||
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
|
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
|
||||||
s.slog = slog.New(handler).With(s.opts.Fields...)
|
s.slog = slog.New(handler).With(s.opts.Fields...)
|
||||||
|
|
||||||
slog.SetDefault(s.slog)
|
|
||||||
|
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -204,6 +160,15 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, attrs ...interfa
|
|||||||
var pcs [1]uintptr
|
var pcs [1]uintptr
|
||||||
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
||||||
r := slog.NewRecord(time.Now(), loggerToSlogLevel(lvl), fmt.Sprintf("%s", attrs[0]), pcs[0])
|
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:]...)
|
// r.Add(attrs[1:]...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = 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
|
var pcs [1]uintptr
|
||||||
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
runtime.Callers(s.opts.CallerSkipCount, pcs[:]) // skip [Callers, Infof]
|
||||||
r := slog.NewRecord(time.Now(), loggerToSlogLevel(lvl), fmt.Sprintf(msg, attrs...), pcs[0])
|
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...)
|
// r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
}
|
}
|
||||||
@ -399,24 +373,9 @@ func (s *slogLogger) String() string {
|
|||||||
|
|
||||||
func NewLogger(opts ...logger.Option) logger.Logger {
|
func NewLogger(opts ...logger.Option) logger.Logger {
|
||||||
s := &slogLogger{
|
s := &slogLogger{
|
||||||
opts: logger.NewOptions(opts...),
|
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
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user