@@ -6,42 +6,57 @@ import (
66 "go.opentelemetry.io/otel"
77 "go.opentelemetry.io/otel/attribute"
88 "go.opentelemetry.io/otel/codes"
9+ semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
910 "go.opentelemetry.io/otel/trace"
1011
1112 "github.com/go-redis/redis/extra/rediscmd/v8"
1213 "github.com/go-redis/redis/v8"
1314)
1415
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+ )
1620
17- type TracingHook struct {}
21+ type TracingHook struct {
22+ tracer trace.Tracer
23+ }
1824
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+ }
2032
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 }
2339}
2440
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 ) {
2642 if ! trace .SpanFromContext (ctx ).IsRecording () {
2743 return ctx , nil
2844 }
2945
30- attrs := []attribute.KeyValue {
31- attribute .String ("db.system" , "redis" ),
32- attribute .String ("db.statement" , rediscmd .CmdString (cmd )),
33- }
3446 opts := []trace.SpanStartOption {
3547 trace .WithSpanKind (trace .SpanKindClient ),
36- trace .WithAttributes (attrs ... ),
48+ trace .WithAttributes (
49+ semconv .DBSystemRedis ,
50+ semconv .DBStatementKey .String (rediscmd .CmdString (cmd )),
51+ ),
3752 }
3853
39- ctx , _ = tracer .Start (ctx , cmd .FullName (), opts ... )
54+ ctx , _ = th . tracer .Start (ctx , cmd .FullName (), opts ... )
4055
4156 return ctx , nil
4257}
4358
44- func (TracingHook ) AfterProcess (ctx context.Context , cmd redis.Cmder ) error {
59+ func (th * TracingHook ) AfterProcess (ctx context.Context , cmd redis.Cmder ) error {
4560 span := trace .SpanFromContext (ctx )
4661 if err := cmd .Err (); err != nil {
4762 recordError (ctx , span , err )
@@ -50,29 +65,28 @@ func (TracingHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
5065 return nil
5166}
5267
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 ) {
5469 if ! trace .SpanFromContext (ctx ).IsRecording () {
5570 return ctx , nil
5671 }
5772
5873 summary , cmdsString := rediscmd .CmdsString (cmds )
5974
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- }
6575 opts := []trace.SpanStartOption {
6676 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+ ),
6882 }
6983
70- ctx , _ = tracer .Start (ctx , "pipeline " + summary , opts ... )
84+ ctx , _ = th . tracer .Start (ctx , "pipeline " + summary , opts ... )
7185
7286 return ctx , nil
7387}
7488
75- func (TracingHook ) AfterProcessPipeline (ctx context.Context , cmds []redis.Cmder ) error {
89+ func (th * TracingHook ) AfterProcessPipeline (ctx context.Context , cmds []redis.Cmder ) error {
7690 span := trace .SpanFromContext (ctx )
7791 if err := cmds [0 ].Err (); err != nil {
7892 recordError (ctx , span , err )
@@ -87,3 +101,28 @@ func recordError(ctx context.Context, span trace.Span, err error) {
87101 span .SetStatus (codes .Error , err .Error ())
88102 }
89103}
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