mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-08-02 02:52:18 +08:00
Django span names according to convention (#992)
This commit is contained in:
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Changed span name extraction from request to comply semantic convention ([#992](https://github.com/open-telemetry/opentelemetry-python/pull/992))
|
||||||
|
|
||||||
## Version 0.13b0
|
## Version 0.13b0
|
||||||
|
|
||||||
Released 2020-09-17
|
Released 2020-09-17
|
||||||
|
@ -26,6 +26,14 @@ from opentelemetry.propagators import extract
|
|||||||
from opentelemetry.trace import SpanKind, get_tracer
|
from opentelemetry.trace import SpanKind, get_tracer
|
||||||
from opentelemetry.util import ExcludeList
|
from opentelemetry.util import ExcludeList
|
||||||
|
|
||||||
|
try:
|
||||||
|
from django.core.urlresolvers import ( # pylint: disable=no-name-in-module
|
||||||
|
resolve,
|
||||||
|
Resolver404,
|
||||||
|
)
|
||||||
|
except ImportError:
|
||||||
|
from django.urls import resolve, Resolver404
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -50,17 +58,33 @@ class _DjangoMiddleware(MiddlewareMixin):
|
|||||||
else:
|
else:
|
||||||
_excluded_urls = ExcludeList(_excluded_urls)
|
_excluded_urls = ExcludeList(_excluded_urls)
|
||||||
|
|
||||||
def process_view(
|
@staticmethod
|
||||||
self, request, view_func, view_args, view_kwargs
|
def _get_span_name(request):
|
||||||
): # pylint: disable=unused-argument
|
try:
|
||||||
|
if getattr(request, "resolver_match"):
|
||||||
|
match = request.resolver_match
|
||||||
|
else:
|
||||||
|
match = resolve(request.get_full_path())
|
||||||
|
|
||||||
|
if hasattr(match, "route"):
|
||||||
|
return match.route
|
||||||
|
|
||||||
|
# Instead of using `view_name`, better to use `_func_name` as some applications can use similar
|
||||||
|
# view names in different modules
|
||||||
|
if hasattr(match, "_func_name"):
|
||||||
|
return match._func_name # pylint: disable=protected-access
|
||||||
|
|
||||||
|
# Fallback for safety as `_func_name` private field
|
||||||
|
return match.view_name
|
||||||
|
|
||||||
|
except Resolver404:
|
||||||
|
return "HTTP {}".format(request.method)
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
# request.META is a dictionary containing all available HTTP headers
|
# request.META is a dictionary containing all available HTTP headers
|
||||||
# Read more about request.META here:
|
# Read more about request.META here:
|
||||||
# https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.META
|
# https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.META
|
||||||
|
|
||||||
# environ = {
|
|
||||||
# key.lower().replace('_', '-').replace("http-", "", 1): value
|
|
||||||
# for key, value in request.META.items()
|
|
||||||
# }
|
|
||||||
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
|
if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -73,7 +97,7 @@ class _DjangoMiddleware(MiddlewareMixin):
|
|||||||
attributes = collect_request_attributes(environ)
|
attributes = collect_request_attributes(environ)
|
||||||
|
|
||||||
span = tracer.start_span(
|
span = tracer.start_span(
|
||||||
view_func.__name__,
|
self._get_span_name(request),
|
||||||
kind=SpanKind.SERVER,
|
kind=SpanKind.SERVER,
|
||||||
attributes=attributes,
|
attributes=attributes,
|
||||||
start_time=environ.get(
|
start_time=environ.get(
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
from sys import modules
|
from sys import modules
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from django import VERSION
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.test import Client
|
from django.test import Client
|
||||||
@ -28,7 +29,16 @@ from opentelemetry.trace.status import StatusCanonicalCode
|
|||||||
from opentelemetry.util import ExcludeList
|
from opentelemetry.util import ExcludeList
|
||||||
|
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
from .views import error, excluded, excluded_noarg, excluded_noarg2, traced
|
from .views import (
|
||||||
|
error,
|
||||||
|
excluded,
|
||||||
|
excluded_noarg,
|
||||||
|
excluded_noarg2,
|
||||||
|
route_span_name,
|
||||||
|
traced,
|
||||||
|
)
|
||||||
|
|
||||||
|
DJANGO_2_2 = VERSION >= (2, 2)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r"^traced/", traced),
|
url(r"^traced/", traced),
|
||||||
@ -36,6 +46,7 @@ urlpatterns = [
|
|||||||
url(r"^excluded_arg/", excluded),
|
url(r"^excluded_arg/", excluded),
|
||||||
url(r"^excluded_noarg/", excluded_noarg),
|
url(r"^excluded_noarg/", excluded_noarg),
|
||||||
url(r"^excluded_noarg2/", excluded_noarg2),
|
url(r"^excluded_noarg2/", excluded_noarg2),
|
||||||
|
url(r"^span_name/([0-9]{4})/$", route_span_name),
|
||||||
]
|
]
|
||||||
_django_instrumentor = DjangoInstrumentor()
|
_django_instrumentor = DjangoInstrumentor()
|
||||||
|
|
||||||
@ -65,7 +76,9 @@ class TestMiddleware(WsgiTestBase):
|
|||||||
|
|
||||||
span = spans[0]
|
span = spans[0]
|
||||||
|
|
||||||
self.assertEqual(span.name, "traced")
|
self.assertEqual(
|
||||||
|
span.name, "^traced/" if DJANGO_2_2 else "tests.views.traced"
|
||||||
|
)
|
||||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||||
self.assertEqual(span.status.canonical_code, StatusCanonicalCode.OK)
|
self.assertEqual(span.status.canonical_code, StatusCanonicalCode.OK)
|
||||||
self.assertEqual(span.attributes["http.method"], "GET")
|
self.assertEqual(span.attributes["http.method"], "GET")
|
||||||
@ -84,7 +97,9 @@ class TestMiddleware(WsgiTestBase):
|
|||||||
|
|
||||||
span = spans[0]
|
span = spans[0]
|
||||||
|
|
||||||
self.assertEqual(span.name, "traced")
|
self.assertEqual(
|
||||||
|
span.name, "^traced/" if DJANGO_2_2 else "tests.views.traced"
|
||||||
|
)
|
||||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||||
self.assertEqual(span.status.canonical_code, StatusCanonicalCode.OK)
|
self.assertEqual(span.status.canonical_code, StatusCanonicalCode.OK)
|
||||||
self.assertEqual(span.attributes["http.method"], "POST")
|
self.assertEqual(span.attributes["http.method"], "POST")
|
||||||
@ -104,7 +119,9 @@ class TestMiddleware(WsgiTestBase):
|
|||||||
|
|
||||||
span = spans[0]
|
span = spans[0]
|
||||||
|
|
||||||
self.assertEqual(span.name, "error")
|
self.assertEqual(
|
||||||
|
span.name, "^error/" if DJANGO_2_2 else "tests.views.error"
|
||||||
|
)
|
||||||
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.UNKNOWN
|
||||||
@ -136,3 +153,24 @@ class TestMiddleware(WsgiTestBase):
|
|||||||
client.get("/excluded_noarg2/")
|
client.get("/excluded_noarg2/")
|
||||||
span_list = self.memory_exporter.get_finished_spans()
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
self.assertEqual(len(span_list), 1)
|
self.assertEqual(len(span_list), 1)
|
||||||
|
|
||||||
|
def test_span_name(self):
|
||||||
|
Client().get("/span_name/1234/")
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 1)
|
||||||
|
|
||||||
|
span = span_list[0]
|
||||||
|
self.assertEqual(
|
||||||
|
span.name,
|
||||||
|
"^span_name/([0-9]{4})/$"
|
||||||
|
if DJANGO_2_2
|
||||||
|
else "tests.views.route_span_name",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_span_name_404(self):
|
||||||
|
Client().get("/span_name/1234567890/")
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 1)
|
||||||
|
|
||||||
|
span = span_list[0]
|
||||||
|
self.assertEqual(span.name, "HTTP GET")
|
||||||
|
@ -19,3 +19,9 @@ def excluded_noarg(request): # pylint: disable=unused-argument
|
|||||||
|
|
||||||
def excluded_noarg2(request): # pylint: disable=unused-argument
|
def excluded_noarg2(request): # pylint: disable=unused-argument
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
||||||
|
|
||||||
|
def route_span_name(
|
||||||
|
request, *args, **kwargs
|
||||||
|
): # pylint: disable=unused-argument
|
||||||
|
return HttpResponse()
|
||||||
|
Reference in New Issue
Block a user