-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
Copy pathotel.go
112 lines (87 loc) · 2.34 KB
/
otel.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package redisext
import (
"context"
"strings"
"github.com/go-redis/redis/v8"
"github.com/go-redis/redis/v8/internal"
"go.opentelemetry.io/otel/api/global"
"go.opentelemetry.io/otel/api/kv"
"go.opentelemetry.io/otel/api/trace"
)
type OpenTelemetryHook struct{}
var _ redis.Hook = OpenTelemetryHook{}
func (OpenTelemetryHook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
if !trace.SpanFromContext(ctx).IsRecording() {
return ctx, nil
}
b := make([]byte, 32)
b = appendCmd(b, cmd)
tracer := global.Tracer("github.com/go-redis/redis")
ctx, span := tracer.Start(ctx, cmd.FullName())
span.SetAttributes(
kv.String("db.system", "redis"),
kv.String("redis.cmd", internal.String(b)),
)
return ctx, nil
}
func (OpenTelemetryHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
trace.SpanFromContext(ctx).End()
return nil
}
func (OpenTelemetryHook) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) {
if !trace.SpanFromContext(ctx).IsRecording() {
return ctx, nil
}
const numCmdLimit = 100
const numNameLimit = 10
seen := make(map[string]struct{}, len(cmds))
unqNames := make([]string, 0, len(cmds))
b := make([]byte, 0, 32*len(cmds))
for i, cmd := range cmds {
if i > numCmdLimit {
break
}
if i > 0 {
b = append(b, '\n')
}
b = appendCmd(b, cmd)
if len(unqNames) >= numNameLimit {
continue
}
name := cmd.FullName()
if _, ok := seen[name]; !ok {
seen[name] = struct{}{}
unqNames = append(unqNames, name)
}
}
tracer := global.Tracer("github.com/go-redis/redis")
ctx, span := tracer.Start(ctx, "pipeline "+strings.Join(unqNames, " "))
span.SetAttributes(
kv.String("db.system", "redis"),
kv.Int("redis.num_cmd", len(cmds)),
kv.String("redis.cmds", internal.String(b)),
)
return ctx, nil
}
func (OpenTelemetryHook) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error {
trace.SpanFromContext(ctx).End()
return nil
}
func appendCmd(b []byte, cmd redis.Cmder) []byte {
const lenLimit = 64
for i, arg := range cmd.Args() {
if i > 0 {
b = append(b, ' ')
}
start := len(b)
b = internal.AppendArg(b, arg)
if len(b)-start > lenLimit {
b = append(b[:start+lenLimit], "..."...)
}
}
if err := cmd.Err(); err != nil {
b = append(b, ": "...)
b = append(b, err.Error()...)
}
return b
}