You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.1 KiB
81 lines
2.1 KiB
package tracing |
|
|
|
import ( |
|
"context" |
|
"fmt" |
|
|
|
"github.com/go-kratos/kratos/v2/errors" |
|
"go.opentelemetry.io/otel" |
|
"go.opentelemetry.io/otel/attribute" |
|
"go.opentelemetry.io/otel/codes" |
|
"go.opentelemetry.io/otel/propagation" |
|
"go.opentelemetry.io/otel/trace" |
|
"google.golang.org/protobuf/proto" |
|
) |
|
|
|
// Tracer is otel span tracer |
|
type Tracer struct { |
|
tracer trace.Tracer |
|
kind trace.SpanKind |
|
opt *options |
|
} |
|
|
|
// NewTracer create tracer instance |
|
func NewTracer(kind trace.SpanKind, opts ...Option) *Tracer { |
|
op := options{ |
|
propagator: propagation.NewCompositeTextMapPropagator(Metadata{}, propagation.Baggage{}, propagation.TraceContext{}), |
|
tracerName: "kratos", |
|
} |
|
for _, o := range opts { |
|
o(&op) |
|
} |
|
if op.tracerProvider != nil { |
|
otel.SetTracerProvider(op.tracerProvider) |
|
} |
|
|
|
switch kind { |
|
case trace.SpanKindClient: |
|
return &Tracer{tracer: otel.Tracer(op.tracerName), kind: kind, opt: &op} |
|
case trace.SpanKindServer: |
|
return &Tracer{tracer: otel.Tracer(op.tracerName), kind: kind, opt: &op} |
|
default: |
|
panic(fmt.Sprintf("unsupported span kind: %v", kind)) |
|
} |
|
} |
|
|
|
// Start start tracing span |
|
func (t *Tracer) Start(ctx context.Context, operation string, carrier propagation.TextMapCarrier) (context.Context, trace.Span) { |
|
if t.kind == trace.SpanKindServer { |
|
ctx = t.opt.propagator.Extract(ctx, carrier) |
|
} |
|
ctx, span := t.tracer.Start(ctx, |
|
operation, |
|
trace.WithSpanKind(t.kind), |
|
) |
|
if t.kind == trace.SpanKindClient { |
|
t.opt.propagator.Inject(ctx, carrier) |
|
} |
|
return ctx, span |
|
} |
|
|
|
// End finish tracing span |
|
func (t *Tracer) End(ctx context.Context, span trace.Span, m interface{}, err error) { |
|
if err != nil { |
|
span.RecordError(err) |
|
if e := errors.FromError(err); e != nil { |
|
span.SetAttributes(attribute.Key("rpc.status_code").Int64(int64(e.Code))) |
|
} |
|
span.SetStatus(codes.Error, err.Error()) |
|
} else { |
|
span.SetStatus(codes.Ok, "OK") |
|
} |
|
|
|
if p, ok := m.(proto.Message); ok { |
|
if t.kind == trace.SpanKindServer { |
|
span.SetAttributes(attribute.Key("send_msg.size").Int(proto.Size(p))) |
|
} else { |
|
span.SetAttributes(attribute.Key("recv_msg.size").Int(proto.Size(p))) |
|
} |
|
} |
|
span.End() |
|
}
|
|
|