backport from v3

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 939285cefb
5 changed files with 56 additions and 45 deletions

View File

@ -39,8 +39,10 @@ type Options struct {
SourceKey string
// StacktraceKey is the key used for the stacktrace
StacktraceKey string
// Stacktrace controls writing of stacktaces on error
Stacktrace bool
// AddStacktrace controls writing of stacktaces on error
AddStacktrace bool
// AddSource enabled writing source file and position in log
AddSource bool
}
// NewOptions creates new options struct
@ -52,6 +54,7 @@ func NewOptions(opts ...options.Option) Options {
CallerSkipCount: DefaultCallerSkipCount,
Context: context.Background(),
ContextAttrFuncs: DefaultContextAttrFuncs,
AddSource: true,
}
_ = WithMicroKeys()(&options)
@ -207,9 +210,16 @@ func WithMicroKeys() options.Option {
}
}
// WithStacktrace controls writing stacktrace on error
func WithStacktrace(v bool) options.Option {
// WithAddStacktrace controls writing stacktrace on error
func WithAddStacktrace(v bool) options.Option {
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,
}
/*
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
l.slog = slog
return nil
}
*/
l.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{
ReplaceAttr: s.renameAttr,
ReplaceAttr: l.renameAttr,
Level: l.leveler,
AddSource: true,
AddSource: l.opts.AddSource,
}
l.leveler.Set(loggerToSlogLevel(l.opts.Level))
handler := slog.NewJSONHandler(options.Out, handleOpt)
@ -116,50 +109,47 @@ 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())
l := &slogLogger{opts: s.opts}
l.leveler = new(slog.LevelVar)
l.leveler.Set(s.leveler.Level())
handleOpt := &slog.HandlerOptions{
ReplaceAttr: nl.renameAttr,
Level: nl.leveler,
AddSource: true,
ReplaceAttr: l.renameAttr,
Level: l.leveler,
AddSource: l.opts.AddSource,
}
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
nl.slog = slog.New(handler).With(attrs...)
l.slog = slog.New(handler).With(attrs...)
s.mu.RUnlock()
return nl
return l
}
func (s *slogLogger) Init(opts ...options.Option) error {
s.mu.Lock()
if len(s.opts.ContextAttrFuncs) == 0 {
s.opts.ContextAttrFuncs = logger.DefaultContextAttrFuncs
}
for _, o := range opts {
if err := o(&s.opts); err != nil {
return err
}
}
/*
if slog, ok := s.opts.Context.Value(loggerKey{}).(*slog.Logger); ok {
s.slog = slog
return nil
}
*/
s.leveler = new(slog.LevelVar)
handleOpt := &slog.HandlerOptions{
ReplaceAttr: s.renameAttr,
Level: s.leveler,
AddSource: true,
AddSource: s.opts.AddSource,
}
s.leveler.Set(loggerToSlogLevel(s.opts.Level))
handler := slog.NewJSONHandler(s.opts.Out, handleOpt)
s.slog = slog.New(handler).With(s.opts.Attrs...)
s.mu.Unlock()
return nil
}
@ -180,7 +170,7 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, msg string, attr
break
}
}
if s.opts.Stacktrace && lvl == logger.ErrorLevel {
if s.opts.AddStacktrace && lvl == logger.ErrorLevel {
stackInfo := make([]byte, 1024*1024)
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
@ -260,7 +250,7 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}
break
}
}
if s.opts.Stacktrace {
if s.opts.AddStacktrace {
stackInfo := make([]byte, 1024*1024)
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)

View File

@ -13,7 +13,7 @@ import (
func TestError(t *testing.T) {
ctx := context.TODO()
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 {
t.Fatal(err)
}

View File

@ -27,12 +27,12 @@ func TestLoggerWithTracer(t *testing.T) {
logger.Error(ctx, "my test error", fmt.Errorf("error"))
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")
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
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
type Tracer interface {
// Name return tracer name
@ -52,16 +72,6 @@ type Span interface {
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
type byKey []interface{}
@ -76,6 +86,7 @@ func UniqLabels(labels []interface{}) []interface{} {
if len(labels)%2 == 1 {
labels = labels[:len(labels)-1]
}
if len(labels) > 2 {
sort.Sort(byKey(labels))