Repository: getsentry/sentry-python

Issue:
Transaction source custom semantics not correct
We should get rid of `unknown` as a source completely since this is never supposed to be set by an SDK, only by relay as an inference in absence of other sources.
Also default to `custom` as the default in `start_transaction` / set transaction name helpers, and make sure there are no other cases where it ends up in a null/undefined state.

Discussion:
sl0thentr0py: @Lms24 yea I manually checked all the cases, `route` is here only for the `Generic WSGI..` stuff which is also not exactly a route but just the default name.
Later in other integrations, we do the actual resolving and set the correct source. Examples
* [ASGI](https://github.com/getsentry/sentry-python/blob/6d242c88e7baf253bca36753b576d58403141c23/sentry_sdk/integrations/asgi.py#L240-L246)
* [Django](https://github.com/getsentry/sentry-python/blob/6d242c88e7baf253bca36753b576d58403141c23/sentry_sdk/integrations/django/__init__.py#L339-L343)
Lms24: @sl0thentr0py perfect, thanks! 

Patch:
diff --git a/sentry_sdk/integrations/aiohttp.py b/sentry_sdk/integrations/aiohttp.py
index 9f4a823b..f0779017 100644
--- a/sentry_sdk/integrations/aiohttp.py
+++ b/sentry_sdk/integrations/aiohttp.py
@@ -9,7 +9,7 @@ from sentry_sdk.integrations._wsgi_common import (
     _filter_headers,
     request_body_within_bounds,
 )
-from sentry_sdk.tracing import SOURCE_FOR_STYLE, Transaction
+from sentry_sdk.tracing import SOURCE_FOR_STYLE, Transaction, TRANSACTION_SOURCE_ROUTE
 from sentry_sdk.utils import (
     capture_internal_exceptions,
     event_from_exception,
@@ -103,6 +103,7 @@ class AioHttpIntegration(Integration):
                     # If this transaction name makes it to the UI, AIOHTTP's
                     # URL resolver did not find a route or died trying.
                     name="generic AIOHTTP request",
+                    source=TRANSACTION_SOURCE_ROUTE,
                 )
                 with hub.start_transaction(
                     transaction, custom_sampling_context={"aiohttp_request": request}
diff --git a/sentry_sdk/integrations/rq.py b/sentry_sdk/integrations/rq.py
index f4c77d7d..095ab357 100644
--- a/sentry_sdk/integrations/rq.py
+++ b/sentry_sdk/integrations/rq.py
@@ -5,7 +5,7 @@ import weakref
 from sentry_sdk.hub import Hub
 from sentry_sdk.integrations import DidNotEnable, Integration
 from sentry_sdk.integrations.logging import ignore_logger
-from sentry_sdk.tracing import Transaction
+from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_TASK
 from sentry_sdk.utils import capture_internal_exceptions, event_from_exception
 
 try:
@@ -63,6 +63,7 @@ class RqIntegration(Integration):
                     job.meta.get("_sentry_trace_headers") or {},
                     op="rq.task",
                     name="unknown RQ task",
+                    source=TRANSACTION_SOURCE_TASK,
                 )
 
                 with capture_internal_exceptions():
diff --git a/sentry_sdk/integrations/starlette.py b/sentry_sdk/integrations/starlette.py
index 18cc4d51..a58c9e9b 100644
--- a/sentry_sdk/integrations/starlette.py
+++ b/sentry_sdk/integrations/starlette.py
@@ -12,9 +12,8 @@ from sentry_sdk.integrations._wsgi_common import (
     request_body_within_bounds,
 )
 from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
-from sentry_sdk.tracing import SOURCE_FOR_STYLE
+from sentry_sdk.tracing import SOURCE_FOR_STYLE, TRANSACTION_SOURCE_ROUTE
 from sentry_sdk.utils import (
-    TRANSACTION_SOURCE_ROUTE,
     AnnotatedValue,
     capture_internal_exceptions,
     event_from_exception,
diff --git a/sentry_sdk/integrations/tornado.py b/sentry_sdk/integrations/tornado.py
index af048fb5..b4a639b1 100644
--- a/sentry_sdk/integrations/tornado.py
+++ b/sentry_sdk/integrations/tornado.py
@@ -3,7 +3,11 @@ import contextlib
 from inspect import iscoroutinefunction
 
 from sentry_sdk.hub import Hub, _should_send_default_pii
-from sentry_sdk.tracing import TRANSACTION_SOURCE_COMPONENT, Transaction
+from sentry_sdk.tracing import (
+    TRANSACTION_SOURCE_COMPONENT,
+    TRANSACTION_SOURCE_ROUTE,
+    Transaction,
+)
 from sentry_sdk.utils import (
     HAS_REAL_CONTEXTVARS,
     CONTEXTVARS_ERROR_MESSAGE,
@@ -116,6 +120,7 @@ def _handle_request_impl(self):
             # sentry_urldispatcher_resolve is responsible for
             # setting a transaction name later.
             name="generic Tornado request",
+            source=TRANSACTION_SOURCE_ROUTE,
         )
 
         with hub.start_transaction(
diff --git a/sentry_sdk/integrations/wsgi.py b/sentry_sdk/integrations/wsgi.py
index 32bba51c..214aea41 100644
--- a/sentry_sdk/integrations/wsgi.py
+++ b/sentry_sdk/integrations/wsgi.py
@@ -8,7 +8,7 @@ from sentry_sdk.utils import (
     event_from_exception,
 )
 from sentry_sdk._compat import PY2, reraise, iteritems
-from sentry_sdk.tracing import Transaction
+from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_ROUTE
 from sentry_sdk.sessions import auto_session_tracking
 from sentry_sdk.integrations._wsgi_common import _filter_headers
 from sentry_sdk.profiler import profiling
@@ -123,7 +123,10 @@ class SentryWsgiMiddleware(object):
                             )
 
                     transaction = Transaction.continue_from_environ(
-                        environ, op="http.server", name="generic WSGI request"
+                        environ,
+                        op="http.server",
+                        name="generic WSGI request",
+                        source=TRANSACTION_SOURCE_ROUTE,
                     )
 
                     with hub.start_transaction(
diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py
index fa95b6ec..e291d2f0 100644
--- a/sentry_sdk/tracing.py
+++ b/sentry_sdk/tracing.py
@@ -34,7 +34,6 @@ TRANSACTION_SOURCE_ROUTE = "route"
 TRANSACTION_SOURCE_VIEW = "view"
 TRANSACTION_SOURCE_COMPONENT = "component"
 TRANSACTION_SOURCE_TASK = "task"
-TRANSACTION_SOURCE_UNKNOWN = "unknown"
 
 SOURCE_FOR_STYLE = {
     "endpoint": TRANSACTION_SOURCE_COMPONENT,
@@ -547,7 +546,7 @@ class Transaction(Span):
         sentry_tracestate=None,  # type: Optional[str]
         third_party_tracestate=None,  # type: Optional[str]
         baggage=None,  # type: Optional[Baggage]
-        source=TRANSACTION_SOURCE_UNKNOWN,  # type: str
+        source=TRANSACTION_SOURCE_CUSTOM,  # type: str
         **kwargs  # type: Any
     ):
         # type: (...) -> None
diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py
index 6307e6b6..ccac6e37 100644
--- a/sentry_sdk/utils.py
+++ b/sentry_sdk/utils.py
@@ -42,16 +42,6 @@ logger = logging.getLogger("sentry_sdk.errors")
 MAX_STRING_LENGTH = 512
 BASE64_ALPHABET = re.compile(r"^[a-zA-Z0-9/+=]*$")
 
-# Transaction source
-# see https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
-TRANSACTION_SOURCE_CUSTOM = "custom"
-TRANSACTION_SOURCE_URL = "url"
-TRANSACTION_SOURCE_ROUTE = "route"
-TRANSACTION_SOURCE_VIEW = "view"
-TRANSACTION_SOURCE_COMPONENT = "component"
-TRANSACTION_SOURCE_TASK = "task"
-TRANSACTION_SOURCE_UNKNOWN = "unknown"
-
 
 def json_dumps(data):
     # type: (Any) -> bytes


Test patch:
diff --git a/tests/integrations/celery/test_celery.py b/tests/integrations/celery/test_celery.py
index f72b896f..2c520317 100644
--- a/tests/integrations/celery/test_celery.py
+++ b/tests/integrations/celery/test_celery.py
@@ -159,7 +159,7 @@ def test_transaction_events(capture_events, init_celery, celery_invocation, task
     assert execution_event["transaction_info"] == {"source": "task"}
 
     assert submission_event["transaction"] == "submission"
-    assert submission_event["transaction_info"] == {"source": "unknown"}
+    assert submission_event["transaction_info"] == {"source": "custom"}
 
     assert execution_event["type"] == submission_event["type"] == "transaction"
     assert execution_event["contexts"]["trace"]["trace_id"] == transaction.trace_id
diff --git a/tests/integrations/tornado/test_tornado.py b/tests/integrations/tornado/test_tornado.py
index f59781dc..c0dac2d9 100644
--- a/tests/integrations/tornado/test_tornado.py
+++ b/tests/integrations/tornado/test_tornado.py
@@ -131,7 +131,7 @@ def test_transactions(tornado_testcase, sentry_init, capture_events, handler, co
     assert client_tx["type"] == "transaction"
     assert client_tx["transaction"] == "client"
     assert client_tx["transaction_info"] == {
-        "source": "unknown"
+        "source": "custom"
     }  # because this is just the start_transaction() above.
 
     if server_error is not None:
diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py
index 80a8ba7a..fbaf07d5 100644
--- a/tests/tracing/test_integration_tests.py
+++ b/tests/tracing/test_integration_tests.py
@@ -32,6 +32,9 @@ def test_basic(sentry_init, capture_events, sample_rate):
         assert len(events) == 1
         event = events[0]
 
+        assert event["transaction"] == "hi"
+        assert event["transaction_info"]["source"] == "custom"
+
         span1, span2 = event["spans"]
         parent_span = event
         assert span1["tags"]["status"] == "internal_error"