Skip to content

Commit 1cf1491

Browse files
committed
fix(sampling): Attribute backpressure as unsampling reason
1 parent 8a4062b commit 1cf1491

2 files changed

Lines changed: 76 additions & 4 deletions

File tree

sentry_sdk/tracing_utils.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,23 +1577,39 @@ def _make_sampling_decision(
15771577
return False, 0.0, None, "sample_rate"
15781578

15791579
# Adjust sample rate if we're under backpressure
1580+
sample_rate_before_backpressure = sample_rate
15801581
if client.monitor:
15811582
sample_rate /= 2**client.monitor.downsample_factor
15821583

15831584
if not sample_rate:
15841585
logger.debug(f"[Tracing] Discarding {name} because backpressure")
15851586
return False, 0.0, None, "backpressure"
15861587

1588+
# Make the actual decision
15871589
sampled = sample_rand < sample_rate
15881590

15891591
if sampled:
15901592
logger.debug(f"[Tracing] Starting {name}")
15911593
outcome = None
1594+
15921595
else:
1593-
logger.debug(
1594-
f"[Tracing] Discarding {name} because it's not included in the random sample (sampling rate = {sample_rate})"
1595-
)
1596-
outcome = "sample_rate"
1596+
# Determine why exactly the span will not be sampled. If we've lowered
1597+
# the effective sample_rate because of backpressure, check whether the
1598+
# span would've been sampled if backpressure wasn't active. If that's the
1599+
# case, backpressure is the actual reason, otherwise just pure sampling
1600+
# rate.
1601+
if (
1602+
sample_rate_before_backpressure != sample_rate
1603+
and sample_rand < sample_rate_before_backpressure
1604+
):
1605+
logger.debug(f"[Tracing] Discarding {name} because backpressure")
1606+
outcome = "backpressure"
1607+
1608+
else:
1609+
logger.debug(
1610+
f"[Tracing] Discarding {name} because it's not included in the random sample (sampling rate = {sample_rate})"
1611+
)
1612+
outcome = "sample_rate"
15971613

15981614
return sampled, sample_rate, sample_rand, outcome
15991615

tests/tracing/test_span_streaming.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,62 @@ def test_continue_trace_unsampled(sentry_init, capture_items):
754754
assert len(spans) == 0
755755

756756

757+
@pytest.mark.parametrize(
758+
("sample_rand", "expected_sampled", "expected_outcome"),
759+
[
760+
("0.100000", True, None),
761+
("0.300000", False, "backpressure"),
762+
("0.700000", False, "sample_rate"),
763+
],
764+
)
765+
def test_backpressure_outcome(
766+
sentry_init,
767+
capture_items,
768+
capture_record_lost_event_calls,
769+
sample_rand,
770+
expected_sampled,
771+
expected_outcome,
772+
):
773+
sentry_init(
774+
traces_sample_rate=0.5,
775+
enable_backpressure_handling=True,
776+
_experiments={"trace_lifecycle": "stream"},
777+
)
778+
779+
items = capture_items("span")
780+
record_lost_event_calls = capture_record_lost_event_calls()
781+
782+
client = sentry_sdk.get_client()
783+
client.monitor._downsample_factor = 1
784+
785+
trace_id = "0af7651916cd43dd8448eb211c80319c"
786+
parent_span_id = "b7ad6b7169203331"
787+
788+
sentry_sdk.traces.continue_trace(
789+
{
790+
"sentry-trace": f"{trace_id}-{parent_span_id}",
791+
"baggage": f"sentry-trace_id={trace_id},sentry-sample_rand={sample_rand}",
792+
}
793+
)
794+
795+
with sentry_sdk.traces.start_span(name="span") as span:
796+
pass
797+
798+
sentry_sdk.get_client().flush()
799+
spans = [item.payload for item in items]
800+
801+
assert span.sampled is expected_sampled
802+
803+
if expected_sampled:
804+
assert len(spans) == 1
805+
assert not record_lost_event_calls
806+
else:
807+
assert len(spans) == 0
808+
assert record_lost_event_calls == [
809+
(expected_outcome, "span", None, 1),
810+
]
811+
812+
757813
def test_unsampled_spans_produce_client_report(
758814
sentry_init, capture_items, capture_record_lost_event_calls
759815
):

0 commit comments

Comments
 (0)