Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
1cbc353479
commit
f28f8e13b3
@ -48,8 +48,10 @@ type Logger interface {
|
||||
Fatal(ctx context.Context, msg string, attrs ...interface{})
|
||||
// Log logs message with needed level
|
||||
Log(ctx context.Context, level Level, msg string, attrs ...interface{})
|
||||
// String returns the name of logger
|
||||
// String returns the type name of logger
|
||||
String() string
|
||||
// String returns the name of logger
|
||||
Name() string
|
||||
}
|
||||
|
||||
// Info writes formatted msg to default logger on info level
|
||||
|
@ -35,6 +35,10 @@ type Options struct {
|
||||
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
|
||||
}
|
||||
|
||||
// NewOptions creates new options struct
|
||||
@ -116,6 +120,9 @@ func WithZapKeys() options.Option {
|
||||
if err = options.Set(src, "caller", ".SourceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -135,6 +142,9 @@ func WithZerologKeys() options.Option {
|
||||
if err = options.Set(src, "caller", ".SourceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -154,6 +164,9 @@ func WithSlogKeys() options.Option {
|
||||
if err = options.Set(src, slog.SourceKey, ".SourceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -173,6 +186,16 @@ func WithMicroKeys() options.Option {
|
||||
if err = options.Set(src, "caller", ".SourceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithStacktrace controls writing stacktrace on error
|
||||
func WithStacktrace(v bool) options.Option {
|
||||
return func(src interface{}) error {
|
||||
return options.Set(src, v, ".Stacktrace")
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,10 @@ import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.unistack.org/micro/v4/logger"
|
||||
@ -13,6 +15,8 @@ import (
|
||||
"go.unistack.org/micro/v4/tracer"
|
||||
)
|
||||
|
||||
var reTrace = regexp.MustCompile(`.*/slog/logger\.go.*\n`)
|
||||
|
||||
var (
|
||||
traceValue = slog.StringValue("trace")
|
||||
debugValue = slog.StringValue("debug")
|
||||
@ -61,13 +65,15 @@ type slogLogger struct {
|
||||
slog *slog.Logger
|
||||
leveler *slog.LevelVar
|
||||
opts logger.Options
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *slogLogger) Clone(opts ...options.Option) logger.Logger {
|
||||
s.mu.RLock()
|
||||
options := s.opts
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
_ = o(&options)
|
||||
}
|
||||
|
||||
l := &slogLogger{
|
||||
@ -91,6 +97,8 @@ func (s *slogLogger) Clone(opts ...options.Option) logger.Logger {
|
||||
handler := slog.NewJSONHandler(options.Out, handleOpt)
|
||||
l.slog = slog.New(handler).With(options.Attrs...)
|
||||
|
||||
s.mu.RUnlock()
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
@ -107,6 +115,7 @@ func (s *slogLogger) Options() logger.Options {
|
||||
}
|
||||
|
||||
func (s *slogLogger) Attrs(attrs ...interface{}) logger.Logger {
|
||||
s.mu.RLock()
|
||||
nl := &slogLogger{opts: s.opts}
|
||||
nl.leveler = new(slog.LevelVar)
|
||||
nl.leveler.Set(s.leveler.Level())
|
||||
@ -120,6 +129,8 @@ func (s *slogLogger) Attrs(attrs ...interface{}) logger.Logger {
|
||||
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
|
||||
nl.slog = slog.New(handler).With(attrs...)
|
||||
|
||||
s.mu.RUnlock()
|
||||
|
||||
return nl
|
||||
}
|
||||
|
||||
@ -219,6 +230,15 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}
|
||||
for _, fn := range s.opts.ContextAttrFuncs {
|
||||
attrs = append(attrs, fn(ctx)...)
|
||||
}
|
||||
if s.opts.Stacktrace {
|
||||
stackInfo := make([]byte, 1024*1024)
|
||||
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
|
||||
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
|
||||
if len(traceLines) != 0 {
|
||||
attrs = append(attrs, slog.String("stacktrace", traceLines[len(traceLines)-1]))
|
||||
}
|
||||
}
|
||||
}
|
||||
r.Add(attrs...)
|
||||
r.Attrs(func(a slog.Attr) bool {
|
||||
if a.Key == "error" {
|
||||
|
@ -9,6 +9,19 @@ import (
|
||||
"go.unistack.org/micro/v4/logger"
|
||||
)
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
buf := bytes.NewBuffer(nil)
|
||||
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf), logger.WithStacktrace(true))
|
||||
if err := l.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
l.Error(ctx, "message")
|
||||
if !bytes.Contains(buf.Bytes(), []byte(`"stacktrace":"`)) {
|
||||
t.Fatalf("logger stacktrace not works, buf contains: %s", buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
Loading…
Reference in New Issue
Block a user