diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index ae0b90253e..ca249fe8fe 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -1,3 +1,4 @@ +from decimal import Decimal import uuid import warnings from datetime import datetime, timedelta, timezone @@ -1198,10 +1199,8 @@ def _set_initial_sampling_decision(self, sampling_context): self.sampled = False return - # Now we roll the dice. self._sample_rand is inclusive of 0, but not of 1, - # so strict < is safe here. In case sample_rate is a boolean, cast it - # to a float (True becomes 1.0 and False becomes 0.0) - self.sampled = self._sample_rand < self.sample_rate + # Now we roll the dice. + self.sampled = self._sample_rand < Decimal.from_float(self.sample_rate) if self.sampled: logger.debug( diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index ba56695740..552f4fd59a 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -5,7 +5,7 @@ import sys from collections.abc import Mapping from datetime import timedelta -from decimal import ROUND_DOWN, Context, Decimal +from decimal import ROUND_DOWN, Decimal, DefaultContext, localcontext from functools import wraps from random import Random from urllib.parse import quote, unquote @@ -872,10 +872,13 @@ def _generate_sample_rand( # Round down to exactly six decimal-digit precision. # Setting the context is needed to avoid an InvalidOperation exception - # in case the user has changed the default precision. - return Decimal(sample_rand).quantize( - Decimal("0.000001"), rounding=ROUND_DOWN, context=Context(prec=6) - ) + # in case the user has changed the default precision or set traps. + with localcontext(DefaultContext) as ctx: + ctx.prec = 6 + return Decimal(sample_rand).quantize( + Decimal("0.000001"), + rounding=ROUND_DOWN, + ) def _sample_rand_range(parent_sampled, sample_rate): diff --git a/tests/tracing/test_sample_rand.py b/tests/tracing/test_sample_rand.py index ef277a3dec..f9c10aa04e 100644 --- a/tests/tracing/test_sample_rand.py +++ b/tests/tracing/test_sample_rand.py @@ -1,4 +1,5 @@ import decimal +from decimal import Inexact, FloatOperation from unittest import mock import pytest @@ -58,14 +59,19 @@ def test_transaction_uses_incoming_sample_rand( def test_decimal_context(sentry_init, capture_events): """ - Ensure that having a decimal context with a precision below 6 + Ensure that having a user altered decimal context with a precision below 6 does not cause an InvalidOperation exception. """ sentry_init(traces_sample_rate=1.0) events = capture_events() old_prec = decimal.getcontext().prec + old_inexact = decimal.getcontext().traps[Inexact] + old_float_operation = decimal.getcontext().traps[FloatOperation] + decimal.getcontext().prec = 2 + decimal.getcontext().traps[Inexact] = True + decimal.getcontext().traps[FloatOperation] = True try: with mock.patch( @@ -77,5 +83,7 @@ def test_decimal_context(sentry_init, capture_events): ) finally: decimal.getcontext().prec = old_prec + decimal.getcontext().traps[Inexact] = old_inexact + decimal.getcontext().traps[FloatOperation] = old_float_operation assert len(events) == 1