Skip to content

Commit

Permalink
Django: Record status and http.status_code on exception
Browse files Browse the repository at this point in the history
  • Loading branch information
owais committed Oct 19, 2020
1 parent 5fc08ad commit 722fbc4
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@
from opentelemetry.configuration import Configuration
from opentelemetry.context import attach, detach
from opentelemetry.instrumentation.django.version import __version__
from opentelemetry.instrumentation.utils import extract_attributes_from_object
from opentelemetry.instrumentation.utils import (
extract_attributes_from_object,
http_status_to_canonical_code,
)
from opentelemetry.instrumentation.wsgi import (
add_response_attributes,
collect_request_attributes,
get_header_from_environ,
)
from opentelemetry.propagators import extract
from opentelemetry.trace import SpanKind, get_tracer
from opentelemetry.trace.status import Status
from opentelemetry.util import ExcludeList

try:
Expand Down Expand Up @@ -111,6 +115,18 @@ def _get_metric_labels_from_attributes(attributes):
labels["http.flavor"] = attributes.get("http.flavor")
return labels

@staticmethod
def _record_request_metrics(request):
try:
metric_recorder = getattr(settings, "OTEL_METRIC_RECORDER", None)
if metric_recorder is not None:
# pylint:disable=W0212
metric_recorder.record_server_duration_range(
request._otel_start_time, time.time(), request._otel_labels
)
except Exception as ex: # pylint: disable=W0703
_logger.warning("Error recording duration metrics: %s", ex)

def process_request(self, request):
# request.META is a dictionary containing all available HTTP headers
# Read more about request.META here:
Expand Down Expand Up @@ -183,16 +199,34 @@ def process_exception(self, request, exception):
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
return

status_code = 500
# pylint:disable=W0212
request._otel_labels["http.status_code"] = str(status_code)

if self._environ_activation_key in request.META.keys():
# pylint:disable=W0212
span = request.META.get(self._environ_span_key, None)
if span and span.is_recording():
span.set_attribute("http.status_code", status_code)
span.set_status(
Status(
canonical_code=http_status_to_canonical_code(
status_code
),
description="{}: {}".format(
exception.__class__.__name__, exception
),
)
)
request.META[self._environ_activation_key].__exit__(
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)
self._record_request_metrics(request)

def process_response(self, request, response):
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
Expand Down Expand Up @@ -222,14 +256,5 @@ def process_response(self, request, response):
detach(request.environ.get(self._environ_token))
request.META.pop(self._environ_token)

try:
metric_recorder = getattr(settings, "OTEL_METRIC_RECORDER", None)
if metric_recorder is not None:
# pylint:disable=W0212
metric_recorder.record_server_duration_range(
request._otel_start_time, time.time(), request._otel_labels
)
except Exception as ex: # pylint: disable=W0703
_logger.warning("Error recording duration metrics: %s", ex)

self._record_request_metrics(request)
return response
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,15 @@ def test_error(self):
)
self.assertEqual(span.kind, SpanKind.SERVER)
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.url"], "http://testserver/error/"
)
self.assertEqual(span.attributes["http.route"], "^error/")
self.assertEqual(span.attributes["http.scheme"], "http")
self.assertEqual(span.attributes["http.status_code"], 500)
self.assertIsNotNone(_django_instrumentor.meter)
self.assertEqual(len(_django_instrumentor.meter.metrics), 1)
recorder = _django_instrumentor.meter.metrics.pop()
Expand All @@ -210,6 +211,7 @@ def test_error(self):
"http.flavor": "1.1",
"http.method": "GET",
"http.url": "http://testserver/error/",
"http.status_code": 500,
}
)
for key in recorder.bound_instruments.keys():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Record span status and http.status_code attribute on exception
([#1257](https://github.com/open-telemetry/opentelemetry-python/pull/1257))

## Version 0.13b0

Released 2020-09-17
Expand Down

0 comments on commit 722fbc4

Please sign in to comment.