diff --git a/CHANGELOG.md b/CHANGELOG.md index e68e8d736b..c3bf9df07e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `opentelemetry-instrumentation-urllib3` Add urllib3 instrumentation ([#299](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/299)) +- `opentelemetry-instrumentation-django` Add ASGI support + ([#391](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/391)) ## [0.19b0](https://github.com/open-telemetry/opentelemetry-python-contrib/releases/tag/v0.19b0) - 2021-03-26 diff --git a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py index 3fe15b5069..45ec91e75f 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -113,7 +113,7 @@ def get_host_port_url_tuple(scope): """ server = scope.get("server") or ["0.0.0.0", 80] port = server[1] - server_host = server[0] + (":" + str(port) if port != 80 else "") + server_host = server[0] + (":" + str(port) if str(port) != "80" else "") full_path = scope.get("root_path", "") + scope.get("path", "") http_url = scope.get("scheme", "http") + "://" + server_host + full_path return server_host, port, http_url diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py index 04d6149eb7..50243e34e6 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py @@ -51,6 +51,7 @@ collect_request_attributes as asgi_collect_request_attributes, set_status_code, ) + _is_asgi_supported = True except ImportError: asgi_getter = None @@ -201,11 +202,15 @@ def process_response(self, request, response): and self._environ_span_key in request.META.keys() ): if is_asgi_request: - set_status_code(request.META[self._environ_span_key], response.status_code) + set_status_code( + request.META[self._environ_span_key], response.status_code + ) else: add_response_attributes( request.META[self._environ_span_key], - "{} {}".format(response.status_code, response.reason_phrase), + "{} {}".format( + response.status_code, response.reason_phrase + ), response, ) diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py index 8a8ce8bd9c..ad15dac0a0 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py @@ -56,9 +56,10 @@ _django_instrumentor = DjangoInstrumentor() -@pytest.mark.skipif(not DJANGO_3_1, reason="AsyncClient implemented since Django 3.1") +@pytest.mark.skipif( + not DJANGO_3_1, reason="AsyncClient implemented since Django 3.1" +) class TestMiddlewareAsgi(SimpleTestCase, TestBase): - @classmethod def setUpClass(cls): super().setUpClass() @@ -110,7 +111,6 @@ def _remove_databases_failures(cls): # Disable databases. pass - @pytest.mark.skip(reason="TODO") async def test_templated_route_get(self): await self.async_client.get("/route/2020/template/") @@ -125,7 +125,7 @@ async def test_templated_route_get(self): self.assertEqual(span.attributes["http.method"], "GET") self.assertEqual( span.attributes["http.url"], - "http://testserver/route/2020/template/", + "http://127.0.0.1/route/2020/template/", ) self.assertEqual( span.attributes["http.route"], @@ -133,9 +133,9 @@ async def test_templated_route_get(self): ) self.assertEqual(span.attributes["http.scheme"], "http") self.assertEqual(span.attributes["http.status_code"], 200) - self.assertEqual(span.attributes["http.status_text"], "OK") + # TODO: Add http.status_text to ASGI instrumentation. + # self.assertEqual(span.attributes["http.status_text"], "OK") - @pytest.mark.skip(reason="TODO") async def test_traced_get(self): await self.async_client.get("/traced/") @@ -149,12 +149,13 @@ async def test_traced_get(self): self.assertEqual(span.status.status_code, StatusCode.UNSET) self.assertEqual(span.attributes["http.method"], "GET") self.assertEqual( - span.attributes["http.url"], "http://testserver/traced/" + span.attributes["http.url"], "http://127.0.0.1/traced/" ) self.assertEqual(span.attributes["http.route"], "^traced/") self.assertEqual(span.attributes["http.scheme"], "http") self.assertEqual(span.attributes["http.status_code"], 200) - self.assertEqual(span.attributes["http.status_text"], "OK") + # TODO: Add http.status_text to ASGI instrumentation. + # self.assertEqual(span.attributes["http.status_text"], "OK") async def test_not_recording(self): mock_tracer = Mock() @@ -169,7 +170,6 @@ async def test_not_recording(self): self.assertFalse(mock_span.set_attribute.called) self.assertFalse(mock_span.set_status.called) - @pytest.mark.skip(reason="TODO") async def test_traced_post(self): await self.async_client.post("/traced/") @@ -183,14 +183,14 @@ async def test_traced_post(self): self.assertEqual(span.status.status_code, StatusCode.UNSET) self.assertEqual(span.attributes["http.method"], "POST") self.assertEqual( - span.attributes["http.url"], "http://testserver/traced/" + span.attributes["http.url"], "http://127.0.0.1/traced/" ) self.assertEqual(span.attributes["http.route"], "^traced/") self.assertEqual(span.attributes["http.scheme"], "http") self.assertEqual(span.attributes["http.status_code"], 200) - self.assertEqual(span.attributes["http.status_text"], "OK") + # TODO: Add http.status_text to ASGI instrumentation. + # self.assertEqual(span.attributes["http.status_text"], "OK") - @pytest.mark.skip(reason="TODO") async def test_error(self): with self.assertRaises(ValueError): await self.async_client.get("/error/") @@ -205,7 +205,7 @@ async def test_error(self): self.assertEqual(span.status.status_code, StatusCode.ERROR) self.assertEqual(span.attributes["http.method"], "GET") self.assertEqual( - span.attributes["http.url"], "http://testserver/error/" + span.attributes["http.url"], "http://127.0.0.1/error/" ) self.assertEqual(span.attributes["http.route"], "^error/") self.assertEqual(span.attributes["http.scheme"], "http") @@ -262,7 +262,7 @@ async def test_span_name_404(self): span = span_list[0] self.assertEqual(span.name, "HTTP GET") - @pytest.mark.skip(reason="TODO") + @pytest.mark.skip(reason="TODO: Traced request attributes not supported yet.") async def test_traced_request_attrs(self): await self.async_client.get("/span_name/1234/", CONTENT_TYPE="test/ct") span_list = self.memory_exporter.get_finished_spans() diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/views.py b/instrumentation/opentelemetry-instrumentation-django/tests/views.py index 82220717ce..0bcc7e95be 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/views.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/views.py @@ -35,7 +35,9 @@ async def async_traced(request): # pylint: disable=unused-argument return HttpResponse() -async def async_traced_template(request, year): # pylint: disable=unused-argument +async def async_traced_template( + request, year +): # pylint: disable=unused-argument return HttpResponse()