5
5
import pytest
6
6
from celery import Celery , VERSION
7
7
from celery .bin import worker
8
+ from celery .app .task import Task
9
+ from opentelemetry import trace as otel_trace , context
8
10
9
11
import sentry_sdk
10
- from sentry_sdk import start_span , get_current_span
12
+ from sentry_sdk import get_current_span
11
13
from sentry_sdk .integrations .celery import (
12
14
CeleryIntegration ,
13
15
_wrap_task_run ,
@@ -126,14 +128,14 @@ def dummy_task(x, y):
126
128
foo = 42 # noqa
127
129
return x / y
128
130
129
- with start_span (op = "unit test transaction" ) as transaction :
131
+ with sentry_sdk . start_span (op = "unit test transaction" ) as root_span :
130
132
celery_invocation (dummy_task , 1 , 2 )
131
133
_ , expected_context = celery_invocation (dummy_task , 1 , 0 )
132
134
133
135
(_ , error_event , _ , _ ) = events
134
136
135
- assert error_event ["contexts" ]["trace" ]["trace_id" ] == transaction .trace_id
136
- assert error_event ["contexts" ]["trace" ]["span_id" ] != transaction .span_id
137
+ assert error_event ["contexts" ]["trace" ]["trace_id" ] == root_span .trace_id
138
+ assert error_event ["contexts" ]["trace" ]["span_id" ] != root_span .span_id
137
139
assert error_event ["transaction" ] == "dummy_task"
138
140
assert "celery_task_id" in error_event ["tags" ]
139
141
assert error_event ["extra" ]["celery-job" ] == dict (
@@ -190,17 +192,14 @@ def test_transaction_events(capture_events, init_celery, celery_invocation, task
190
192
def dummy_task (x , y ):
191
193
return x / y
192
194
193
- # XXX: For some reason the first call does not get instrumented properly.
194
- celery_invocation (dummy_task , 1 , 1 )
195
-
196
195
events = capture_events ()
197
196
198
- with start_span (name = "submission" ) as transaction :
197
+ with sentry_sdk . start_span (name = "submission" ) as root_span :
199
198
celery_invocation (dummy_task , 1 , 0 if task_fails else 1 )
200
199
201
200
if task_fails :
202
201
error_event = events .pop (0 )
203
- assert error_event ["contexts" ]["trace" ]["trace_id" ] == transaction .trace_id
202
+ assert error_event ["contexts" ]["trace" ]["trace_id" ] == root_span .trace_id
204
203
assert error_event ["exception" ]["values" ][0 ]["type" ] == "ZeroDivisionError"
205
204
206
205
execution_event , submission_event = events
@@ -211,24 +210,21 @@ def dummy_task(x, y):
211
210
assert submission_event ["transaction_info" ] == {"source" : "custom" }
212
211
213
212
assert execution_event ["type" ] == submission_event ["type" ] == "transaction"
214
- assert execution_event ["contexts" ]["trace" ]["trace_id" ] == transaction .trace_id
215
- assert submission_event ["contexts" ]["trace" ]["trace_id" ] == transaction .trace_id
213
+ assert execution_event ["contexts" ]["trace" ]["trace_id" ] == root_span .trace_id
214
+ assert submission_event ["contexts" ]["trace" ]["trace_id" ] == root_span .trace_id
216
215
217
216
if task_fails :
218
217
assert execution_event ["contexts" ]["trace" ]["status" ] == "internal_error"
219
218
else :
220
219
assert execution_event ["contexts" ]["trace" ]["status" ] == "ok"
221
220
222
221
assert len (execution_event ["spans" ]) == 1
223
- assert (
224
- execution_event ["spans" ][0 ].items ()
225
- >= {
226
- "trace_id" : str (transaction .trace_id ),
227
- "same_process_as_parent" : True ,
222
+ assert execution_event ["spans" ][0 ] == ApproxDict (
223
+ {
224
+ "trace_id" : str (root_span .trace_id ),
228
225
"op" : "queue.process" ,
229
226
"description" : "dummy_task" ,
230
- "data" : ApproxDict (),
231
- }.items ()
227
+ }
232
228
)
233
229
assert submission_event ["spans" ] == [
234
230
{
@@ -237,11 +233,14 @@ def dummy_task(x, y):
237
233
"op" : "queue.submit.celery" ,
238
234
"origin" : "auto.queue.celery" ,
239
235
"parent_span_id" : submission_event ["contexts" ]["trace" ]["span_id" ],
240
- "same_process_as_parent" : True ,
241
236
"span_id" : submission_event ["spans" ][0 ]["span_id" ],
242
237
"start_timestamp" : submission_event ["spans" ][0 ]["start_timestamp" ],
243
238
"timestamp" : submission_event ["spans" ][0 ]["timestamp" ],
244
- "trace_id" : str (transaction .trace_id ),
239
+ "trace_id" : str (root_span .trace_id ),
240
+ "status" : "ok" ,
241
+ "tags" : {
242
+ "status" : "ok" ,
243
+ },
245
244
}
246
245
]
247
246
@@ -275,7 +274,7 @@ def test_simple_no_propagation(capture_events, init_celery):
275
274
def dummy_task ():
276
275
1 / 0
277
276
278
- with start_span (name = "task" ) as root_span :
277
+ with sentry_sdk . start_span (name = "task" ) as root_span :
279
278
dummy_task .delay ()
280
279
281
280
(event ,) = events
@@ -350,7 +349,7 @@ def dummy_task(self):
350
349
runs .append (1 )
351
350
1 / 0
352
351
353
- with start_span (name = "submit_celery" ):
352
+ with sentry_sdk . start_span (name = "submit_celery" ):
354
353
# Curious: Cannot use delay() here or py2.7-celery-4.2 crashes
355
354
res = dummy_task .apply_async ()
356
355
@@ -445,7 +444,7 @@ def walk_dogs(x, y):
445
444
walk_dogs , [["Maisey" , "Charlie" , "Bodhi" , "Cory" ], "Dog park round trip" ], 1
446
445
)
447
446
448
- sampling_context = traces_sampler .call_args_list [1 ][0 ][0 ]
447
+ sampling_context = traces_sampler .call_args_list [0 ][0 ][0 ]
449
448
assert sampling_context ["celery.job.task" ] == "dog_walk"
450
449
for i , arg in enumerate (args_kwargs ["args" ]):
451
450
assert sampling_context [f"celery.job.args.{ i } " ] == str (arg )
@@ -469,7 +468,7 @@ def __call__(self, *args, **kwargs):
469
468
def dummy_task (x , y ):
470
469
return x / y
471
470
472
- with start_span (name = "celery" ):
471
+ with sentry_sdk . start_span (name = "celery" ):
473
472
celery_invocation (dummy_task , 1 , 0 )
474
473
475
474
assert not events
@@ -510,7 +509,7 @@ def test_baggage_propagation(init_celery):
510
509
def dummy_task (self , x , y ):
511
510
return _get_headers (self )
512
511
513
- with start_span (name = "task" ) as root_span :
512
+ with sentry_sdk . start_span (name = "task" ) as root_span :
514
513
result = dummy_task .apply_async (
515
514
args = (1 , 0 ),
516
515
headers = {"baggage" : "custom=value" },
@@ -520,6 +519,7 @@ def dummy_task(self, x, y):
520
519
[
521
520
"sentry-release=abcdef" ,
522
521
"sentry-trace_id={}" .format (root_span .trace_id ),
522
+ "sentry-transaction=task" ,
523
523
"sentry-environment=production" ,
524
524
"sentry-sample_rate=1.0" ,
525
525
"sentry-sampled=true" ,
@@ -537,26 +537,42 @@ def test_sentry_propagate_traces_override(init_celery):
537
537
propagate_traces = True , traces_sample_rate = 1.0 , release = "abcdef"
538
538
)
539
539
540
+ # Since we're applying the task inline eagerly,
541
+ # we need to cleanup the otel context for this test.
542
+ # and since we patch build_tracer, we need to do this before that runs...
543
+ # TODO: the right way is to not test this inline
544
+ original_apply = Task .apply
545
+
546
+ def cleaned_apply (* args , ** kwargs ):
547
+ token = context .attach (otel_trace .set_span_in_context (otel_trace .INVALID_SPAN ))
548
+ rv = original_apply (* args , ** kwargs )
549
+ context .detach (token )
550
+ return rv
551
+
552
+ Task .apply = cleaned_apply
553
+
540
554
@celery .task (name = "dummy_task" , bind = True )
541
555
def dummy_task (self , message ):
542
556
trace_id = get_current_span ().trace_id
543
557
return trace_id
544
558
545
- with start_span (name = "task" ) as root_span :
546
- transaction_trace_id = root_span .trace_id
559
+ with sentry_sdk . start_span (name = "task" ) as root_span :
560
+ root_span_trace_id = root_span .trace_id
547
561
548
562
# should propagate trace
549
- task_transaction_id = dummy_task .apply_async (
563
+ task_trace_id = dummy_task .apply_async (
550
564
args = ("some message" ,),
551
565
).get ()
552
- assert transaction_trace_id == task_transaction_id
566
+ assert root_span_trace_id == task_trace_id , "Trace should be propagated"
553
567
554
568
# should NOT propagate trace (overrides `propagate_traces` parameter in integration constructor)
555
- task_transaction_id = dummy_task .apply_async (
569
+ task_trace_id = dummy_task .apply_async (
556
570
args = ("another message" ,),
557
571
headers = {"sentry-propagate-traces" : False },
558
572
).get ()
559
- assert transaction_trace_id != task_transaction_id
573
+ assert root_span_trace_id != task_trace_id , "Trace should NOT be propagated"
574
+
575
+ Task .apply = original_apply
560
576
561
577
562
578
def test_apply_async_manually_span (sentry_init ):
@@ -710,7 +726,7 @@ def publish(*args, **kwargs):
710
726
@celery .task ()
711
727
def task (): ...
712
728
713
- with start_span (name = "task" ):
729
+ with sentry_sdk . start_span (name = "task" ):
714
730
task .apply_async ()
715
731
716
732
(event ,) = events
@@ -773,7 +789,7 @@ def publish(*args, **kwargs):
773
789
@celery .task ()
774
790
def task (): ...
775
791
776
- with start_span (name = "custom_transaction" ):
792
+ with sentry_sdk . start_span (name = "custom_transaction" ):
777
793
task .apply_async ()
778
794
779
795
(event ,) = events
0 commit comments