Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
c766477aaa
commit
1cbab38d24
@ -33,6 +33,8 @@ type Options struct {
|
||||
LevelKey string
|
||||
// MessageKey is the key used for the message of the log call
|
||||
MessageKey string
|
||||
// ErrorKey is the key used for the error info
|
||||
ErrorKey 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
|
||||
@ -52,10 +54,10 @@ func NewOptions(opts ...options.Option) Options {
|
||||
ContextAttrFuncs: DefaultContextAttrFuncs,
|
||||
}
|
||||
|
||||
WithMicroKeys()(&options)
|
||||
_ = WithMicroKeys()(&options)
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
_ = o(&options)
|
||||
}
|
||||
return options
|
||||
}
|
||||
@ -123,6 +125,9 @@ func WithZapKeys() options.Option {
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "error", ".ErrorKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -145,6 +150,9 @@ func WithZerologKeys() options.Option {
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "error", ".ErrorKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -167,6 +175,9 @@ func WithSlogKeys() options.Option {
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "error", ".ErrorKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -189,6 +200,9 @@ func WithMicroKeys() options.Option {
|
||||
if err = options.Set(src, "stacktrace", ".StacktraceKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = options.Set(src, "error", ".ErrorKey"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -174,6 +174,12 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, msg string, attr
|
||||
for _, fn := range s.opts.ContextAttrFuncs {
|
||||
attrs = append(attrs, fn(ctx)...)
|
||||
}
|
||||
for _, a := range attrs {
|
||||
if ve, ok := a.(error); ok && ve != nil {
|
||||
attrs = append(attrs, slog.String(s.opts.ErrorKey, ve.Error()))
|
||||
break
|
||||
}
|
||||
}
|
||||
if s.opts.Stacktrace && lvl == logger.ErrorLevel {
|
||||
stackInfo := make([]byte, 1024*1024)
|
||||
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
|
||||
@ -184,6 +190,15 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, msg string, attr
|
||||
}
|
||||
}
|
||||
r.Add(attrs...)
|
||||
r.Attrs(func(a slog.Attr) bool {
|
||||
if a.Key == s.opts.ErrorKey {
|
||||
if span, ok := tracer.SpanFromContext(ctx); ok {
|
||||
span.SetStatus(tracer.SpanStatusError, a.Value.String())
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
_ = s.slog.Handler().Handle(ctx, r)
|
||||
}
|
||||
|
||||
@ -239,6 +254,12 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}
|
||||
for _, fn := range s.opts.ContextAttrFuncs {
|
||||
attrs = append(attrs, fn(ctx)...)
|
||||
}
|
||||
for _, a := range attrs {
|
||||
if ve, ok := a.(error); ok && ve != nil {
|
||||
attrs = append(attrs, slog.String(s.opts.ErrorKey, ve.Error()))
|
||||
break
|
||||
}
|
||||
}
|
||||
if s.opts.Stacktrace {
|
||||
stackInfo := make([]byte, 1024*1024)
|
||||
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
|
||||
@ -250,7 +271,7 @@ func (s *slogLogger) Error(ctx context.Context, msg string, attrs ...interface{}
|
||||
}
|
||||
r.Add(attrs...)
|
||||
r.Attrs(func(a slog.Attr) bool {
|
||||
if a.Key == "error" {
|
||||
if a.Key == s.opts.ErrorKey {
|
||||
if span, ok := tracer.SpanFromContext(ctx); ok {
|
||||
span.SetStatus(tracer.SpanStatusError, a.Value.String())
|
||||
return false
|
||||
|
@ -3,6 +3,7 @@ package slog
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
@ -16,7 +17,7 @@ func TestError(t *testing.T) {
|
||||
if err := l.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
l.Error(ctx, "message")
|
||||
l.Error(ctx, "msg", fmt.Errorf("message"))
|
||||
if !bytes.Contains(buf.Bytes(), []byte(`"stacktrace":"`)) {
|
||||
t.Fatalf("logger stacktrace not works, buf contains: %s", buf.Bytes())
|
||||
}
|
||||
|
143
tracer/memory/memory.go
Normal file
143
tracer/memory/memory.go
Normal file
@ -0,0 +1,143 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.unistack.org/micro/v4/options"
|
||||
"go.unistack.org/micro/v4/tracer"
|
||||
"go.unistack.org/micro/v4/util/id"
|
||||
)
|
||||
|
||||
var _ tracer.Tracer = (*Tracer)(nil)
|
||||
|
||||
type Tracer struct {
|
||||
opts tracer.Options
|
||||
spans []tracer.Span
|
||||
}
|
||||
|
||||
func (t *Tracer) Spans() []tracer.Span {
|
||||
return t.spans
|
||||
}
|
||||
|
||||
func (t *Tracer) Start(ctx context.Context, name string, opts ...options.Option) (context.Context, tracer.Span) {
|
||||
options := tracer.NewSpanOptions(opts...)
|
||||
span := &Span{
|
||||
name: name,
|
||||
ctx: ctx,
|
||||
tracer: t,
|
||||
kind: options.Kind,
|
||||
startTime: time.Now(),
|
||||
}
|
||||
span.spanID.s, _ = id.New()
|
||||
span.traceID.s, _ = id.New()
|
||||
if span.ctx == nil {
|
||||
span.ctx = context.Background()
|
||||
}
|
||||
t.spans = append(t.spans, span)
|
||||
return tracer.NewSpanContext(ctx, span), span
|
||||
}
|
||||
|
||||
func (t *Tracer) Flush(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tracer) Init(opts ...options.Option) error {
|
||||
var err error
|
||||
for _, o := range opts {
|
||||
if err = o(&t.opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tracer) Name() string {
|
||||
return t.opts.Name
|
||||
}
|
||||
|
||||
type noopStringer struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (s noopStringer) String() string {
|
||||
return s.s
|
||||
}
|
||||
|
||||
type Span struct {
|
||||
ctx context.Context
|
||||
tracer tracer.Tracer
|
||||
name string
|
||||
statusMsg string
|
||||
startTime time.Time
|
||||
finishTime time.Time
|
||||
traceID noopStringer
|
||||
spanID noopStringer
|
||||
events []*Event
|
||||
labels []interface{}
|
||||
logs []interface{}
|
||||
kind tracer.SpanKind
|
||||
status tracer.SpanStatus
|
||||
}
|
||||
|
||||
func (s *Span) Finish(opts ...options.Option) {
|
||||
s.finishTime = time.Now()
|
||||
}
|
||||
|
||||
func (s *Span) Context() context.Context {
|
||||
return s.ctx
|
||||
}
|
||||
|
||||
func (s *Span) Tracer() tracer.Tracer {
|
||||
return s.tracer
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
name string
|
||||
labels []interface{}
|
||||
}
|
||||
|
||||
func (s *Span) AddEvent(name string, opts ...options.Option) {
|
||||
options := tracer.NewEventOptions(opts...)
|
||||
s.events = append(s.events, &Event{name: name, labels: options.Labels})
|
||||
}
|
||||
|
||||
func (s *Span) SetName(name string) {
|
||||
s.name = name
|
||||
}
|
||||
|
||||
func (s *Span) AddLogs(kv ...interface{}) {
|
||||
s.logs = append(s.logs, kv...)
|
||||
}
|
||||
|
||||
func (s *Span) AddLabels(kv ...interface{}) {
|
||||
s.labels = append(s.labels, kv...)
|
||||
}
|
||||
|
||||
func (s *Span) Kind() tracer.SpanKind {
|
||||
return s.kind
|
||||
}
|
||||
|
||||
func (s *Span) TraceID() string {
|
||||
return s.traceID.String()
|
||||
}
|
||||
|
||||
func (s *Span) SpanID() string {
|
||||
return s.spanID.String()
|
||||
}
|
||||
|
||||
func (s *Span) Status() (tracer.SpanStatus, string) {
|
||||
return s.status, s.statusMsg
|
||||
}
|
||||
|
||||
func (s *Span) SetStatus(st tracer.SpanStatus, msg string) {
|
||||
s.status = st
|
||||
s.statusMsg = msg
|
||||
}
|
||||
|
||||
// NewTracer returns new memory tracer
|
||||
func NewTracer(opts ...options.Option) *Tracer {
|
||||
return &Tracer{
|
||||
opts: tracer.NewOptions(opts...),
|
||||
}
|
||||
}
|
38
tracer/memory/memory_test.go
Normal file
38
tracer/memory/memory_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.unistack.org/micro/v4/logger"
|
||||
"go.unistack.org/micro/v4/logger/slog"
|
||||
"go.unistack.org/micro/v4/tracer"
|
||||
)
|
||||
|
||||
func TestLoggerWithTracer(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
buf := bytes.NewBuffer(nil)
|
||||
logger.DefaultLogger = slog.NewLogger(logger.WithOutput(buf))
|
||||
|
||||
if err := logger.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var span tracer.Span
|
||||
tr := NewTracer()
|
||||
ctx, span = tr.Start(ctx, "test1")
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
_, _ = tr.Start(ctx, "test2")
|
||||
|
||||
for _, s := range tr.Spans() {
|
||||
t.Logf("span %#+v\n", s)
|
||||
}
|
||||
}
|
@ -24,7 +24,6 @@ func (t *noopTracer) Start(ctx context.Context, name string, opts ...options.Opt
|
||||
name: name,
|
||||
ctx: ctx,
|
||||
tracer: t,
|
||||
labels: options.Labels,
|
||||
kind: options.Kind,
|
||||
}
|
||||
span.spanID.s, _ = id.New()
|
||||
@ -36,7 +35,7 @@ func (t *noopTracer) Start(ctx context.Context, name string, opts ...options.Opt
|
||||
return NewSpanContext(ctx, span), span
|
||||
}
|
||||
|
||||
func (t *noopTracer) Flush(ctx context.Context) error {
|
||||
func (t *noopTracer) Flush(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -51,11 +50,6 @@ func (t *noopTracer) Name() string {
|
||||
return t.opts.Name
|
||||
}
|
||||
|
||||
type noopEvent struct {
|
||||
name string
|
||||
labels []interface{}
|
||||
}
|
||||
|
||||
type noopStringer struct {
|
||||
s string
|
||||
}
|
||||
@ -71,14 +65,11 @@ type noopSpan struct {
|
||||
statusMsg string
|
||||
traceID noopStringer
|
||||
spanID noopStringer
|
||||
events []*noopEvent
|
||||
labels []interface{}
|
||||
logs []interface{}
|
||||
kind SpanKind
|
||||
status SpanStatus
|
||||
}
|
||||
|
||||
func (s *noopSpan) Finish(opts ...options.Option) {
|
||||
func (s *noopSpan) Finish(_ ...options.Option) {
|
||||
}
|
||||
|
||||
func (s *noopSpan) Context() context.Context {
|
||||
@ -89,21 +80,17 @@ func (s *noopSpan) Tracer() Tracer {
|
||||
return s.tracer
|
||||
}
|
||||
|
||||
func (s *noopSpan) AddEvent(name string, opts ...options.Option) {
|
||||
options := NewEventOptions(opts...)
|
||||
s.events = append(s.events, &noopEvent{name: name, labels: options.Labels})
|
||||
func (s *noopSpan) AddEvent(_ string, _ ...options.Option) {
|
||||
}
|
||||
|
||||
func (s *noopSpan) SetName(name string) {
|
||||
s.name = name
|
||||
}
|
||||
|
||||
func (s *noopSpan) AddLogs(kv ...interface{}) {
|
||||
s.logs = append(s.logs, kv...)
|
||||
func (s *noopSpan) AddLogs(_ ...interface{}) {
|
||||
}
|
||||
|
||||
func (s *noopSpan) AddLabels(kv ...interface{}) {
|
||||
s.labels = append(s.labels, kv...)
|
||||
func (s *noopSpan) AddLabels(_ ...interface{}) {
|
||||
}
|
||||
|
||||
func (s *noopSpan) Kind() SpanKind {
|
||||
|
Loading…
Reference in New Issue
Block a user