Skip to content

Commit 395e3e5

Browse files
committed
test(tracing): enhance tests for W3C traceparent header handling across integrations
1 parent ad1cde3 commit 395e3e5

File tree

9 files changed

+426
-16
lines changed

9 files changed

+426
-16
lines changed

tests/integrations/asgi/test_asgi.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,11 +297,21 @@ async def test_trace_from_headers_if_performance_enabled(
297297

298298
trace_id = "582b43a4192642f0b136d5159a501701"
299299
sentry_trace_header = "{}-{}-{}".format(trace_id, "6e8f22c393e68f19", 1)
300+
w3c_trace_header = "00-082b43a4192642f0b136d5159a501701-6e8f22c393e68f19-01"
301+
302+
# If both sentry-trace and traceparent headers are present, sentry-trace takes precedence.
303+
# See: https://github.com/getsentry/team-sdks/issues/41
300304

301305
with pytest.raises(ZeroDivisionError):
302306
async with TestClient(app) as client:
303307
events = capture_events()
304-
await client.get("/", headers={"sentry-trace": sentry_trace_header})
308+
await client.get(
309+
"/",
310+
headers={
311+
"sentry-trace": sentry_trace_header,
312+
"traceparent": w3c_trace_header,
313+
},
314+
)
305315

306316
msg_event, error_event, transaction_event = events
307317

@@ -330,11 +340,21 @@ async def test_trace_from_headers_if_performance_disabled(
330340

331341
trace_id = "582b43a4192642f0b136d5159a501701"
332342
sentry_trace_header = "{}-{}-{}".format(trace_id, "6e8f22c393e68f19", 1)
343+
w3c_trace_header = "00-082b43a4192642f0b136d5159a501701-6e8f22c393e68f19-01"
344+
345+
# If both sentry-trace and traceparent headers are present, sentry-trace takes precedence.
346+
# See: https://github.com/getsentry/team-sdks/issues/41
333347

334348
with pytest.raises(ZeroDivisionError):
335349
async with TestClient(app) as client:
336350
events = capture_events()
337-
await client.get("/", headers={"sentry-trace": sentry_trace_header})
351+
await client.get(
352+
"/",
353+
headers={
354+
"sentry-trace": sentry_trace_header,
355+
"traceparent": w3c_trace_header,
356+
},
357+
)
338358

339359
msg_event, error_event = events
340360

tests/integrations/aws_lambda/test_aws_lambda.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,41 @@ def test_trace_continuation(lambda_client, test_environment):
386386

387387
# We simulate here AWS Api Gateway's behavior of passing HTTP headers
388388
# as the `headers` dict in the event passed to the Lambda function.
389+
# If both sentry-trace and traceparent headers are present, sentry-trace takes precedence.
390+
# See: https://github.com/getsentry/team-sdks/issues/41
389391
payload = {
390392
"headers": {
391393
"sentry-trace": sentry_trace_header,
394+
"traceparent": "00-071a43a4192642f0b136d5159a501701-6e8f22c393e68f19-01",
395+
}
396+
}
397+
398+
lambda_client.invoke(
399+
FunctionName="BasicException",
400+
Payload=json.dumps(payload),
401+
)
402+
envelopes = test_environment["server"].envelopes
403+
404+
(error_event, transaction_event) = envelopes
405+
406+
assert (
407+
error_event["contexts"]["trace"]["trace_id"]
408+
== transaction_event["contexts"]["trace"]["trace_id"]
409+
== "471a43a4192642f0b136d5159a501701"
410+
)
411+
412+
413+
def test_trace_continuation_w3c_traceparent(lambda_client, test_environment):
414+
trace_id = "471a43a4192642f0b136d5159a501701"
415+
parent_span_id = "6e8f22c393e68f19"
416+
parent_sampled = "01"
417+
w3c_trace_header = "00-{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)
418+
419+
# We simulate here AWS Api Gateway's behavior of passing HTTP headers
420+
# as the `headers` dict in the event passed to the Lambda function.
421+
payload = {
422+
"headers": {
423+
"traceparent": w3c_trace_header,
392424
}
393425
}
394426

@@ -516,9 +548,12 @@ def test_error_has_existing_trace_context(
516548

517549
# We simulate here AWS Api Gateway's behavior of passing HTTP headers
518550
# as the `headers` dict in the event passed to the Lambda function.
551+
# If both sentry-trace and traceparent headers are present, sentry-trace takes precedence.
552+
# See: https://github.com/getsentry/team-sdks/issues/41
519553
payload = {
520554
"headers": {
521555
"sentry-trace": sentry_trace_header,
556+
"traceparent": "00-071a43a4192642f0b136d5159a501701-6e8f22c393e68f19-01",
522557
}
523558
}
524559

@@ -548,3 +583,47 @@ def test_error_has_existing_trace_context(
548583
transaction_event["contexts"]["trace"]["trace_id"]
549584
== "471a43a4192642f0b136d5159a501701"
550585
)
586+
587+
588+
@pytest.mark.parametrize(
589+
"lambda_function_name",
590+
["RaiseErrorPerformanceEnabled", "RaiseErrorPerformanceDisabled"],
591+
)
592+
def test_error_has_existing_w3c_trace_context(
593+
lambda_client, test_environment, lambda_function_name
594+
):
595+
trace_id = "471a43a4192642f0b136d5159a501701"
596+
parent_span_id = "6e8f22c393e68f19"
597+
parent_sampled = "01"
598+
w3c_trace_header = "00-{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)
599+
600+
# We simulate here AWS Api Gateway's behavior of passing HTTP headers
601+
# as the `headers` dict in the event passed to the Lambda function.
602+
payload = {"headers": {"traceparent": w3c_trace_header}}
603+
604+
lambda_client.invoke(
605+
FunctionName=lambda_function_name,
606+
Payload=json.dumps(payload),
607+
)
608+
envelopes = test_environment["server"].envelopes
609+
610+
if lambda_function_name == "RaiseErrorPerformanceEnabled":
611+
(error_event, transaction_event) = envelopes
612+
else:
613+
(error_event,) = envelopes
614+
transaction_event = None
615+
616+
assert "trace" in error_event["contexts"]
617+
assert "trace_id" in error_event["contexts"]["trace"]
618+
assert (
619+
error_event["contexts"]["trace"]["trace_id"]
620+
== "471a43a4192642f0b136d5159a501701"
621+
)
622+
623+
if transaction_event:
624+
assert "trace" in transaction_event["contexts"]
625+
assert "trace_id" in transaction_event["contexts"]["trace"]
626+
assert (
627+
transaction_event["contexts"]["trace"]["trace_id"]
628+
== "471a43a4192642f0b136d5159a501701"
629+
)

tests/integrations/gcp/test_gcp.py

Lines changed: 120 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ def _safe_is_equal(x, y):
360360

361361
def test_error_has_new_trace_context_performance_enabled(run_cloud_function):
362362
"""
363-
Check if an 'trace' context is added to errros and transactions when performance monitoring is enabled.
363+
Check if an 'trace' context is added to errors and transactions when performance monitoring is enabled.
364364
"""
365365
envelope_items, _ = run_cloud_function(
366366
dedent(
@@ -401,7 +401,7 @@ def cloud_function(functionhandler, event):
401401

402402
def test_error_has_new_trace_context_performance_disabled(run_cloud_function):
403403
"""
404-
Check if an 'trace' context is added to errros and transactions when performance monitoring is disabled.
404+
Check if an 'trace' context is added to errors and transactions when performance monitoring is disabled.
405405
"""
406406
envelope_items, _ = run_cloud_function(
407407
dedent(
@@ -439,13 +439,123 @@ def cloud_function(functionhandler, event):
439439

440440
def test_error_has_existing_trace_context_performance_enabled(run_cloud_function):
441441
"""
442-
Check if an 'trace' context is added to errros and transactions
442+
Check if an 'trace' context is added to errors and transactions
443443
from the incoming 'sentry-trace' header when performance monitoring is enabled.
444444
"""
445445
trace_id = "471a43a4192642f0b136d5159a501701"
446446
parent_span_id = "6e8f22c393e68f19"
447447
parent_sampled = 1
448448
sentry_trace_header = "{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)
449+
w3c_trace_header = "00-971a43a4192642f0b136d5159a501701-6e8f22c393e68f19-00"
450+
451+
# If both sentry-trace and traceparent headers are present, sentry-trace takes precedence.
452+
# See: https://github.com/getsentry/team-sdks/issues/41
453+
454+
envelope_items, _ = run_cloud_function(
455+
dedent(
456+
"""
457+
functionhandler = None
458+
459+
from collections import namedtuple
460+
GCPEvent = namedtuple("GCPEvent", ["headers"])
461+
event = GCPEvent(headers={"sentry-trace": "%s", "traceparent": "%s"})
462+
463+
def cloud_function(functionhandler, event):
464+
sentry_sdk.capture_message("hi")
465+
x = 3/0
466+
return "3"
467+
"""
468+
% sentry_trace_header,
469+
w3c_trace_header,
470+
)
471+
+ FUNCTIONS_PRELUDE
472+
+ dedent(
473+
"""
474+
init_sdk(traces_sample_rate=1.0)
475+
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
476+
"""
477+
)
478+
)
479+
(msg_event, error_event, transaction_event) = envelope_items
480+
481+
assert "trace" in msg_event["contexts"]
482+
assert "trace_id" in msg_event["contexts"]["trace"]
483+
484+
assert "trace" in error_event["contexts"]
485+
assert "trace_id" in error_event["contexts"]["trace"]
486+
487+
assert "trace" in transaction_event["contexts"]
488+
assert "trace_id" in transaction_event["contexts"]["trace"]
489+
490+
assert (
491+
msg_event["contexts"]["trace"]["trace_id"]
492+
== error_event["contexts"]["trace"]["trace_id"]
493+
== transaction_event["contexts"]["trace"]["trace_id"]
494+
== "471a43a4192642f0b136d5159a501701"
495+
)
496+
497+
498+
def test_error_has_existing_w3c_trace_context_performance_disabled(run_cloud_function):
499+
"""
500+
Check if an 'trace' context is added to errors and transactions
501+
from the incoming 'traceparent' header when performance monitoring is disabled.
502+
"""
503+
trace_id = "471a43a4192642f0b136d5159a501701"
504+
parent_span_id = "6e8f22c393e68f19"
505+
parent_sampled = "01"
506+
w3c_trace_header = "00-{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)
507+
508+
# If both sentry-trace and traceparent headers are present, sentry-trace takes precedence.
509+
# See: https://github.com/getsentry/team-sdks/issues/41
510+
511+
envelope_items, _ = run_cloud_function(
512+
dedent(
513+
"""
514+
functionhandler = None
515+
516+
from collections import namedtuple
517+
GCPEvent = namedtuple("GCPEvent", ["headers"])
518+
event = GCPEvent(headers={"traceparent": "%s"})
519+
520+
def cloud_function(functionhandler, event):
521+
sentry_sdk.capture_message("hi")
522+
x = 3/0
523+
return "3"
524+
"""
525+
% w3c_trace_header
526+
)
527+
+ FUNCTIONS_PRELUDE
528+
+ dedent(
529+
"""
530+
init_sdk(traces_sample_rate=None), # this is the default, just added for clarity
531+
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
532+
"""
533+
)
534+
)
535+
(msg_event, error_event) = envelope_items
536+
537+
assert "trace" in msg_event["contexts"]
538+
assert "trace_id" in msg_event["contexts"]["trace"]
539+
540+
assert "trace" in error_event["contexts"]
541+
assert "trace_id" in error_event["contexts"]["trace"]
542+
543+
assert (
544+
msg_event["contexts"]["trace"]["trace_id"]
545+
== error_event["contexts"]["trace"]["trace_id"]
546+
== "471a43a4192642f0b136d5159a501701"
547+
)
548+
549+
550+
def test_error_has_existing_w3c_trace_context_performance_enabled(run_cloud_function):
551+
"""
552+
Check if an 'trace' context is added to errors and transactions
553+
from the incoming 'traceparent' header when performance monitoring is enabled.
554+
"""
555+
trace_id = "471a43a4192642f0b136d5159a501701"
556+
parent_span_id = "6e8f22c393e68f19"
557+
parent_sampled = "01"
558+
w3c_trace_header = "00-{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)
449559

450560
envelope_items, _ = run_cloud_function(
451561
dedent(
@@ -454,14 +564,14 @@ def test_error_has_existing_trace_context_performance_enabled(run_cloud_function
454564
455565
from collections import namedtuple
456566
GCPEvent = namedtuple("GCPEvent", ["headers"])
457-
event = GCPEvent(headers={"sentry-trace": "%s"})
567+
event = GCPEvent(headers={"traceparent": "%s"})
458568
459569
def cloud_function(functionhandler, event):
460570
sentry_sdk.capture_message("hi")
461571
x = 3/0
462572
return "3"
463573
"""
464-
% sentry_trace_header
574+
% w3c_trace_header
465575
)
466576
+ FUNCTIONS_PRELUDE
467577
+ dedent(
@@ -492,13 +602,13 @@ def cloud_function(functionhandler, event):
492602

493603
def test_error_has_existing_trace_context_performance_disabled(run_cloud_function):
494604
"""
495-
Check if an 'trace' context is added to errros and transactions
605+
Check if an 'trace' context is added to errors and transactions
496606
from the incoming 'sentry-trace' header when performance monitoring is disabled.
497607
"""
498608
trace_id = "471a43a4192642f0b136d5159a501701"
499609
parent_span_id = "6e8f22c393e68f19"
500-
parent_sampled = 1
501-
sentry_trace_header = "{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)
610+
parent_sampled = "01"
611+
w3c_trace_header = "00-{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)
502612

503613
envelope_items, _ = run_cloud_function(
504614
dedent(
@@ -507,14 +617,14 @@ def test_error_has_existing_trace_context_performance_disabled(run_cloud_functio
507617
508618
from collections import namedtuple
509619
GCPEvent = namedtuple("GCPEvent", ["headers"])
510-
event = GCPEvent(headers={"sentry-trace": "%s"})
620+
event = GCPEvent(headers={"traceparent": "%s"})
511621
512622
def cloud_function(functionhandler, event):
513623
sentry_sdk.capture_message("hi")
514624
x = 3/0
515625
return "3"
516626
"""
517-
% sentry_trace_header
627+
% w3c_trace_header
518628
)
519629
+ FUNCTIONS_PRELUDE
520630
+ dedent(

tests/integrations/grpc/test_grpc.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,53 @@ def test_grpc_server_continues_transaction(sentry_init, capture_events_forksafe)
152152
assert span["op"] == "test"
153153

154154

155+
@pytest.mark.forked
156+
def test_grpc_server_continues_transaction_from_w3c_traceparent(
157+
sentry_init, capture_events_forksafe
158+
):
159+
sentry_init(traces_sample_rate=1.0, integrations=[GRPCIntegration()])
160+
events = capture_events_forksafe()
161+
162+
server, channel = _set_up()
163+
164+
# Use the provided channel
165+
stub = gRPCTestServiceStub(channel)
166+
167+
with start_transaction() as transaction:
168+
metadata = (
169+
(
170+
"baggage",
171+
"sentry-trace_id={trace_id},sentry-environment=test,"
172+
"sentry-transaction=test-transaction,sentry-sample_rate=1.0".format(
173+
trace_id=transaction.trace_id
174+
),
175+
),
176+
(
177+
"traceparent",
178+
"00-{trace_id}-{parent_span_id}-{sampled}".format(
179+
trace_id=transaction.trace_id,
180+
parent_span_id=transaction.span_id,
181+
sampled="01",
182+
),
183+
),
184+
)
185+
stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata)
186+
187+
_tear_down(server=server)
188+
189+
events.write_file.close()
190+
event = events.read_event()
191+
span = event["spans"][0]
192+
193+
assert event["type"] == "transaction"
194+
assert event["transaction_info"] == {
195+
"source": "custom",
196+
}
197+
assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER
198+
assert event["contexts"]["trace"]["trace_id"] == transaction.trace_id
199+
assert span["op"] == "test"
200+
201+
155202
@pytest.mark.forked
156203
def test_grpc_client_starts_span(sentry_init, capture_events_forksafe):
157204
sentry_init(traces_sample_rate=1.0, integrations=[GRPCIntegration()])

0 commit comments

Comments
 (0)