Skip to content

Commit 18a1877

Browse files
merge master
2 parents 1f729dc + 504cbe9 commit 18a1877

3 files changed

Lines changed: 88 additions & 4 deletions

File tree

scripts/populate_tox/config.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@
393393
# https://github.com/jamesls/fakeredis/issues/245
394394
# https://github.com/cunla/fakeredis-py/issues/341
395395
"*": ["fakeredis"],
396+
# RQ commit https://github.com/rq/rq/commit/64cb1a27b9d1f2fd52bbbb5c1e4518c024f74685
397+
# introduced unguarded access to "addr" from the CLIENT LIST command.
398+
# The default "addr" value was removed in https://github.com/cunla/fakeredis-py/commit/0441288fb22c8c191fc716b561e0001cf512abe5.
399+
# from fakeredis.
400+
">=1.1.14": ["fakeredis<2.36.0"],
396401
"<0.9": ["fakeredis<1.0", "redis<3.2.2"],
397402
">=0.9,<0.14": ["fakeredis>=1.0,<1.7.4"],
398403
"py3.6,py3.7": ["fakeredis!=2.26.0"],

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: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,69 @@ 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.250000", False, "backpressure"),
762+
("0.300000", False, "backpressure"),
763+
("0.500000", False, "sample_rate"),
764+
("0.700000", False, "sample_rate"),
765+
],
766+
)
767+
def test_backpressure_outcome(
768+
sentry_init,
769+
capture_items,
770+
capture_record_lost_event_calls,
771+
sample_rand,
772+
expected_sampled,
773+
expected_outcome,
774+
):
775+
sentry_init(
776+
traces_sample_rate=0.5,
777+
enable_backpressure_handling=True,
778+
_experiments={"trace_lifecycle": "stream"},
779+
)
780+
781+
items = capture_items("span")
782+
record_lost_event_calls = capture_record_lost_event_calls()
783+
784+
client = sentry_sdk.get_client()
785+
client.monitor._downsample_factor = 1
786+
787+
trace_id = "0af7651916cd43dd8448eb211c80319c"
788+
parent_span_id = "b7ad6b7169203331"
789+
790+
sentry_sdk.traces.continue_trace(
791+
{
792+
"sentry-trace": f"{trace_id}-{parent_span_id}",
793+
"baggage": f"sentry-trace_id={trace_id},sentry-sample_rand={sample_rand}",
794+
}
795+
)
796+
797+
with sentry_sdk.traces.start_span(name="span") as span:
798+
pass
799+
800+
sentry_sdk.get_client().flush()
801+
spans = [item.payload for item in items]
802+
803+
# Original traces_sample_rate is 0.5, downsampled sample rate is 0.25, so:
804+
# - sample_rand < 0.25 -> sampled
805+
# - 0.25 < sample_rand < 0.5 -> unsampled because of backpressure (would've been sampled if no backpressure)
806+
# - 0.5 < sample_rand -> unsampled because of sampling rate
807+
808+
assert span.sampled is expected_sampled
809+
810+
if expected_sampled:
811+
assert len(spans) == 1
812+
assert not record_lost_event_calls
813+
else:
814+
assert len(spans) == 0
815+
assert record_lost_event_calls == [
816+
(expected_outcome, "span", None, 1),
817+
]
818+
819+
757820
def test_unsampled_spans_produce_client_report(
758821
sentry_init, capture_items, capture_record_lost_event_calls
759822
):

0 commit comments

Comments
 (0)