@@ -6,42 +6,57 @@ import (
6
6
"go.opentelemetry.io/otel"
7
7
"go.opentelemetry.io/otel/attribute"
8
8
"go.opentelemetry.io/otel/codes"
9
+ semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
9
10
"go.opentelemetry.io/otel/trace"
10
11
11
12
"github.com/go-redis/redis/extra/rediscmd/v8"
12
13
"github.com/go-redis/redis/v8"
13
14
)
14
15
15
- var tracer = otel .Tracer ("github.com/go-redis/redis" )
16
+ const (
17
+ // todo: consider using the full module path "github.com/go-redis/redis/extra/redisotel"
18
+ defaultTracerName = "github.com/go-redis/redis"
19
+ )
16
20
17
- type TracingHook struct {}
21
+ type TracingHook struct {
22
+ tracer trace.Tracer
23
+ }
18
24
19
- var _ redis.Hook = (* TracingHook )(nil )
25
+ func NewTracingHook (opts ... Option ) * TracingHook {
26
+ cfg := & config {
27
+ tp : otel .GetTracerProvider (),
28
+ }
29
+ for _ , opt := range opts {
30
+ opt .apply (cfg )
31
+ }
20
32
21
- func NewTracingHook () * TracingHook {
22
- return new (TracingHook )
33
+ tracer := cfg .tp .Tracer (
34
+ defaultTracerName ,
35
+ // todo: consider adding a version
36
+ // trace.WithInstrumentationVersion("semver:8.11.4"),
37
+ )
38
+ return & TracingHook {tracer : tracer }
23
39
}
24
40
25
- func (TracingHook ) BeforeProcess (ctx context.Context , cmd redis.Cmder ) (context.Context , error ) {
41
+ func (th * TracingHook ) BeforeProcess (ctx context.Context , cmd redis.Cmder ) (context.Context , error ) {
26
42
if ! trace .SpanFromContext (ctx ).IsRecording () {
27
43
return ctx , nil
28
44
}
29
45
30
- attrs := []attribute.KeyValue {
31
- attribute .String ("db.system" , "redis" ),
32
- attribute .String ("db.statement" , rediscmd .CmdString (cmd )),
33
- }
34
46
opts := []trace.SpanStartOption {
35
47
trace .WithSpanKind (trace .SpanKindClient ),
36
- trace .WithAttributes (attrs ... ),
48
+ trace .WithAttributes (
49
+ semconv .DBSystemRedis ,
50
+ semconv .DBStatementKey .String (rediscmd .CmdString (cmd )),
51
+ ),
37
52
}
38
53
39
- ctx , _ = tracer .Start (ctx , cmd .FullName (), opts ... )
54
+ ctx , _ = th . tracer .Start (ctx , cmd .FullName (), opts ... )
40
55
41
56
return ctx , nil
42
57
}
43
58
44
- func (TracingHook ) AfterProcess (ctx context.Context , cmd redis.Cmder ) error {
59
+ func (th * TracingHook ) AfterProcess (ctx context.Context , cmd redis.Cmder ) error {
45
60
span := trace .SpanFromContext (ctx )
46
61
if err := cmd .Err (); err != nil {
47
62
recordError (ctx , span , err )
@@ -50,29 +65,28 @@ func (TracingHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
50
65
return nil
51
66
}
52
67
53
- func (TracingHook ) BeforeProcessPipeline (ctx context.Context , cmds []redis.Cmder ) (context.Context , error ) {
68
+ func (th * TracingHook ) BeforeProcessPipeline (ctx context.Context , cmds []redis.Cmder ) (context.Context , error ) {
54
69
if ! trace .SpanFromContext (ctx ).IsRecording () {
55
70
return ctx , nil
56
71
}
57
72
58
73
summary , cmdsString := rediscmd .CmdsString (cmds )
59
74
60
- attrs := []attribute.KeyValue {
61
- attribute .String ("db.system" , "redis" ),
62
- attribute .Int ("db.redis.num_cmd" , len (cmds )),
63
- attribute .String ("db.statement" , cmdsString ),
64
- }
65
75
opts := []trace.SpanStartOption {
66
76
trace .WithSpanKind (trace .SpanKindClient ),
67
- trace .WithAttributes (attrs ... ),
77
+ trace .WithAttributes (
78
+ semconv .DBSystemRedis ,
79
+ semconv .DBStatementKey .String (cmdsString ),
80
+ attribute .Int ("db.redis.num_cmd" , len (cmds )),
81
+ ),
68
82
}
69
83
70
- ctx , _ = tracer .Start (ctx , "pipeline " + summary , opts ... )
84
+ ctx , _ = th . tracer .Start (ctx , "pipeline " + summary , opts ... )
71
85
72
86
return ctx , nil
73
87
}
74
88
75
- func (TracingHook ) AfterProcessPipeline (ctx context.Context , cmds []redis.Cmder ) error {
89
+ func (th * TracingHook ) AfterProcessPipeline (ctx context.Context , cmds []redis.Cmder ) error {
76
90
span := trace .SpanFromContext (ctx )
77
91
if err := cmds [0 ].Err (); err != nil {
78
92
recordError (ctx , span , err )
@@ -87,3 +101,28 @@ func recordError(ctx context.Context, span trace.Span, err error) {
87
101
span .SetStatus (codes .Error , err .Error ())
88
102
}
89
103
}
104
+
105
+ type config struct {
106
+ tp trace.TracerProvider
107
+ }
108
+
109
+ // Option specifies instrumentation configuration options.
110
+ type Option interface {
111
+ apply (* config )
112
+ }
113
+
114
+ type optionFunc func (* config )
115
+
116
+ func (o optionFunc ) apply (c * config ) {
117
+ o (c )
118
+ }
119
+
120
+ // WithTracerProvider specifies a tracer provider to use for creating a tracer.
121
+ // If none is specified, the global provider is used.
122
+ func WithTracerProvider (provider trace.TracerProvider ) Option {
123
+ return optionFunc (func (cfg * config ) {
124
+ if provider != nil {
125
+ cfg .tp = provider
126
+ }
127
+ })
128
+ }
0 commit comments