10
10
require_relative '../../../../../lib/opentelemetry/instrumentation/redis/patches/redis_v4_client'
11
11
12
12
describe OpenTelemetry ::Instrumentation ::Redis ::Patches ::RedisV4Client do
13
+ # NOTE: These tests should be run for redis v4 and redis v5, even though the patches won't be installed on v5.
14
+ # Perhaps these tests should live in a different file?
13
15
let ( :instrumentation ) { OpenTelemetry ::Instrumentation ::Redis ::Instrumentation . instance }
14
16
let ( :exporter ) { EXPORTER }
15
17
let ( :password ) { 'passw0rd' }
21
23
# will generate one extra span on connect because the Redis client will
22
24
# send an AUTH command before doing anything else.
23
25
def redis_with_auth ( redis_options = { } )
24
- redis_options [ :password ] = password
25
- redis_options [ :host ] = redis_host
26
- redis_options [ :port ] = redis_port
26
+ redis_options [ :password ] || = password
27
+ redis_options [ :host ] || = redis_host
28
+ redis_options [ :port ] || = redis_port
27
29
Redis . new ( redis_options )
28
30
end
29
31
32
+ def redis_version
33
+ Gem . loaded_specs [ 'redis' ] &.version
34
+ end
35
+
36
+ def redis_version_major
37
+ redis_version &.segments &.first
38
+ end
39
+
40
+ def redis_gte_5?
41
+ redis_version_major &.>=( 5 )
42
+ end
43
+
30
44
before do
31
45
# ensure obfuscation is off if it was previously set in a different test
32
46
config = { db_statement : :include }
@@ -98,16 +112,27 @@ def redis_with_auth(redis_options = {})
98
112
redis = redis_with_auth ( db : 1 )
99
113
redis . get ( 'K' )
100
114
101
- _ ( exporter . finished_spans . size ) . must_equal 3
115
+ if redis_gte_5?
116
+ _ ( exporter . finished_spans . size ) . must_equal 2
117
+ select_span = exporter . finished_spans . first
118
+ get_span = exporter . finished_spans . last
119
+ _ ( select_span . name ) . must_equal 'PIPELINED'
120
+ _ ( select_span . attributes [ 'db.statement' ] ) . must_equal ( "AUTH ?\n SELECT 1" )
121
+ else
122
+ _ ( exporter . finished_spans . size ) . must_equal 3
123
+
124
+ select_span = exporter . finished_spans [ 1 ]
125
+ _ ( select_span . name ) . must_equal 'SELECT'
126
+ _ ( select_span . attributes [ 'db.statement' ] ) . must_equal ( 'SELECT 1' )
127
+
128
+ get_span = exporter . finished_spans . last
129
+ end
102
130
103
- select_span = exporter . finished_spans [ 1 ]
104
- _ ( select_span . name ) . must_equal 'SELECT'
105
131
_ ( select_span . attributes [ 'db.system' ] ) . must_equal 'redis'
106
- _ ( select_span . attributes [ 'db.statement' ] ) . must_equal ( 'SELECT 1' )
107
132
_ ( select_span . attributes [ 'net.peer.name' ] ) . must_equal redis_host
108
133
_ ( select_span . attributes [ 'net.peer.port' ] ) . must_equal redis_port
134
+ _ ( select_span . attributes [ 'db.redis.database_index' ] ) . must_equal 1
109
135
110
- get_span = exporter . finished_spans . last
111
136
_ ( get_span . name ) . must_equal 'GET'
112
137
_ ( get_span . attributes [ 'db.system' ] ) . must_equal 'redis'
113
138
_ ( get_span . attributes [ 'db.statement' ] ) . must_equal ( 'GET K' )
@@ -150,21 +175,35 @@ def redis_with_auth(redis_options = {})
150
175
_ ( last_span . status . code ) . must_equal (
151
176
OpenTelemetry ::Trace ::Status ::ERROR
152
177
)
153
- _ ( last_span . status . description . tr ( '`' , "'" ) ) . must_include (
154
- "ERR unknown command 'THIS_IS_NOT_A_REDIS_FUNC', with args beginning with: 'THIS_IS_NOT_A_VALID_ARG"
155
- )
178
+
179
+ if redis_gte_5?
180
+ _ ( last_span . status . description . tr ( '`' , "'" ) ) . must_include (
181
+ 'Unhandled exception of type: RedisClient::CommandError'
182
+ )
183
+ else
184
+ _ ( last_span . status . description . tr ( '`' , "'" ) ) . must_include (
185
+ "ERR unknown command 'THIS_IS_NOT_A_REDIS_FUNC', with args beginning with: 'THIS_IS_NOT_A_VALID_ARG"
186
+ )
187
+ end
156
188
end
157
189
158
190
it 'records net.peer.name and net.peer.port attributes' do
159
- expect do
160
- Redis . new ( host : 'example.com' , port : 8321 , timeout : 0.01 ) . auth ( password )
161
- end . must_raise Redis ::CannotConnectError
162
-
163
- _ ( last_span . name ) . must_equal 'AUTH'
164
- _ ( last_span . attributes [ 'db.system' ] ) . must_equal 'redis'
165
- _ ( last_span . attributes [ 'db.statement' ] ) . must_equal 'AUTH ?'
166
- _ ( last_span . attributes [ 'net.peer.name' ] ) . must_equal 'example.com'
167
- _ ( last_span . attributes [ 'net.peer.port' ] ) . must_equal 8321
191
+ client = Redis . new ( host : 'example.com' , port : 8321 , timeout : 0.01 )
192
+ expect { client . auth ( password ) } . must_raise Redis ::CannotConnectError
193
+
194
+ if redis_gte_5?
195
+ skip (
196
+ 'Redis 5 is a wrapper around RedisClient, which calls' \
197
+ '`ensure_connected` before any of the middlewares are invoked.' \
198
+ 'This is more appropriately instrumented via a `#connect` hook in the middleware.'
199
+ )
200
+ else
201
+ _ ( last_span . name ) . must_equal 'AUTH'
202
+ _ ( last_span . attributes [ 'db.system' ] ) . must_equal 'redis'
203
+ _ ( last_span . attributes [ 'db.statement' ] ) . must_equal 'AUTH ?'
204
+ _ ( last_span . attributes [ 'net.peer.name' ] ) . must_equal 'example.com'
205
+ _ ( last_span . attributes [ 'net.peer.port' ] ) . must_equal 8321
206
+ end
168
207
end
169
208
170
209
it 'traces pipelined commands' do
@@ -185,10 +224,11 @@ def redis_with_auth(redis_options = {})
185
224
186
225
it 'traces pipelined commands on commit' do
187
226
redis = redis_with_auth
188
- redis . queue ( [ :set , 'v1' , '0' ] )
189
- redis . queue ( [ :incr , 'v1' ] )
190
- redis . queue ( [ :get , 'v1' ] )
191
- redis . commit
227
+ redis . pipelined do |pipeline |
228
+ pipeline . set ( 'v1' , '0' )
229
+ pipeline . incr ( 'v1' )
230
+ pipeline . get ( 'v1' )
231
+ end
192
232
193
233
_ ( exporter . finished_spans . size ) . must_equal 2
194
234
_ ( last_span . name ) . must_equal 'PIPELINED'
@@ -225,16 +265,17 @@ def redis_with_auth(redis_options = {})
225
265
it 'truncates long db.statements' do
226
266
redis = redis_with_auth
227
267
the_long_value = 'y' * 100
228
- redis . queue ( [ :set , 'v1' , the_long_value ] )
229
- redis . queue ( [ :set , 'v1' , the_long_value ] )
230
- redis . queue ( [ :set , 'v1' , the_long_value ] )
231
- redis . queue ( [ :set , 'v1' , the_long_value ] )
232
- redis . queue ( [ :set , 'v1' , the_long_value ] )
233
- redis . queue ( [ :set , 'v1' , the_long_value ] )
234
- redis . queue ( [ :set , 'v1' , the_long_value ] )
235
- redis . queue ( [ :set , 'v1' , the_long_value ] )
236
- redis . queue ( [ :set , 'v1' , the_long_value ] )
237
- redis . commit
268
+ redis . pipelined do |pipeline |
269
+ pipeline . set ( 'v1' , the_long_value )
270
+ pipeline . set ( 'v1' , the_long_value )
271
+ pipeline . set ( 'v1' , the_long_value )
272
+ pipeline . set ( 'v1' , the_long_value )
273
+ pipeline . set ( 'v1' , the_long_value )
274
+ pipeline . set ( 'v1' , the_long_value )
275
+ pipeline . set ( 'v1' , the_long_value )
276
+ pipeline . set ( 'v1' , the_long_value )
277
+ pipeline . set ( 'v1' , the_long_value )
278
+ end
238
279
239
280
expected_db_statement = <<~HEREDOC . chomp
240
281
SET v1 yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
@@ -297,7 +338,7 @@ def redis_with_auth(redis_options = {})
297
338
_ ( exporter . finished_spans . size ) . must_equal 3
298
339
299
340
set_span = exporter . finished_spans [ 0 ]
300
- _ ( set_span . name ) . must_equal ' AUTH'
341
+ _ ( set_span . name ) . must_equal ( redis_gte_5? ? 'PIPELINED' : ' AUTH')
301
342
_ ( set_span . attributes [ 'db.system' ] ) . must_equal 'redis'
302
343
_ ( set_span . attributes ) . wont_include ( 'db.statement' )
303
344
@@ -326,7 +367,7 @@ def redis_with_auth(redis_options = {})
326
367
_ ( exporter . finished_spans . size ) . must_equal 3
327
368
328
369
set_span = exporter . finished_spans [ 0 ]
329
- _ ( set_span . name ) . must_equal ' AUTH'
370
+ _ ( set_span . name ) . must_equal ( redis_gte_5? ? 'PIPELINED' : ' AUTH')
330
371
_ ( set_span . attributes [ 'db.system' ] ) . must_equal 'redis'
331
372
_ ( set_span . attributes [ 'db.statement' ] ) . must_equal (
332
373
'AUTH ?'
0 commit comments