mirror of
https://github.com/redis/go-redis.git
synced 2025-04-17 20:17:02 +03:00
According to the opentelemetry specification this should always be set to client for database client libraries. I've also removed the SetAttributes call and instead set the attributes during creation of the span. This is what the library SHOULD be doing according to the opentelemetry api specification.
90 lines
2.1 KiB
Go
90 lines
2.1 KiB
Go
package redisotel
|
|
|
|
import (
|
|
"context"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/codes"
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
"github.com/go-redis/redis/extra/rediscmd/v8"
|
|
"github.com/go-redis/redis/v8"
|
|
)
|
|
|
|
var tracer = otel.Tracer("github.com/go-redis/redis")
|
|
|
|
type TracingHook struct{}
|
|
|
|
var _ redis.Hook = (*TracingHook)(nil)
|
|
|
|
func NewTracingHook() *TracingHook {
|
|
return new(TracingHook)
|
|
}
|
|
|
|
func (TracingHook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
|
|
if !trace.SpanFromContext(ctx).IsRecording() {
|
|
return ctx, nil
|
|
}
|
|
|
|
attrs := []attribute.KeyValue{
|
|
attribute.String("db.system", "redis"),
|
|
attribute.String("db.statement", rediscmd.CmdString(cmd)),
|
|
}
|
|
opts := []trace.SpanStartOption{
|
|
trace.WithSpanKind(trace.SpanKindClient),
|
|
trace.WithAttributes(attrs...),
|
|
}
|
|
|
|
ctx, _ = tracer.Start(ctx, cmd.FullName(), opts...)
|
|
|
|
return ctx, nil
|
|
}
|
|
|
|
func (TracingHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
|
|
span := trace.SpanFromContext(ctx)
|
|
if err := cmd.Err(); err != nil {
|
|
recordError(ctx, span, err)
|
|
}
|
|
span.End()
|
|
return nil
|
|
}
|
|
|
|
func (TracingHook) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) {
|
|
if !trace.SpanFromContext(ctx).IsRecording() {
|
|
return ctx, nil
|
|
}
|
|
|
|
summary, cmdsString := rediscmd.CmdsString(cmds)
|
|
|
|
attrs := []attribute.KeyValue{
|
|
attribute.String("db.system", "redis"),
|
|
attribute.Int("db.redis.num_cmd", len(cmds)),
|
|
attribute.String("db.statement", cmdsString),
|
|
}
|
|
opts := []trace.SpanStartOption{
|
|
trace.WithSpanKind(trace.SpanKindClient),
|
|
trace.WithAttributes(attrs...),
|
|
}
|
|
|
|
ctx, _ = tracer.Start(ctx, "pipeline "+summary, opts...)
|
|
|
|
return ctx, nil
|
|
}
|
|
|
|
func (TracingHook) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error {
|
|
span := trace.SpanFromContext(ctx)
|
|
if err := cmds[0].Err(); err != nil {
|
|
recordError(ctx, span, err)
|
|
}
|
|
span.End()
|
|
return nil
|
|
}
|
|
|
|
func recordError(ctx context.Context, span trace.Span, err error) {
|
|
if err != redis.Nil {
|
|
span.RecordError(err)
|
|
span.SetStatus(codes.Error, err.Error())
|
|
}
|
|
}
|