diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index a6b1905a3c..de07969822 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -714,8 +714,27 @@ def __repr__(self): ) ) + def _possibly_started(self): + # type: () -> bool + """Returns whether the transaction might have been started. + + If this returns False, we know that the transaction was not started + with sentry_sdk.start_transaction, and therefore the transaction will + be discarded. + """ + + # We must explicitly check self.sampled is False since self.sampled can be None + return self._span_recorder is not None or self.sampled is False + def __enter__(self): # type: () -> Transaction + if not self._possibly_started(): + logger.warning( + "Transaction was entered without being started with sentry_sdk.start_transaction." + "The transaction will not be sent to Sentry. To fix, start the transaction by" + "passing it to sentry_sdk.start_transaction." + ) + super().__enter__() if self._profile is not None: diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py index af1837f12c..e1006ef1bb 100644 --- a/tests/tracing/test_misc.py +++ b/tests/tracing/test_misc.py @@ -401,3 +401,19 @@ def test_transaction_dropeed_sampled_false(sentry_init): mock_logger.debug.assert_any_call( "Discarding transaction because it was not started with sentry_sdk.start_transaction" ) + + +def test_transaction_not_started_warning(sentry_init): + sentry_init(enable_tracing=True) + + tx = Transaction() + + with mock.patch("sentry_sdk.tracing.logger") as mock_logger: + with tx: + pass + + mock_logger.warning.assert_any_call( + "Transaction was entered without being started with sentry_sdk.start_transaction." + "The transaction will not be sent to Sentry. To fix, start the transaction by" + "passing it to sentry_sdk.start_transaction." + )