Skip to content

Commit cec2cd2

Browse files
committed
fix(tracing): Fix InvalidOperation (#4179)
`InvalidOperation` can occur when using tracing if the `Decimal` class's global context has been modified to set the precision below 6. This change fixes this bug by setting a custom context for our `quantize` call. Fixes #4177
1 parent 0cd2bce commit cec2cd2

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

sentry_sdk/tracing_utils.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import uuid
77
from collections.abc import Mapping
88
from datetime import datetime, timedelta, timezone
9+
from decimal import ROUND_DOWN, Context, Decimal
910
from functools import wraps
1011
from random import Random
1112
from urllib.parse import quote, unquote
@@ -699,8 +700,6 @@ def _generate_sample_rand(
699700
700701
The pseudorandom number generator is seeded with the trace ID.
701702
"""
702-
import decimal
703-
704703
lower, upper = interval
705704
if not lower < upper: # using `if lower >= upper` would handle NaNs incorrectly
706705
raise ValueError("Invalid interval: lower must be less than upper")
@@ -711,8 +710,10 @@ def _generate_sample_rand(
711710
sample_rand = rng.uniform(lower, upper)
712711

713712
# Round down to exactly six decimal-digit precision.
714-
return decimal.Decimal(sample_rand).quantize(
715-
decimal.Decimal("0.000001"), rounding=decimal.ROUND_DOWN
713+
# Setting the context is needed to avoid an InvalidOperation exception
714+
# in case the user has changed the default precision.
715+
return Decimal(sample_rand).quantize(
716+
Decimal("0.000001"), rounding=ROUND_DOWN, context=Context(prec=6)
716717
)
717718

718719

tests/tracing/test_sample_rand.py

+26
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import decimal
12
from unittest import mock
23

34
import pytest
@@ -53,3 +54,28 @@ def test_transaction_uses_incoming_sample_rand(
5354
# Transaction event captured if sample_rand < sample_rate, indicating that
5455
# sample_rand is used to make the sampling decision.
5556
assert len(events) == int(sample_rand < sample_rate)
57+
58+
59+
def test_decimal_context(sentry_init, capture_events):
60+
"""
61+
Ensure that having a decimal context with a precision below 6
62+
does not cause an InvalidOperation exception.
63+
"""
64+
sentry_init(traces_sample_rate=1.0)
65+
events = capture_events()
66+
67+
old_prec = decimal.getcontext().prec
68+
decimal.getcontext().prec = 2
69+
70+
try:
71+
with mock.patch(
72+
"sentry_sdk.tracing_utils.Random.uniform", return_value=0.123456789
73+
):
74+
with sentry_sdk.start_transaction() as transaction:
75+
assert (
76+
transaction.get_baggage().sentry_items["sample_rand"] == "0.123456"
77+
)
78+
finally:
79+
decimal.getcontext().prec = old_prec
80+
81+
assert len(events) == 1

0 commit comments

Comments
 (0)