@@ -61,6 +61,32 @@ func WithDBStatement(f StatementFunc) Option {
61
61
// StatementFunc is a the function that maps a command's tokens to a string to put in the db.statement attribute
62
62
type StatementFunc func (cmdTokens []string ) string
63
63
64
+ type commandMetrics struct {
65
+ duration metric.Float64Histogram
66
+ errors metric.Int64Counter
67
+ addOpts []metric.AddOption
68
+ recordOpts []metric.RecordOption
69
+ opAttr bool
70
+ }
71
+
72
+ func (c * commandMetrics ) recordDuration (ctx context.Context , op string , now time.Time ) {
73
+ opts := c .recordOpts
74
+ if c .opAttr {
75
+ opts = append (c .recordOpts , metric .WithAttributeSet (attribute .NewSet (attribute .String ("operation" , op ))))
76
+ }
77
+ c .duration .Record (ctx , time .Since (now ).Seconds (), opts ... )
78
+ }
79
+
80
+ func (c * commandMetrics ) recordError (ctx context.Context , op string , err error ) {
81
+ if err != nil && ! rueidis .IsRedisNil (err ) {
82
+ opts := c .addOpts
83
+ if c .opAttr {
84
+ opts = append (c .addOpts , metric .WithAttributeSet (attribute .NewSet (attribute .String ("operation" , op ))))
85
+ }
86
+ c .errors .Add (ctx , 1 , opts ... )
87
+ }
88
+ }
89
+
64
90
type otelclient struct {
65
91
client rueidis.Client
66
92
meterProvider metric.MeterProvider
@@ -74,50 +100,66 @@ type otelclient struct {
74
100
addOpts []metric.AddOption
75
101
recordOpts []metric.RecordOption
76
102
histogramOption HistogramOption
103
+ commandMetrics
77
104
}
78
105
79
106
func (o * otelclient ) B () rueidis.Builder {
80
107
return o .client .B ()
81
108
}
82
109
83
110
func (o * otelclient ) Do (ctx context.Context , cmd rueidis.Completed ) (resp rueidis.RedisResult ) {
84
- ctx , span := o .start (ctx , first (cmd .Commands ()), sum (cmd .Commands ()))
111
+ op := first (cmd .Commands ())
112
+ defer o .recordDuration (ctx , op , time .Now ())
113
+ ctx , span := o .start (ctx , op , sum (cmd .Commands ()))
85
114
if o .dbStmtFunc != nil {
86
115
span .SetAttributes (dbstmt .String (o .dbStmtFunc (cmd .Commands ())))
87
116
}
88
117
89
118
resp = o .client .Do (ctx , cmd )
90
119
o .end (span , resp .Error ())
120
+ o .recordError (ctx , op , resp .Error ())
91
121
return
92
122
}
93
123
94
124
func (o * otelclient ) DoMulti (ctx context.Context , multi ... rueidis.Completed ) (resp []rueidis.RedisResult ) {
95
- ctx , span := o .start (ctx , multiFirst (multi ), multiSum (multi ))
125
+ op := multiFirst (multi )
126
+ defer o .recordDuration (ctx , op , time .Now ())
127
+ ctx , span := o .start (ctx , op , multiSum (multi ))
96
128
resp = o .client .DoMulti (ctx , multi ... )
97
- o .end (span , firstError (resp ))
129
+ err := firstError (resp )
130
+ o .end (span , err )
131
+ o .recordError (ctx , op , err )
98
132
return
99
133
}
100
134
101
135
func (o * otelclient ) DoStream (ctx context.Context , cmd rueidis.Completed ) (resp rueidis.RedisResultStream ) {
102
- ctx , span := o .start (ctx , first (cmd .Commands ()), sum (cmd .Commands ()))
136
+ op := first (cmd .Commands ())
137
+ defer o .recordDuration (ctx , op , time .Now ())
138
+ ctx , span := o .start (ctx , op , sum (cmd .Commands ()))
103
139
if o .dbStmtFunc != nil {
104
140
span .SetAttributes (dbstmt .String (o .dbStmtFunc (cmd .Commands ())))
105
141
}
106
142
107
143
resp = o .client .DoStream (ctx , cmd )
108
144
o .end (span , resp .Error ())
145
+ o .recordError (ctx , op , resp .Error ())
109
146
return
110
147
}
111
148
112
149
func (o * otelclient ) DoMultiStream (ctx context.Context , multi ... rueidis.Completed ) (resp rueidis.MultiRedisResultStream ) {
113
- ctx , span := o .start (ctx , multiFirst (multi ), multiSum (multi ))
150
+ op := multiFirst (multi )
151
+ defer o .recordDuration (ctx , op , time .Now ())
152
+ ctx , span := o .start (ctx , op , multiSum (multi ))
114
153
resp = o .client .DoMultiStream (ctx , multi ... )
115
154
o .end (span , resp .Error ())
155
+ o .recordError (ctx , op , resp .Error ())
116
156
return
117
157
}
118
158
119
159
func (o * otelclient ) DoCache (ctx context.Context , cmd rueidis.Cacheable , ttl time.Duration ) (resp rueidis.RedisResult ) {
120
- ctx , span := o .start (ctx , first (cmd .Commands ()), sum (cmd .Commands ()))
160
+ op := first (cmd .Commands ())
161
+ defer o .recordDuration (ctx , op , time .Now ())
162
+ ctx , span := o .start (ctx , op , sum (cmd .Commands ()))
121
163
if o .dbStmtFunc != nil {
122
164
span .SetAttributes (dbstmt .String (o .dbStmtFunc (cmd .Commands ())))
123
165
}
@@ -131,11 +173,14 @@ func (o *otelclient) DoCache(ctx context.Context, cmd rueidis.Cacheable, ttl tim
131
173
}
132
174
}
133
175
o .end (span , resp .Error ())
176
+ o .recordError (ctx , op , resp .Error ())
134
177
return
135
178
}
136
179
137
180
func (o * otelclient ) DoMultiCache (ctx context.Context , multi ... rueidis.CacheableTTL ) (resps []rueidis.RedisResult ) {
138
- ctx , span := o .start (ctx , multiCacheableFirst (multi ), multiCacheableSum (multi ))
181
+ op := multiCacheableFirst (multi )
182
+ defer o .recordDuration (ctx , op , time .Now ())
183
+ ctx , span := o .start (ctx , op , multiCacheableSum (multi ))
139
184
resps = o .client .DoMultiCache (ctx , multi ... )
140
185
for _ , resp := range resps {
141
186
if resp .NonRedisError () == nil {
@@ -146,28 +191,32 @@ func (o *otelclient) DoMultiCache(ctx context.Context, multi ...rueidis.Cacheabl
146
191
}
147
192
}
148
193
}
149
- o .end (span , firstError (resps ))
194
+ err := firstError (resps )
195
+ o .end (span , err )
196
+ o .recordError (ctx , op , err )
150
197
return
151
198
}
152
199
153
200
func (o * otelclient ) Dedicated (fn func (rueidis.DedicatedClient ) error ) (err error ) {
154
201
return o .client .Dedicated (func (client rueidis.DedicatedClient ) error {
155
202
return fn (& dedicated {
156
- client : client ,
157
- tAttrs : o .tAttrs ,
158
- tracer : o .tracer ,
159
- dbStmtFunc : o .dbStmtFunc ,
203
+ client : client ,
204
+ tAttrs : o .tAttrs ,
205
+ tracer : o .tracer ,
206
+ dbStmtFunc : o .dbStmtFunc ,
207
+ commandMetrics : o .commandMetrics ,
160
208
})
161
209
})
162
210
}
163
211
164
212
func (o * otelclient ) Dedicate () (rueidis.DedicatedClient , func ()) {
165
213
client , cancel := o .client .Dedicate ()
166
214
return & dedicated {
167
- client : client ,
168
- tAttrs : o .tAttrs ,
169
- tracer : o .tracer ,
170
- dbStmtFunc : o .dbStmtFunc ,
215
+ client : client ,
216
+ tAttrs : o .tAttrs ,
217
+ tracer : o .tracer ,
218
+ dbStmtFunc : o .dbStmtFunc ,
219
+ commandMetrics : o .commandMetrics ,
171
220
}, cancel
172
221
}
173
222
@@ -198,6 +247,7 @@ func (o *otelclient) Nodes() map[string]rueidis.Client {
198
247
tAttrs : o .tAttrs ,
199
248
histogramOption : o .histogramOption ,
200
249
dbStmtFunc : o .dbStmtFunc ,
250
+ commandMetrics : o .commandMetrics ,
201
251
}
202
252
}
203
253
return nodes
@@ -218,27 +268,35 @@ type dedicated struct {
218
268
tracer trace.Tracer
219
269
tAttrs trace.SpanStartEventOption
220
270
dbStmtFunc StatementFunc
271
+ commandMetrics
221
272
}
222
273
223
274
func (d * dedicated ) B () rueidis.Builder {
224
275
return d .client .B ()
225
276
}
226
277
227
278
func (d * dedicated ) Do (ctx context.Context , cmd rueidis.Completed ) (resp rueidis.RedisResult ) {
228
- ctx , span := d .start (ctx , first (cmd .Commands ()), sum (cmd .Commands ()))
279
+ op := first (cmd .Commands ())
280
+ defer d .recordDuration (ctx , op , time .Now ())
281
+ ctx , span := d .start (ctx , op , sum (cmd .Commands ()))
229
282
if d .dbStmtFunc != nil {
230
283
span .SetAttributes (dbstmt .String (d .dbStmtFunc (cmd .Commands ())))
231
284
}
232
285
233
286
resp = d .client .Do (ctx , cmd )
234
287
d .end (span , resp .Error ())
288
+ d .recordError (ctx , op , resp .Error ())
235
289
return
236
290
}
237
291
238
292
func (d * dedicated ) DoMulti (ctx context.Context , multi ... rueidis.Completed ) (resp []rueidis.RedisResult ) {
239
- ctx , span := d .start (ctx , multiFirst (multi ), multiSum (multi ))
293
+ op := multiFirst (multi )
294
+ defer d .recordDuration (ctx , op , time .Now ())
295
+ ctx , span := d .start (ctx , op , multiSum (multi ))
240
296
resp = d .client .DoMulti (ctx , multi ... )
241
- d .end (span , firstError (resp ))
297
+ err := firstError (resp )
298
+ d .end (span , err )
299
+ d .recordError (ctx , op , err )
242
300
return
243
301
}
244
302
0 commit comments