Repository: getsentry/sentry-python

Issue:
Don't record spans for internal SDK requests to the DSN
### How do you use Sentry?

Sentry Saas (sentry.io)

### Version

1.25.1

### Steps to Reproduce

```python
import sentry_sdk

sentry_sdk.init(traces_sample_rate=1.0, debug=True)

# for i in range(1000):
with sentry_sdk.start_transaction(name='parent transaction'):
    with sentry_sdk.start_span(op='span wrapper', description='foobar'):
        for i in range(100):
            with sentry_sdk.start_transaction(name='child transaction'):
                for i in range(1050):
                    with sentry_sdk.start_span(op='sleep', description='zzz'):
                        2**10

sentry_sdk.flush(10)
```

### Expected Result

no internal http spans

### Actual Result

![image](https://github.com/getsentry/sentry-python/assets/6536764/18fc5a0b-a345-4806-b3ad-1aaa22a6002f)


Discussion:

Patch:
diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py
index 02006e94..7479f462 100644
--- a/sentry_sdk/client.py
+++ b/sentry_sdk/client.py
@@ -581,6 +581,17 @@ class _Client(object):
 
         return event_id
 
+    def is_sentry_url(self, url):
+        # type: (str) -> bool
+        """
+        Determines whether the given URL matches the Sentry DSN.
+        """
+        return (
+            self.transport is not None
+            and self.transport.parsed_dsn is not None
+            and self.transport.parsed_dsn.netloc in url
+        )
+
     def capture_session(
         self, session  # type: Session
     ):
diff --git a/sentry_sdk/hub.py b/sentry_sdk/hub.py
index ac77fb42..70784638 100644
--- a/sentry_sdk/hub.py
+++ b/sentry_sdk/hub.py
@@ -837,6 +837,10 @@ class Hub(with_metaclass(HubMeta)):  # type: ignore
 
         return meta
 
+    def is_sentry_url(self, url):
+        # type: (str) -> bool
+        return self.client is not None and self.client.is_sentry_url(url)
+
 
 GLOBAL_HUB = Hub()
 _local.set(GLOBAL_HUB)
diff --git a/sentry_sdk/integrations/stdlib.py b/sentry_sdk/integrations/stdlib.py
index be02779d..f6db43c5 100644
--- a/sentry_sdk/integrations/stdlib.py
+++ b/sentry_sdk/integrations/stdlib.py
@@ -69,13 +69,14 @@ def _install_httplib():
     def putrequest(self, method, url, *args, **kwargs):
         # type: (HTTPConnection, str, str, *Any, **Any) -> Any
         hub = Hub.current
-        if hub.get_integration(StdlibIntegration) is None:
-            return real_putrequest(self, method, url, *args, **kwargs)
 
         host = self.host
         port = self.port
         default_port = self.default_port
 
+        if hub.get_integration(StdlibIntegration) is None or hub.is_sentry_url(host):
+            return real_putrequest(self, method, url, *args, **kwargs)
+
         real_url = url
         if real_url is None or not real_url.startswith(("http://", "https://")):
             real_url = "%s://%s%s%s" % (
diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py
index eb0d0e78..9906f18b 100644
--- a/sentry_sdk/tracing_utils.py
+++ b/sentry_sdk/tracing_utils.py
@@ -377,13 +377,7 @@ def should_propagate_trace(hub, url):
     client = hub.client  # type: Any
     trace_propagation_targets = client.options["trace_propagation_targets"]
 
-    if client.transport and client.transport.parsed_dsn:
-        dsn_url = client.transport.parsed_dsn.netloc
-    else:
-        dsn_url = None
-
-    is_request_to_sentry = dsn_url and dsn_url in url
-    if is_request_to_sentry:
+    if hub.is_sentry_url(url):
         return False
 
     return match_regex_list(url, trace_propagation_targets, substring_matching=True)


Test patch:
diff --git a/tests/integrations/stdlib/test_httplib.py b/tests/integrations/stdlib/test_httplib.py
index e40f5222..8072bf27 100644
--- a/tests/integrations/stdlib/test_httplib.py
+++ b/tests/integrations/stdlib/test_httplib.py
@@ -84,7 +84,7 @@ def test_crumb_capture_hint(sentry_init, capture_events):
     }
 
 
-def test_empty_realurl(sentry_init, capture_events):
+def test_empty_realurl(sentry_init):
     """
     Ensure that after using sentry_sdk.init you can putrequest a
     None url.
diff --git a/tests/test_client.py b/tests/test_client.py
index 83257ab2..3213da69 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -1136,3 +1136,31 @@ def test_max_value_length_option(
     capture_message("a" * 2000)
 
     assert len(events[0]["message"]) == expected_data_length
+
+
+def test_is_sentry_url_true():
+    client = Client(dsn="https://asdf@abcd1234.ingest.sentry.io/123456789")
+    test_url = "abcd1234.ingest.sentry.io"
+
+    is_sentry_url = client.is_sentry_url(test_url)
+
+    assert is_sentry_url
+
+
+def test_is_sentry_url_false():
+    client = Client(dsn="https://asdf@abcd1234.ingest.sentry.io/123456789")
+    test_url = "abcd1234.mywebsite.com"
+
+    is_sentry_url = client.is_sentry_url(test_url)
+
+    assert not is_sentry_url
+
+
+def test_is_sentry_url_no_transport():
+    client = Client()
+    client.transport = None
+    test_url = "abcd1234.mywebsite.com"
+
+    is_sentry_url = client.is_sentry_url(test_url)
+
+    assert not is_sentry_url
diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py
index 49b1f530..c17110b1 100644
--- a/tests/tracing/test_misc.py
+++ b/tests/tracing/test_misc.py
@@ -305,6 +305,10 @@ def test_should_propagate_trace(
 ):
     hub = MagicMock()
     hub.client = MagicMock()
+
+    # This test assumes the urls are not Sentry URLs. Use test_should_propogate_trace_to_sentry for sentry URLs.
+    hub.is_sentry_url = lambda _: False
+
     hub.client.options = {"trace_propagation_targets": trace_propagation_targets}
     hub.client.transport = MagicMock()
     hub.client.transport.parsed_dsn = Dsn("https://bla@xxx.sentry.io/12312012")