backport from v3
Some checks failed
/ autoupdate (push) Failing after 1m3s

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2024-03-06 01:17:19 +03:00
parent 1cbab38d24
commit 7ef5c5d804
5 changed files with 56 additions and 45 deletions

View File

@ -39,8 +39,10 @@ type Options struct {
SourceKey string SourceKey string
// StacktraceKey is the key used for the stacktrace // StacktraceKey is the key used for the stacktrace
StacktraceKey string StacktraceKey string
// Stacktrace controls writing of stacktaces on error // AddStacktrace controls writing of stacktaces on error
Stacktrace bool AddStacktrace bool
// AddSource enabled writing source file and position in log
AddSource bool
} }
// NewOptions creates new options struct // NewOptions creates new options struct
@ -52,6 +54,7 @@ func NewOptions(opts ...options.Option) Options {
CallerSkipCount: DefaultCallerSkipCount, CallerSkipCount: DefaultCallerSkipCount,
Context: context.Background(), Context: context.Background(),
ContextAttrFuncs: DefaultContextAttrFuncs, ContextAttrFuncs: DefaultContextAttrFuncs,
AddSource: true,
} }
_ = WithMicroKeys()(&options) _ = WithMicroKeys()(&options)
@ -207,9 +210,16 @@ func WithMicroKeys() options.Option {
} }
} }
// WithStacktrace controls writing stacktrace on error // WithAddStacktrace controls writing stacktrace on error
func WithStacktrace(v bool) options.Option { func WithAddStacktrace(v bool) options.Option {
return func(src interface{}) error { return func(src interface{}) error {
return options.Set(src, v, ".Stacktrace") return options.Set(src, v, ".AddStacktrace")
}
}
// WitAddSource controls writing source file and pos in log
func WithAddSource(v bool) options.Option {
return func(src interface{}) error {
return options.Set(src, v, ".AddSource")
} }
} }

View File

@ -80,18 +80,11 @@ func (s *slogLogger) Clone(opts ...options.Option) logger.Logger {
opts: options, opts: options,
} }
/*
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
l.slog = slog
return nil
}
*/
l.leveler = new(slog.LevelVar) l.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{ handleOpt := &slog.HandlerOptions{
ReplaceAttr: s.renameAttr, ReplaceAttr: l.renameAttr,
Level: l.leveler, Level: l.leveler,
AddSource: true, AddSource: l.opts.AddSource,
} }
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)
@ -116,50 +109,47 @@ func (s *slogLogger) Options() logger.Options {
func (s *slogLogger) Attrs(attrs ...interface{}) logger.Logger { func (s *slogLogger) Attrs(attrs ...interface{}) logger.Logger {
s.mu.RLock() s.mu.RLock()
nl := &slogLogger{opts: s.opts} l := &slogLogger{opts: s.opts}
nl.leveler = new(slog.LevelVar) l.leveler = new(slog.LevelVar)
nl.leveler.Set(s.leveler.Level()) l.leveler.Set(s.leveler.Level())
handleOpt := &slog.HandlerOptions{ handleOpt := &slog.HandlerOptions{
ReplaceAttr: nl.renameAttr, ReplaceAttr: l.renameAttr,
Level: nl.leveler, Level: l.leveler,
AddSource: true, AddSource: l.opts.AddSource,
} }
handler := slog.NewJSONHandler(s.opts.Out, handleOpt) handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
nl.slog = slog.New(handler).With(attrs...) l.slog = slog.New(handler).With(attrs...)
s.mu.RUnlock() s.mu.RUnlock()
return nl return l
} }
func (s *slogLogger) Init(opts ...options.Option) error { func (s *slogLogger) Init(opts ...options.Option) error {
s.mu.Lock()
if len(s.opts.ContextAttrFuncs) == 0 { if len(s.opts.ContextAttrFuncs) == 0 {
s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs
} }
for _, o := range opts { for _, o := range opts {
if err := o(&s.opts); err != nil { if err := o(&s.opts); err != nil {
return err return err
} }
} }
/*
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
s.slog = slog
return nil
}
*/
s.leveler = new(slog.LevelVar) s.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{ handleOpt := &slog.HandlerOptions{
ReplaceAttr: s.renameAttr, ReplaceAttr: s.renameAttr,
Level: s.leveler, Level: s.leveler,
AddSource: true, AddSource: s.opts.AddSource,
} }
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.Attrs...) s.slog = slog.New(handler).With(s.opts.Attrs...)
s.mu.Unlock()
return nil return nil
} }
@ -180,7 +170,7 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, msg string, attr
break break
} }
} }
if s.opts.Stacktrace && lvl == logger.ErrorLevel { if s.opts.AddStacktrace && lvl == logger.ErrorLevel {
stackInfo := make([]byte, 1024*1024) stackInfo := make([]byte, 1024*1024)
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 { if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1) traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
@ -260,7 +250,7 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}
break break
} }
} }
if s.opts.Stacktrace { if s.opts.AddStacktrace {
stackInfo := make([]byte, 1024*1024) stackInfo := make([]byte, 1024*1024)
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 { if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1) traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)

View File

@ -13,7 +13,7 @@ import (
func TestError(t *testing.T) { func TestError(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf), logger.WithStacktrace(true)) l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf), logger.WithAddStacktrace(true))
if err := l.Init(); err != nil { if err := l.Init(); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -27,12 +27,12 @@ func TestLoggerWithTracer(t *testing.T) {
logger.Error(ctx, "my test error", fmt.Errorf("error")) logger.Error(ctx, "my test error", fmt.Errorf("error"))
if !strings.Contains(buf.String(), span.TraceID()) { if !strings.Contains(buf.String(), span.TraceID()) {
t.Fatalf("log does not contains tracer id: %s", buf.Bytes()) t.Fatalf("log does not contains trace id: %s", buf.Bytes())
} }
_, _ = tr.Start(ctx, "test2") _, _ = tr.Start(ctx, "test2")
for _, s := range tr.Spans() { for _, s := range tr.Spans() {
t.Logf("span %#+v\n", s) _ = s
} }
} }

View File

@ -13,6 +13,26 @@ import (
// DefaultTracer is the global default tracer // DefaultTracer is the global default tracer
var DefaultTracer = NewTracer() var DefaultTracer = NewTracer()
var (
// TraceIDKey is the key used for the trace id in the log call
TraceIDKey = "trace-id"
// SpanIDKey is the key used for the span id in the log call
SpanIDKey = "span-id"
)
func init() {
logger.DefaultContextAttrFuncs = append(logger.DefaultContextAttrFuncs,
func(ctx context.Context) []interface{} {
if span, ok := SpanFromContext(ctx); ok {
return []interface{}{
TraceIDKey, span.TraceID(),
SpanIDKey, span.SpanID(),
}
}
return nil
})
}
// Tracer is an interface for distributed tracing // Tracer is an interface for distributed tracing
type Tracer interface { type Tracer interface {
// Name return tracer name // Name return tracer name
@ -52,16 +72,6 @@ type Span interface {
SpanID() string 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
type byKey []interface{} type byKey []interface{}
@ -76,6 +86,7 @@ func UniqLabels(labels []interface{}) []interface{} {
if len(labels)%2 == 1 { if len(labels)%2 == 1 {
labels = labels[:len(labels)-1] labels = labels[:len(labels)-1]
} }
if len(labels) > 2 { if len(labels) > 2 {
sort.Sort(byKey(labels)) sort.Sort(byKey(labels))