mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-31 14:11:50 +08:00
Django: Record status, http.status_code and event on exception (#1257)
This commit is contained in:
@ -60,6 +60,7 @@ class _DjangoMiddleware(MiddlewareMixin):
|
|||||||
)
|
)
|
||||||
_environ_token = "opentelemetry-instrumentor-django.token"
|
_environ_token = "opentelemetry-instrumentor-django.token"
|
||||||
_environ_span_key = "opentelemetry-instrumentor-django.span_key"
|
_environ_span_key = "opentelemetry-instrumentor-django.span_key"
|
||||||
|
_environ_exception_key = "opentelemetry-instrumentor-django.exception_key"
|
||||||
|
|
||||||
_excluded_urls = Configuration().DJANGO_EXCLUDED_URLS or []
|
_excluded_urls = Configuration().DJANGO_EXCLUDED_URLS or []
|
||||||
if _excluded_urls:
|
if _excluded_urls:
|
||||||
@ -177,22 +178,11 @@ class _DjangoMiddleware(MiddlewareMixin):
|
|||||||
span.set_attribute("http.route", route)
|
span.set_attribute("http.route", route)
|
||||||
|
|
||||||
def process_exception(self, request, exception):
|
def process_exception(self, request, exception):
|
||||||
# Django can call this method and process_response later. In order
|
|
||||||
# to avoid __exit__ and detach from being called twice then, the
|
|
||||||
# respective keys are being removed here.
|
|
||||||
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
|
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._environ_activation_key in request.META.keys():
|
if self._environ_activation_key in request.META.keys():
|
||||||
request.META[self._environ_activation_key].__exit__(
|
request.META[self._environ_exception_key] = exception
|
||||||
type(exception),
|
|
||||||
exception,
|
|
||||||
getattr(exception, "__traceback__", None),
|
|
||||||
)
|
|
||||||
request.META.pop(self._environ_activation_key)
|
|
||||||
|
|
||||||
detach(request.environ[self._environ_token])
|
|
||||||
request.META.pop(self._environ_token, None)
|
|
||||||
|
|
||||||
def process_response(self, request, response):
|
def process_response(self, request, response):
|
||||||
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
|
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
|
||||||
@ -213,6 +203,14 @@ class _DjangoMiddleware(MiddlewareMixin):
|
|||||||
)
|
)
|
||||||
request.META.pop(self._environ_span_key)
|
request.META.pop(self._environ_span_key)
|
||||||
|
|
||||||
|
exception = request.META.pop(self._environ_exception_key, None)
|
||||||
|
if exception:
|
||||||
|
request.META[self._environ_activation_key].__exit__(
|
||||||
|
type(exception),
|
||||||
|
exception,
|
||||||
|
getattr(exception, "__traceback__", None),
|
||||||
|
)
|
||||||
|
else:
|
||||||
request.META[self._environ_activation_key].__exit__(
|
request.META[self._environ_activation_key].__exit__(
|
||||||
None, None, None
|
None, None, None
|
||||||
)
|
)
|
||||||
@ -231,5 +229,4 @@ class _DjangoMiddleware(MiddlewareMixin):
|
|||||||
)
|
)
|
||||||
except Exception as ex: # pylint: disable=W0703
|
except Exception as ex: # pylint: disable=W0703
|
||||||
_logger.warning("Error recording duration metrics: %s", ex)
|
_logger.warning("Error recording duration metrics: %s", ex)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@ -194,7 +194,7 @@ class TestMiddleware(TestBase, WsgiTestBase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
span.status.canonical_code, StatusCanonicalCode.UNKNOWN
|
span.status.canonical_code, StatusCanonicalCode.INTERNAL
|
||||||
)
|
)
|
||||||
self.assertEqual(span.attributes["http.method"], "GET")
|
self.assertEqual(span.attributes["http.method"], "GET")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@ -202,13 +202,22 @@ class TestMiddleware(TestBase, WsgiTestBase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(span.attributes["http.route"], "^error/")
|
self.assertEqual(span.attributes["http.route"], "^error/")
|
||||||
self.assertEqual(span.attributes["http.scheme"], "http")
|
self.assertEqual(span.attributes["http.scheme"], "http")
|
||||||
|
self.assertEqual(span.attributes["http.status_code"], 500)
|
||||||
self.assertIsNotNone(_django_instrumentor.meter)
|
self.assertIsNotNone(_django_instrumentor.meter)
|
||||||
self.assertEqual(len(_django_instrumentor.meter.metrics), 1)
|
self.assertEqual(len(_django_instrumentor.meter.metrics), 1)
|
||||||
|
|
||||||
|
self.assertEqual(len(span.events), 1)
|
||||||
|
event = span.events[0]
|
||||||
|
self.assertEqual(event.name, "exception")
|
||||||
|
self.assertEqual(event.attributes["exception.type"], "ValueError")
|
||||||
|
self.assertEqual(event.attributes["exception.message"], "error")
|
||||||
|
|
||||||
recorder = _django_instrumentor.meter.metrics.pop()
|
recorder = _django_instrumentor.meter.metrics.pop()
|
||||||
match_key = get_dict_as_key(
|
match_key = get_dict_as_key(
|
||||||
{
|
{
|
||||||
"http.flavor": "1.1",
|
"http.flavor": "1.1",
|
||||||
"http.method": "GET",
|
"http.method": "GET",
|
||||||
|
"http.status_code": "500",
|
||||||
"http.url": "http://testserver/error/",
|
"http.url": "http://testserver/error/",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user