logger: add ability to fill fileds from context #269
@ -17,6 +17,10 @@ var (
|
|||||||
DefaultCallerSkipCount = 2
|
DefaultCallerSkipCount = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ContextAttrFunc func(ctx context.Context) []interface{}
|
||||||
|
|
||||||
|
var DefaultContextAttrFuncs []ContextAttrFunc
|
||||||
|
|
||||||
// Logger is a generic logging interface
|
// Logger is a generic logging interface
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
// Init initialises options
|
// Init initialises options
|
||||||
@ -29,57 +33,54 @@ type Logger interface {
|
|||||||
Level(level Level)
|
Level(level Level)
|
||||||
// The Logger options
|
// The Logger options
|
||||||
Options() Options
|
Options() Options
|
||||||
// Fields set fields to always be logged with keyval pairs
|
// Attrs set attrs to always be logged with keyval pairs
|
||||||
Fields(fields ...interface{}) Logger
|
Attrs(attrs ...interface{}) Logger
|
||||||
// Info level message
|
// Info level message
|
||||||
Info(ctx context.Context, msg string, args ...interface{})
|
Info(ctx context.Context, msg string, attrs ...interface{})
|
||||||
// Tracef level message
|
// Tracef level message
|
||||||
Trace(ctx context.Context, msg string, args ...interface{})
|
Trace(ctx context.Context, msg string, attrs ...interface{})
|
||||||
// Debug level message
|
// Debug level message
|
||||||
Debug(ctx context.Context, msg string, args ...interface{})
|
Debug(ctx context.Context, msg string, attrs ...interface{})
|
||||||
// Warn level message
|
// Warn level message
|
||||||
Warn(ctx context.Context, msg string, args ...interface{})
|
Warn(ctx context.Context, msg string, attrs ...interface{})
|
||||||
// Error level message
|
// Error level message
|
||||||
Error(ctx context.Context, msg string, args ...interface{})
|
Error(ctx context.Context, msg string, attrs ...interface{})
|
||||||
// Fatal level message
|
// Fatal level message
|
||||||
Fatal(ctx context.Context, msg string, args ...interface{})
|
Fatal(ctx context.Context, msg string, attrs ...interface{})
|
||||||
// Log logs message with needed level
|
// Log logs message with needed level
|
||||||
Log(ctx context.Context, level Level, msg string, args ...interface{})
|
Log(ctx context.Context, level Level, msg string, attrs ...interface{})
|
||||||
// String returns the name of logger
|
// String returns the name of logger
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field contains keyval pair
|
|
||||||
type Field interface{}
|
|
||||||
|
|
||||||
// Info writes formatted msg to default logger on info level
|
// Info writes formatted msg to default logger on info level
|
||||||
func Info(ctx context.Context, msg string, args ...interface{}) {
|
func Info(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
DefaultLogger.Info(ctx, msg, args...)
|
DefaultLogger.Info(ctx, msg, attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error writes formatted msg to default logger on error level
|
// Error writes formatted msg to default logger on error level
|
||||||
func Error(ctx context.Context, msg string, args ...interface{}) {
|
func Error(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
DefaultLogger.Error(ctx, msg, args...)
|
DefaultLogger.Error(ctx, msg, attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debugf writes formatted msg to default logger on debug level
|
// Debugf writes formatted msg to default logger on debug level
|
||||||
func Debugf(ctx context.Context, msg string, args ...interface{}) {
|
func Debugf(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
DefaultLogger.Debug(ctx, msg, args...)
|
DefaultLogger.Debug(ctx, msg, attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warn writes formatted msg to default logger on warn level
|
// Warn writes formatted msg to default logger on warn level
|
||||||
func Warn(ctx context.Context, msg string, args ...interface{}) {
|
func Warn(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
DefaultLogger.Warn(ctx, msg, args...)
|
DefaultLogger.Warn(ctx, msg, attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace writes formatted msg to default logger on trace level
|
// Trace writes formatted msg to default logger on trace level
|
||||||
func Trace(ctx context.Context, msg string, args ...interface{}) {
|
func Trace(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
DefaultLogger.Trace(ctx, msg, args...)
|
DefaultLogger.Trace(ctx, msg, attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal writes formatted msg to default logger on fatal level
|
// Fatal writes formatted msg to default logger on fatal level
|
||||||
func Fatal(ctx context.Context, msg string, args ...interface{}) {
|
func Fatal(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
DefaultLogger.Fatal(ctx, msg, args...)
|
DefaultLogger.Fatal(ctx, msg, attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// V returns true if passed level enabled in default logger
|
// V returns true if passed level enabled in default logger
|
||||||
@ -87,12 +88,12 @@ func V(level Level) bool {
|
|||||||
return DefaultLogger.V(level)
|
return DefaultLogger.V(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize logger
|
// Init initialize default logger
|
||||||
func Init(opts ...options.Option) error {
|
func Init(opts ...options.Option) error {
|
||||||
return DefaultLogger.Init(opts...)
|
return DefaultLogger.Init(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields create logger with specific fields
|
// Attrs create default logger with specific attrs
|
||||||
func Fields(fields ...interface{}) Logger {
|
func Attrs(attrs ...interface{}) Logger {
|
||||||
return DefaultLogger.Fields(fields...)
|
return DefaultLogger.Attrs(attrs...)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ func TestContext(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nl, ok := FromContext(NewContext(ctx, l.Fields("key", "val")))
|
nl, ok := FromContext(NewContext(ctx, l.Attrs("key", "val")))
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("context without logger")
|
t.Fatal("context without logger")
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ func TestContext(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFields(t *testing.T) {
|
func TestAttrs(t *testing.T) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf))
|
l := NewLogger(WithLevel(TraceLevel), WithOutput(buf))
|
||||||
@ -33,7 +33,7 @@ func TestFields(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nl := l.Fields("key", "val")
|
nl := l.Attrs("key", "val")
|
||||||
|
|
||||||
nl.Info(ctx, "message")
|
nl.Info(ctx, "message")
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`"key":"val"`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`"key":"val"`)) {
|
||||||
@ -49,7 +49,7 @@ func TestFromContextWithFields(t *testing.T) {
|
|||||||
if err := l.Init(); err != nil {
|
if err := l.Init(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
nl := l.Fields("key", "val")
|
nl := l.Attrs("key", "val")
|
||||||
|
|
||||||
ctx = NewContext(ctx, nl)
|
ctx = NewContext(ctx, nl)
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ func TestLogger(t *testing.T) {
|
|||||||
}
|
}
|
||||||
l.Trace(ctx, "trace_msg1")
|
l.Trace(ctx, "trace_msg1")
|
||||||
l.Warn(ctx, "warn_msg1")
|
l.Warn(ctx, "warn_msg1")
|
||||||
l.Fields("error", "test").Info(ctx, "error message")
|
l.Attrs("error", "test").Info(ctx, "error message")
|
||||||
l.Warn(ctx, "first second")
|
l.Warn(ctx, "first second")
|
||||||
|
|
||||||
if !(bytes.Contains(buf.Bytes(), []byte(`"level":"trace"`)) && bytes.Contains(buf.Bytes(), []byte(`"msg":"trace_msg1"`))) {
|
if !(bytes.Contains(buf.Bytes(), []byte(`"level":"trace"`)) && bytes.Contains(buf.Bytes(), []byte(`"msg":"trace_msg1"`))) {
|
||||||
|
@ -4,8 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"go.unistack.org/micro/v4/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
|
rutil "go.unistack.org/micro/v4/util/reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options holds logger options
|
// Options holds logger options
|
||||||
@ -14,24 +16,27 @@ type Options struct {
|
|||||||
Out io.Writer
|
Out io.Writer
|
||||||
// Context holds exernal options
|
// Context holds exernal options
|
||||||
Context context.Context
|
Context context.Context
|
||||||
// Fields holds additional metadata
|
// Attrs holds additional attributes
|
||||||
Fields []interface{}
|
Attrs []interface{}
|
||||||
// Name holds the logger name
|
// Name holds the logger name
|
||||||
Name string
|
Name string
|
||||||
// The logging level the logger should log
|
// The logging level the logger should log
|
||||||
Level Level
|
Level Level
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOptions creates new options struct
|
// NewOptions creates new options struct
|
||||||
func NewOptions(opts ...options.Option) Options {
|
func NewOptions(opts ...options.Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Level: DefaultLevel,
|
Level: DefaultLevel,
|
||||||
Fields: make([]interface{}, 0, 6),
|
Attrs: make([]interface{}, 0, 6),
|
||||||
Out: os.Stderr,
|
Out: os.Stderr,
|
||||||
CallerSkipCount: DefaultCallerSkipCount,
|
CallerSkipCount: DefaultCallerSkipCount,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
|
ContextAttrFuncs: DefaultContextAttrFuncs,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
@ -39,10 +44,27 @@ func NewOptions(opts ...options.Option) Options {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithFields set default fields for the logger
|
// WithContextAttrFuncs appends default funcs for the context arrts filler
|
||||||
func WithFields(fields ...interface{}) options.Option {
|
func WithContextAttrFuncs(attrs ...interface{}) options.Option {
|
||||||
return func(src interface{}) error {
|
return func(src interface{}) error {
|
||||||
return options.Set(src, fields, ".Fields")
|
v, err := options.Get(src, ".ContextAttrFuncs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if rutil.IsZero(v) {
|
||||||
|
v = reflect.MakeSlice(reflect.TypeOf(v), 0, len(attrs)).Interface()
|
||||||
|
}
|
||||||
|
cv := reflect.ValueOf(v)
|
||||||
|
for _, l := range attrs {
|
||||||
|
cv = reflect.Append(cv, reflect.ValueOf(l))
|
||||||
|
}
|
||||||
|
return options.Set(src, cv.Interface(), ".ContextAttrFuncs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAttrs set default fields for the logger
|
||||||
|
func WithAttrs(attrs ...interface{}) options.Option {
|
||||||
|
return func(src interface{}) error {
|
||||||
|
return options.Set(src, attrs, ".Attrs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,6 @@ var renameAttr = func(_ []string, a slog.Attr) slog.Attr {
|
|||||||
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 = "caller"
|
a.Key = "caller"
|
||||||
// add func?
|
|
||||||
// "trace": "<traceid>",
|
|
||||||
// "span": "<spanid>",
|
|
||||||
case slog.TimeKey:
|
case slog.TimeKey:
|
||||||
a.Key = "timestamp"
|
a.Key = "timestamp"
|
||||||
case slog.LevelKey:
|
case slog.LevelKey:
|
||||||
@ -85,7 +82,7 @@ func (s *slogLogger) Clone(opts ...options.Option) Logger {
|
|||||||
}
|
}
|
||||||
l.leveler.Set(loggerToSlogLevel(l.opts.Level))
|
l.leveler.Set(loggerToSlogLevel(l.opts.Level))
|
||||||
handler := slog.NewJSONHandler(options.Out, handleOpt)
|
handler := slog.NewJSONHandler(options.Out, handleOpt)
|
||||||
l.slog = slog.New(handler).With(options.Fields...)
|
l.slog = slog.New(handler).With(options.Attrs...)
|
||||||
|
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
@ -102,7 +99,7 @@ func (s *slogLogger) Options() Options {
|
|||||||
return s.opts
|
return s.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Fields(fields ...interface{}) Logger {
|
func (s *slogLogger) Attrs(attrs ...interface{}) Logger {
|
||||||
nl := &slogLogger{opts: s.opts}
|
nl := &slogLogger{opts: s.opts}
|
||||||
nl.leveler = new(slog.LevelVar)
|
nl.leveler = new(slog.LevelVar)
|
||||||
nl.leveler.Set(s.leveler.Level())
|
nl.leveler.Set(s.leveler.Level())
|
||||||
@ -114,7 +111,7 @@ func (s *slogLogger) Fields(fields ...interface{}) Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
|
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
|
||||||
nl.slog = slog.New(handler).With(fields...)
|
nl.slog = slog.New(handler).With(attrs...)
|
||||||
|
|
||||||
return nl
|
return nl
|
||||||
}
|
}
|
||||||
@ -139,86 +136,107 @@ func (s *slogLogger) Init(opts ...options.Option) error {
|
|||||||
}
|
}
|
||||||
s.leveler.Set(loggerToSlogLevel(s.opts.Level))
|
s.leveler.Set(loggerToSlogLevel(s.opts.Level))
|
||||||
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.Attrs...)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Log(ctx context.Context, lvl Level, msg string, args ...any) {
|
func (s *slogLogger) Log(ctx context.Context, lvl Level, msg string, attrs ...interface{}) {
|
||||||
if !s.V(lvl) {
|
if !s.V(lvl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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), msg, pcs[0])
|
r := slog.NewRecord(time.Now(), loggerToSlogLevel(lvl), msg, pcs[0])
|
||||||
r.Add(args...)
|
for _, fn := range s.opts.ContextAttrFuncs {
|
||||||
|
attrs = append(attrs, fn(ctx))
|
||||||
|
}
|
||||||
|
r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Info(ctx context.Context, msg string, args ...interface{}) {
|
func (s *slogLogger) Info(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
if !s.V(InfoLevel) {
|
if !s.V(InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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(), slog.LevelInfo, msg, pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelInfo, msg, pcs[0])
|
||||||
r.Add(args...)
|
for _, fn := range s.opts.ContextAttrFuncs {
|
||||||
|
attrs = append(attrs, fn(ctx))
|
||||||
|
}
|
||||||
|
r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Debug(ctx context.Context, msg string, args ...any) {
|
func (s *slogLogger) Debug(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
if !s.V(InfoLevel) {
|
if !s.V(InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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(), slog.LevelDebug, msg, pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelDebug, msg, pcs[0])
|
||||||
r.Add(args...)
|
for _, fn := range s.opts.ContextAttrFuncs {
|
||||||
|
attrs = append(attrs, fn(ctx))
|
||||||
|
}
|
||||||
|
r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Trace(ctx context.Context, msg string, args ...interface{}) {
|
func (s *slogLogger) Trace(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
if !s.V(InfoLevel) {
|
if !s.V(InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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(), slog.LevelDebug-1, msg, pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelDebug-1, msg, pcs[0])
|
||||||
r.Add(args...)
|
for _, fn := range s.opts.ContextAttrFuncs {
|
||||||
|
attrs = append(attrs, fn(ctx))
|
||||||
|
}
|
||||||
|
r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Error(ctx context.Context, msg string, args ...any) {
|
func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
if !s.V(InfoLevel) {
|
if !s.V(InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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(), slog.LevelError, msg, pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelError, msg, pcs[0])
|
||||||
r.Add(args...)
|
for _, fn := range s.opts.ContextAttrFuncs {
|
||||||
|
attrs = append(attrs, fn(ctx))
|
||||||
|
}
|
||||||
|
r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Fatal(ctx context.Context, msg string, args ...interface{}) {
|
func (s *slogLogger) Fatal(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
if !s.V(InfoLevel) {
|
if !s.V(InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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(), slog.LevelError+1, msg, pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelError+1, msg, pcs[0])
|
||||||
r.Add(args...)
|
for _, fn := range s.opts.ContextAttrFuncs {
|
||||||
|
attrs = append(attrs, fn(ctx))
|
||||||
|
}
|
||||||
|
r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Warn(ctx context.Context, msg string, args ...any) {
|
func (s *slogLogger) Warn(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
if !s.V(InfoLevel) {
|
if !s.V(InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
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(), slog.LevelWarn, msg, pcs[0])
|
r := slog.NewRecord(time.Now(), slog.LevelWarn, msg, pcs[0])
|
||||||
r.Add(args...)
|
for _, fn := range s.opts.ContextAttrFuncs {
|
||||||
|
attrs = append(attrs, fn(ctx))
|
||||||
|
}
|
||||||
|
r.Add(attrs...)
|
||||||
_ = s.slog.Handler().Handle(ctx, r)
|
_ = s.slog.Handler().Handle(ctx, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v4/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
|
"go.unistack.org/micro/v4/util/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Tracer = (*noopTracer)(nil)
|
var _ Tracer = (*noopTracer)(nil)
|
||||||
@ -26,6 +27,8 @@ func (t *noopTracer) Start(ctx context.Context, name string, opts ...options.Opt
|
|||||||
labels: options.Labels,
|
labels: options.Labels,
|
||||||
kind: options.Kind,
|
kind: options.Kind,
|
||||||
}
|
}
|
||||||
|
span.spanID, _ = id.New()
|
||||||
|
span.traceID, _ = id.New()
|
||||||
if span.ctx == nil {
|
if span.ctx == nil {
|
||||||
span.ctx = context.Background()
|
span.ctx = context.Background()
|
||||||
}
|
}
|
||||||
@ -63,6 +66,8 @@ type noopSpan struct {
|
|||||||
logs []interface{}
|
logs []interface{}
|
||||||
kind SpanKind
|
kind SpanKind
|
||||||
status SpanStatus
|
status SpanStatus
|
||||||
|
traceID string
|
||||||
|
spanID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *noopSpan) Finish(opts ...options.Option) {
|
func (s *noopSpan) Finish(opts ...options.Option) {
|
||||||
@ -97,6 +102,14 @@ func (s *noopSpan) Kind() SpanKind {
|
|||||||
return s.kind
|
return s.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *noopSpan) TraceID() string {
|
||||||
|
return s.traceID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *noopSpan) SpanID() string {
|
||||||
|
return s.spanID
|
||||||
|
}
|
||||||
|
|
||||||
func (s *noopSpan) Status() (SpanStatus, string) {
|
func (s *noopSpan) Status() (SpanStatus, string) {
|
||||||
return s.status, s.statusMsg
|
return s.status, s.statusMsg
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v4/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,6 +46,20 @@ type Span interface {
|
|||||||
AddLogs(kv ...interface{})
|
AddLogs(kv ...interface{})
|
||||||
// Kind returns span kind
|
// Kind returns span kind
|
||||||
Kind() SpanKind
|
Kind() SpanKind
|
||||||
|
// TraceID returns trace id
|
||||||
|
TraceID() string
|
||||||
|
// SpanID returns span id
|
||||||
|
SpanID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
logger.DefaultContextAttrFuncs = append(logger.DefaultContextAttrFuncs, func(ctx context.Context) []interface{} {
|
||||||
|
span, ok := SpanFromContext(ctx)
|
||||||
|
if !ok || span == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []interface{}{"trace", span.TraceID(), "span", span.SpanID()}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort labels alphabeticaly by label name
|
// sort labels alphabeticaly by label name
|
||||||
|
Loading…
Reference in New Issue
Block a user