@@ -9,19 +9,27 @@ import (
|
||||
var _ Tracer = (*noopTracer)(nil)
|
||||
|
||||
type noopTracer struct {
|
||||
opts Options
|
||||
opts Options
|
||||
spans []Span
|
||||
}
|
||||
|
||||
func (t *noopTracer) Spans() []Span {
|
||||
return t.spans
|
||||
}
|
||||
|
||||
func (t *noopTracer) Start(ctx context.Context, name string, opts ...options.Option) (context.Context, Span) {
|
||||
options := NewSpanOptions(opts...)
|
||||
span := &noopSpan{
|
||||
name: name,
|
||||
ctx: ctx,
|
||||
tracer: t,
|
||||
opts: NewSpanOptions(opts...),
|
||||
labels: options.Labels,
|
||||
kind: options.Kind,
|
||||
}
|
||||
if span.ctx == nil {
|
||||
span.ctx = context.Background()
|
||||
}
|
||||
t.spans = append(t.spans, span)
|
||||
return NewSpanContext(ctx, span), span
|
||||
}
|
||||
|
||||
@@ -40,13 +48,21 @@ func (t *noopTracer) Name() string {
|
||||
return t.opts.Name
|
||||
}
|
||||
|
||||
type noopEvent struct {
|
||||
name string
|
||||
labels []interface{}
|
||||
}
|
||||
|
||||
type noopSpan struct {
|
||||
ctx context.Context
|
||||
tracer Tracer
|
||||
name string
|
||||
opts SpanOptions
|
||||
status SpanStatus
|
||||
statusMsg string
|
||||
events []*noopEvent
|
||||
labels []interface{}
|
||||
logs []interface{}
|
||||
kind SpanKind
|
||||
status SpanStatus
|
||||
}
|
||||
|
||||
func (s *noopSpan) Finish(opts ...options.Option) {
|
||||
@@ -61,22 +77,24 @@ func (s *noopSpan) Tracer() 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) SetName(name string) {
|
||||
s.name = name
|
||||
}
|
||||
|
||||
func (s *noopSpan) SetLabels(labels ...interface{}) {
|
||||
s.opts.Labels = labels
|
||||
func (s *noopSpan) AddLogs(kv ...interface{}) {
|
||||
s.logs = append(s.logs, kv...)
|
||||
}
|
||||
|
||||
func (s *noopSpan) AddLabels(labels ...interface{}) {
|
||||
s.opts.Labels = append(s.opts.Labels, labels...)
|
||||
func (s *noopSpan) AddLabels(kv ...interface{}) {
|
||||
s.labels = append(s.labels, kv...)
|
||||
}
|
||||
|
||||
func (s *noopSpan) Kind() SpanKind {
|
||||
return s.opts.Kind
|
||||
return s.kind
|
||||
}
|
||||
|
||||
func (s *noopSpan) Status() (SpanStatus, string) {
|
||||
|
@@ -159,6 +159,15 @@ func NewSpanOptions(opts ...options.Option) SpanOptions {
|
||||
return options
|
||||
}
|
||||
|
||||
// NewEventOptions returns default EventOptions
|
||||
func NewEventOptions(opts ...options.Option) EventOptions {
|
||||
options := EventOptions{}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// NewOptions returns default options
|
||||
func NewOptions(opts ...options.Option) Options {
|
||||
options := Options{
|
||||
|
@@ -3,6 +3,8 @@ package tracer // import "go.unistack.org/micro/v4/tracer"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"go.unistack.org/micro/v4/options"
|
||||
)
|
||||
@@ -27,8 +29,6 @@ type Span interface {
|
||||
Tracer() Tracer
|
||||
// Finish complete and send span
|
||||
Finish(opts ...options.Option)
|
||||
// AddEvent add event to span
|
||||
AddEvent(name string, opts ...options.Option)
|
||||
// Context return context with span
|
||||
Context() context.Context
|
||||
// SetName set the span name
|
||||
@@ -37,10 +37,45 @@ type Span interface {
|
||||
SetStatus(status SpanStatus, msg string)
|
||||
// Status returns span status and msg
|
||||
Status() (SpanStatus, string)
|
||||
// SetLabels set the span labels
|
||||
SetLabels(labels ...interface{})
|
||||
// AddLabels append the span labels
|
||||
AddLabels(labels ...interface{})
|
||||
// AddLabels append labels to span
|
||||
AddLabels(kv ...interface{})
|
||||
// AddEvent append event to span
|
||||
AddEvent(name string, opts ...options.Option)
|
||||
// AddLogs append logs to span
|
||||
AddLogs(kv ...interface{})
|
||||
// Kind returns span kind
|
||||
Kind() SpanKind
|
||||
}
|
||||
|
||||
// sort labels alphabeticaly by label name
|
||||
type byKey []interface{}
|
||||
|
||||
func (k byKey) Len() int { return len(k) / 2 }
|
||||
func (k byKey) Less(i, j int) bool { return fmt.Sprintf("%s", k[i*2]) < fmt.Sprintf("%s", k[j*2]) }
|
||||
func (k byKey) Swap(i, j int) {
|
||||
k[i*2], k[j*2] = k[j*2], k[i*2]
|
||||
k[i*2+1], k[j*2+1] = k[j*2+1], k[i*2+1]
|
||||
}
|
||||
|
||||
func UniqLabels(labels []interface{}) []interface{} {
|
||||
if len(labels)%2 == 1 {
|
||||
labels = labels[:len(labels)-1]
|
||||
}
|
||||
if len(labels) > 2 {
|
||||
sort.Sort(byKey(labels))
|
||||
|
||||
idx := 0
|
||||
for {
|
||||
if labels[idx] == labels[idx+2] {
|
||||
copy(labels[idx:], labels[idx+2:])
|
||||
labels = labels[:len(labels)-2]
|
||||
} else {
|
||||
idx += 2
|
||||
}
|
||||
if idx+2 >= len(labels) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ package wrapper // import "go.unistack.org/micro/v4/tracer/wrapper"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go.unistack.org/micro/v4/client"
|
||||
"go.unistack.org/micro/v4/metadata"
|
||||
@@ -14,11 +15,11 @@ import (
|
||||
|
||||
var DefaultHeadersExctract = []string{metadata.HeaderTopic, metadata.HeaderEndpoint, metadata.HeaderService, metadata.HeaderXRequestID}
|
||||
|
||||
func extractLabels(md metadata.Metadata) []string {
|
||||
labels := make([]string, 0, 5)
|
||||
func ExtractDefaultLabels(md metadata.Metadata) []interface{} {
|
||||
labels := make([]interface{}, 0, len(DefaultHeadersExctract))
|
||||
for _, k := range DefaultHeadersExctract {
|
||||
if v, ok := md.Get(k); ok {
|
||||
labels = append(labels, k, v)
|
||||
labels = append(labels, strings.ToLower(k), v)
|
||||
}
|
||||
}
|
||||
return labels
|
||||
@@ -29,7 +30,7 @@ var (
|
||||
sp.SetName(fmt.Sprintf("Call %s.%s", req.Service(), req.Method()))
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
labels = append(labels, extractLabels(md))
|
||||
labels = append(labels, ExtractDefaultLabels(md)...)
|
||||
}
|
||||
if err != nil {
|
||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||
@@ -38,10 +39,9 @@ var (
|
||||
}
|
||||
|
||||
DefaultClientStreamObserver = func(ctx context.Context, req client.Request, opts []options.Option, stream client.Stream, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("Stream %s.%s", req.Service(), req.Method()))
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
labels = append(labels, extractLabels(md))
|
||||
labels = append(labels, ExtractDefaultLabels(md)...)
|
||||
}
|
||||
if err != nil {
|
||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||
@@ -50,10 +50,9 @@ var (
|
||||
}
|
||||
|
||||
DefaultServerHandlerObserver = func(ctx context.Context, req server.Request, rsp interface{}, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("Handler %s.%s", req.Service(), req.Method()))
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromIncomingContext(ctx); ok {
|
||||
labels = append(labels, extractLabels(md))
|
||||
labels = append(labels, ExtractDefaultLabels(md)...)
|
||||
}
|
||||
if err != nil {
|
||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||
@@ -62,10 +61,10 @@ var (
|
||||
}
|
||||
|
||||
DefaultClientCallFuncObserver = func(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions, sp tracer.Span, err error) {
|
||||
sp.SetName(fmt.Sprintf("Call %s.%s", req.Service(), req.Method()))
|
||||
sp.SetName(fmt.Sprintf("%s.%s call", req.Service(), req.Method()))
|
||||
var labels []interface{}
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
labels = append(labels, extractLabels(md))
|
||||
labels = append(labels, ExtractDefaultLabels(md)...)
|
||||
}
|
||||
if err != nil {
|
||||
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
||||
@@ -177,23 +176,22 @@ func (ot *tWrapper) Call(ctx context.Context, req client.Request, rsp interface{
|
||||
}
|
||||
}
|
||||
|
||||
sp, ok := tracer.SpanFromContext(ctx)
|
||||
if !ok {
|
||||
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-client",
|
||||
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||
tracer.WithSpanLabels(
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", "unary",
|
||||
),
|
||||
)
|
||||
}
|
||||
nctx, sp := ot.opts.Tracer.Start(ctx, fmt.Sprintf("%s.%s rpc-client", req.Service(), req.Method()),
|
||||
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||
options.Labels(
|
||||
"rpc.service", req.Service(),
|
||||
"rpc.method", req.Method(),
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", "unary",
|
||||
),
|
||||
)
|
||||
defer sp.Finish()
|
||||
|
||||
err := ot.Client.Call(ctx, req, rsp, opts...)
|
||||
err := ot.Client.Call(nctx, req, rsp, opts...)
|
||||
|
||||
for _, o := range ot.opts.ClientCallObservers {
|
||||
o(ctx, req, rsp, opts, sp, err)
|
||||
o(nctx, req, rsp, opts, sp, err)
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -207,23 +205,22 @@ func (ot *tWrapper) Stream(ctx context.Context, req client.Request, opts ...opti
|
||||
}
|
||||
}
|
||||
|
||||
sp, ok := tracer.SpanFromContext(ctx)
|
||||
if !ok {
|
||||
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-client",
|
||||
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||
tracer.WithSpanLabels(
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", "stream",
|
||||
),
|
||||
)
|
||||
}
|
||||
nctx, sp := ot.opts.Tracer.Start(ctx, fmt.Sprintf("%s.%s rpc-client", req.Service(), req.Method()),
|
||||
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||
options.Labels(
|
||||
"rpc.service", req.Service(),
|
||||
"rpc.method", req.Method(),
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", "stream",
|
||||
),
|
||||
)
|
||||
defer sp.Finish()
|
||||
|
||||
stream, err := ot.Client.Stream(ctx, req, opts...)
|
||||
stream, err := ot.Client.Stream(nctx, req, opts...)
|
||||
|
||||
for _, o := range ot.opts.ClientStreamObservers {
|
||||
o(ctx, req, opts, stream, sp, err)
|
||||
o(nctx, req, opts, stream, sp, err)
|
||||
}
|
||||
|
||||
return stream, err
|
||||
@@ -242,24 +239,22 @@ func (ot *tWrapper) ServerHandler(ctx context.Context, req server.Request, rsp i
|
||||
callType = "stream"
|
||||
}
|
||||
|
||||
sp, ok := tracer.SpanFromContext(ctx)
|
||||
if !ok {
|
||||
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-server",
|
||||
tracer.WithSpanKind(tracer.SpanKindServer),
|
||||
tracer.WithSpanLabels(
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", callType,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
nctx, sp := ot.opts.Tracer.Start(ctx, fmt.Sprintf("%s.%s rpc-server", req.Service(), req.Method()),
|
||||
tracer.WithSpanKind(tracer.SpanKindServer),
|
||||
options.Labels(
|
||||
"rpc.service", req.Service(),
|
||||
"rpc.method", req.Method(),
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", callType,
|
||||
),
|
||||
)
|
||||
defer sp.Finish()
|
||||
|
||||
err := ot.serverHandler(ctx, req, rsp)
|
||||
err := ot.serverHandler(nctx, req, rsp)
|
||||
|
||||
for _, o := range ot.opts.ServerHandlerObservers {
|
||||
o(ctx, req, rsp, sp, err)
|
||||
o(nctx, req, rsp, sp, err)
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -297,23 +292,23 @@ func (ot *tWrapper) ClientCallFunc(ctx context.Context, addr string, req client.
|
||||
}
|
||||
}
|
||||
|
||||
sp, ok := tracer.SpanFromContext(ctx)
|
||||
if !ok {
|
||||
ctx, sp = ot.opts.Tracer.Start(ctx, "rpc-client",
|
||||
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||
tracer.WithSpanLabels(
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", "unary",
|
||||
),
|
||||
)
|
||||
}
|
||||
nctx, sp := ot.opts.Tracer.Start(ctx, fmt.Sprintf("%s.%s rpc-client", req.Service(), req.Method()),
|
||||
tracer.WithSpanKind(tracer.SpanKindClient),
|
||||
options.Labels(
|
||||
"rpc.service", req.Service(),
|
||||
"rpc.method", req.Method(),
|
||||
"rpc.flavor", "rpc",
|
||||
"rpc.call", "/"+req.Service()+"/"+req.Endpoint(),
|
||||
"rpc.call_type", "unary",
|
||||
),
|
||||
)
|
||||
|
||||
defer sp.Finish()
|
||||
|
||||
err := ot.clientCallFunc(ctx, addr, req, rsp, opts)
|
||||
err := ot.clientCallFunc(nctx, addr, req, rsp, opts)
|
||||
|
||||
for _, o := range ot.opts.ClientCallFuncObservers {
|
||||
o(ctx, addr, req, rsp, opts, sp, err)
|
||||
o(nctx, addr, req, rsp, opts, sp, err)
|
||||
}
|
||||
|
||||
return err
|
||||
|
Reference in New Issue
Block a user