13
13
# limitations under the License.
14
14
15
15
import asyncio
16
+ from time import time_ns
16
17
17
18
import redis
18
19
import redis .asyncio
@@ -326,6 +327,29 @@ def test_basics(self):
326
327
)
327
328
self .assertEqual (span .attributes .get ("db.redis.args_length" ), 2 )
328
329
330
+ def test_execute_command_traced_full_time (self ):
331
+ """Command should be traced for coroutine execution time, not creation time."""
332
+ coro_created_time = None
333
+ finish_time = None
334
+
335
+ async def pipeline_simple ():
336
+ nonlocal coro_created_time
337
+ nonlocal finish_time
338
+
339
+ # delay coroutine creation from coroutine execution
340
+ coro = self .redis_client .get ("foo" )
341
+ coro_created_time = time_ns ()
342
+ await coro
343
+ finish_time = time_ns ()
344
+
345
+ async_call (pipeline_simple ())
346
+
347
+ spans = self .memory_exporter .get_finished_spans ()
348
+ self .assertEqual (len (spans ), 1 )
349
+ span = spans [0 ]
350
+ self .assertTrue (span .start_time > coro_created_time )
351
+ self .assertTrue (span .end_time < finish_time )
352
+
329
353
def test_pipeline_traced (self ):
330
354
async def pipeline_simple ():
331
355
async with self .redis_client .pipeline (
@@ -348,6 +372,35 @@ async def pipeline_simple():
348
372
)
349
373
self .assertEqual (span .attributes .get ("db.redis.pipeline_length" ), 3 )
350
374
375
+ def test_pipeline_traced_full_time (self ):
376
+ """Command should be traced for coroutine execution time, not creation time."""
377
+ coro_created_time = None
378
+ finish_time = None
379
+
380
+ async def pipeline_simple ():
381
+ async with self .redis_client .pipeline (
382
+ transaction = False
383
+ ) as pipeline :
384
+ nonlocal coro_created_time
385
+ nonlocal finish_time
386
+ pipeline .set ("blah" , 32 )
387
+ pipeline .rpush ("foo" , "éé" )
388
+ pipeline .hgetall ("xxx" )
389
+
390
+ # delay coroutine creation from coroutine execution
391
+ coro = pipeline .execute ()
392
+ coro_created_time = time_ns ()
393
+ await coro
394
+ finish_time = time_ns ()
395
+
396
+ async_call (pipeline_simple ())
397
+
398
+ spans = self .memory_exporter .get_finished_spans ()
399
+ self .assertEqual (len (spans ), 1 )
400
+ span = spans [0 ]
401
+ self .assertTrue (span .start_time > coro_created_time )
402
+ self .assertTrue (span .end_time < finish_time )
403
+
351
404
def test_pipeline_immediate (self ):
352
405
async def pipeline_immediate ():
353
406
async with self .redis_client .pipeline () as pipeline :
@@ -367,6 +420,33 @@ async def pipeline_immediate():
367
420
span .attributes .get (SpanAttributes .DB_STATEMENT ), "SET b 2"
368
421
)
369
422
423
+ def test_pipeline_immediate_traced_full_time (self ):
424
+ """Command should be traced for coroutine execution time, not creation time."""
425
+ coro_created_time = None
426
+ finish_time = None
427
+
428
+ async def pipeline_simple ():
429
+ async with self .redis_client .pipeline (
430
+ transaction = False
431
+ ) as pipeline :
432
+ nonlocal coro_created_time
433
+ nonlocal finish_time
434
+ pipeline .set ("a" , 1 )
435
+
436
+ # delay coroutine creation from coroutine execution
437
+ coro = pipeline .immediate_execute_command ("SET" , "b" , 2 )
438
+ coro_created_time = time_ns ()
439
+ await coro
440
+ finish_time = time_ns ()
441
+
442
+ async_call (pipeline_simple ())
443
+
444
+ spans = self .memory_exporter .get_finished_spans ()
445
+ self .assertEqual (len (spans ), 1 )
446
+ span = spans [0 ]
447
+ self .assertTrue (span .start_time > coro_created_time )
448
+ self .assertTrue (span .end_time < finish_time )
449
+
370
450
def test_parent (self ):
371
451
"""Ensure OpenTelemetry works with redis."""
372
452
ot_tracer = trace .get_tracer ("redis_svc" )
@@ -416,6 +496,29 @@ def test_basics(self):
416
496
)
417
497
self .assertEqual (span .attributes .get ("db.redis.args_length" ), 2 )
418
498
499
+ def test_execute_command_traced_full_time (self ):
500
+ """Command should be traced for coroutine execution time, not creation time."""
501
+ coro_created_time = None
502
+ finish_time = None
503
+
504
+ async def pipeline_simple ():
505
+ nonlocal coro_created_time
506
+ nonlocal finish_time
507
+
508
+ # delay coroutine creation from coroutine execution
509
+ coro = self .redis_client .get ("foo" )
510
+ coro_created_time = time_ns ()
511
+ await coro
512
+ finish_time = time_ns ()
513
+
514
+ async_call (pipeline_simple ())
515
+
516
+ spans = self .memory_exporter .get_finished_spans ()
517
+ self .assertEqual (len (spans ), 1 )
518
+ span = spans [0 ]
519
+ self .assertTrue (span .start_time > coro_created_time )
520
+ self .assertTrue (span .end_time < finish_time )
521
+
419
522
def test_pipeline_traced (self ):
420
523
async def pipeline_simple ():
421
524
async with self .redis_client .pipeline (
@@ -438,6 +541,35 @@ async def pipeline_simple():
438
541
)
439
542
self .assertEqual (span .attributes .get ("db.redis.pipeline_length" ), 3 )
440
543
544
+ def test_pipeline_traced_full_time (self ):
545
+ """Command should be traced for coroutine execution time, not creation time."""
546
+ coro_created_time = None
547
+ finish_time = None
548
+
549
+ async def pipeline_simple ():
550
+ async with self .redis_client .pipeline (
551
+ transaction = False
552
+ ) as pipeline :
553
+ nonlocal coro_created_time
554
+ nonlocal finish_time
555
+ pipeline .set ("blah" , 32 )
556
+ pipeline .rpush ("foo" , "éé" )
557
+ pipeline .hgetall ("xxx" )
558
+
559
+ # delay coroutine creation from coroutine execution
560
+ coro = pipeline .execute ()
561
+ coro_created_time = time_ns ()
562
+ await coro
563
+ finish_time = time_ns ()
564
+
565
+ async_call (pipeline_simple ())
566
+
567
+ spans = self .memory_exporter .get_finished_spans ()
568
+ self .assertEqual (len (spans ), 1 )
569
+ span = spans [0 ]
570
+ self .assertTrue (span .start_time > coro_created_time )
571
+ self .assertTrue (span .end_time < finish_time )
572
+
441
573
def test_parent (self ):
442
574
"""Ensure OpenTelemetry works with redis."""
443
575
ot_tracer = trace .get_tracer ("redis_svc" )
0 commit comments