Repository: scoutapp/scout_apm_python
Pull request #276 (2019-10-11 16:08:03)

Track urlconf on Django
Since Django supports changing it through `request.urlconf`, we should capture it, as it will indicate which version of a URL/view is in use.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e851ac4..04ee051 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,8 @@
   `"path"`
   ([PR #268](https://github.com/scoutapp/scout_apm_python/pull/268),
   [PR #269](https://github.com/scoutapp/scout_apm_python/pull/269)).
+- Track the `urlconf` on Django, for multi-domain support
+  ([PR #276](https://github.com/scoutapp/scout_apm_python/pull/276)).
 
 ### Fixed
 
diff --git a/src/scout_apm/django/middleware.py b/src/scout_apm/django/middleware.py
index cee806c..acb0347 100644
--- a/src/scout_apm/django/middleware.py
+++ b/src/scout_apm/django/middleware.py
@@ -1,6 +1,9 @@
 # coding=utf-8
 from __future__ import absolute_import, division, print_function, unicode_literals
 
+import django
+from django.conf import settings
+
 from scout_apm.core.config import ScoutConfig
 from scout_apm.core.tracked_request import TrackedRequest
 from scout_apm.core.web_requests import (
@@ -9,6 +12,11 @@ from scout_apm.core.web_requests import (
     track_request_queue_time,
 )
 
+if django.VERSION >= (2, 0):
+    from django.urls import get_urlconf
+else:
+    from django.core.urlresolvers import get_urlconf
+
 
 def get_operation_name(request):
     view_func = request.resolver_match.func
@@ -59,6 +67,8 @@ def track_request_view_data(request, tracked_request):
         except Exception:
             pass
 
+    tracked_request.tag("urlconf", get_urlconf(settings.ROOT_URLCONF))
+
 
 class MiddlewareTimingMiddleware(object):
     """


Test patch:
diff --git a/tests/integration/test_django.py b/tests/integration/test_django.py
index f524afe..8c9cea2 100644
--- a/tests/integration/test_django.py
+++ b/tests/integration/test_django.py
@@ -415,6 +415,53 @@ def test_old_style_username_exception(tracked_requests):
     assert "username" not in tracked_request.tags
 
 
+def urlconf_middleware(get_response):
+    def middleware(request):
+        sys.modules["tests.integration.django_app_second_copy"] = django_app
+        request.urlconf = "tests.integration.django_app_second_copy"
+        return get_response(request)
+
+    return middleware
+
+
+@skip_unless_new_style_middleware
+def test_urlconf(tracked_requests):
+    new_middleware = (
+        settings.MIDDLEWARE[:-1]
+        + [__name__ + ".urlconf_middleware"]
+        + settings.MIDDLEWARE[-1:]
+    )
+    with app_with_scout(MIDDLEWARE=new_middleware) as app:
+        response = TestApp(app).get("/hello/")
+
+    assert response.status_int == 200
+    assert len(tracked_requests) == 1
+    tracked_request = tracked_requests[0]
+    assert tracked_request.tags["urlconf"] == "tests.integration.django_app_second_copy"
+
+
+class UrlconfMiddleware(object):
+    def process_request(self, request):
+        sys.modules["tests.integration.django_app_second_copy"] = django_app
+        request.urlconf = "tests.integration.django_app_second_copy"
+
+
+@skip_unless_old_style_middleware
+def test_old_style_urlconf(tracked_requests):
+    new_middleware = (
+        settings.MIDDLEWARE_CLASSES[:-1]
+        + [__name__ + ".UrlconfMiddleware"]
+        + settings.MIDDLEWARE_CLASSES[-1:]
+    )
+    with app_with_scout(MIDDLEWARE_CLASSES=new_middleware) as app:
+        response = TestApp(app).get("/")
+
+    assert response.status_int == 200
+    assert len(tracked_requests) == 1
+    tracked_request = tracked_requests[0]
+    assert tracked_request.tags["urlconf"] == "tests.integration.django_app_second_copy"
+
+
 @parametrize_queue_time_header_name
 def test_queue_time(header_name, tracked_requests):
     # Not testing floats due to Python 2/3 rounding differences