mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-08-03 04:10:48 +08:00
Django: Capture custom request/response headers (#1024)
This commit is contained in:
@ -43,7 +43,12 @@ from opentelemetry.trace import (
|
||||
format_span_id,
|
||||
format_trace_id,
|
||||
)
|
||||
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
|
||||
from opentelemetry.util.http import (
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
|
||||
get_excluded_urls,
|
||||
get_traced_request_attrs,
|
||||
)
|
||||
|
||||
# pylint: disable=import-error
|
||||
from .views import (
|
||||
@ -51,6 +56,7 @@ from .views import (
|
||||
excluded,
|
||||
excluded_noarg,
|
||||
excluded_noarg2,
|
||||
response_with_custom_header,
|
||||
route_span_name,
|
||||
traced,
|
||||
traced_template,
|
||||
@ -67,6 +73,7 @@ else:
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r"^traced/", traced),
|
||||
re_path(r"^traced_custom_header/", response_with_custom_header),
|
||||
re_path(r"^route/(?P<year>[0-9]{4})/template/$", traced_template),
|
||||
re_path(r"^error/", error),
|
||||
re_path(r"^excluded_arg/", excluded),
|
||||
@ -451,3 +458,107 @@ class TestMiddlewareWithTracerProvider(TestBase, WsgiTestBase):
|
||||
parent_span.get_span_context().span_id,
|
||||
span_list[0].parent.span_id,
|
||||
)
|
||||
|
||||
|
||||
class TestMiddlewareWsgiWithCustomHeaders(TestBase, WsgiTestBase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
conf.settings.configure(ROOT_URLCONF=modules[__name__])
|
||||
super().setUpClass()
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
setup_test_environment()
|
||||
tracer_provider, exporter = self.create_tracer_provider()
|
||||
self.exporter = exporter
|
||||
_django_instrumentor.instrument(tracer_provider=tracer_provider)
|
||||
self.env_patch = patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3",
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3",
|
||||
},
|
||||
)
|
||||
self.env_patch.start()
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
self.env_patch.stop()
|
||||
teardown_test_environment()
|
||||
_django_instrumentor.uninstrument()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super().tearDownClass()
|
||||
conf.settings = conf.LazySettings()
|
||||
|
||||
def test_http_custom_request_headers_in_span_attributes(self):
|
||||
expected = {
|
||||
"http.request.header.custom_test_header_1": (
|
||||
"test-header-value-1",
|
||||
),
|
||||
"http.request.header.custom_test_header_2": (
|
||||
"test-header-value-2",
|
||||
),
|
||||
}
|
||||
Client(
|
||||
HTTP_CUSTOM_TEST_HEADER_1="test-header-value-1",
|
||||
HTTP_CUSTOM_TEST_HEADER_2="test-header-value-2",
|
||||
).get("/traced/")
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
self.assertSpanHasAttributes(span, expected)
|
||||
self.memory_exporter.clear()
|
||||
|
||||
def test_http_custom_request_headers_not_in_span_attributes(self):
|
||||
not_expected = {
|
||||
"http.request.header.custom_test_header_2": (
|
||||
"test-header-value-2",
|
||||
),
|
||||
}
|
||||
Client(HTTP_CUSTOM_TEST_HEADER_1="test-header-value-1").get("/traced/")
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
for key, _ in not_expected.items():
|
||||
self.assertNotIn(key, span.attributes)
|
||||
self.memory_exporter.clear()
|
||||
|
||||
def test_http_custom_response_headers_in_span_attributes(self):
|
||||
expected = {
|
||||
"http.response.header.custom_test_header_1": (
|
||||
"test-header-value-1",
|
||||
),
|
||||
"http.response.header.custom_test_header_2": (
|
||||
"test-header-value-2",
|
||||
),
|
||||
}
|
||||
Client().get("/traced_custom_header/")
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
self.assertSpanHasAttributes(span, expected)
|
||||
self.memory_exporter.clear()
|
||||
|
||||
def test_http_custom_response_headers_not_in_span_attributes(self):
|
||||
not_expected = {
|
||||
"http.response.header.custom_test_header_3": (
|
||||
"test-header-value-3",
|
||||
),
|
||||
}
|
||||
Client().get("/traced_custom_header/")
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
for key, _ in not_expected.items():
|
||||
self.assertNotIn(key, span.attributes)
|
||||
self.memory_exporter.clear()
|
||||
|
@ -42,7 +42,12 @@ from opentelemetry.trace import (
|
||||
format_span_id,
|
||||
format_trace_id,
|
||||
)
|
||||
from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs
|
||||
from opentelemetry.util.http import (
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
|
||||
get_excluded_urls,
|
||||
get_traced_request_attrs,
|
||||
)
|
||||
|
||||
# pylint: disable=import-error
|
||||
from .views import (
|
||||
@ -53,6 +58,7 @@ from .views import (
|
||||
async_route_span_name,
|
||||
async_traced,
|
||||
async_traced_template,
|
||||
async_with_custom_header,
|
||||
)
|
||||
|
||||
DJANGO_2_0 = VERSION >= (2, 0)
|
||||
@ -65,6 +71,7 @@ else:
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r"^traced/", async_traced),
|
||||
re_path(r"^traced_custom_header/", async_with_custom_header),
|
||||
re_path(r"^route/(?P<year>[0-9]{4})/template/$", async_traced_template),
|
||||
re_path(r"^error/", async_error),
|
||||
re_path(r"^excluded_arg/", async_excluded),
|
||||
@ -415,3 +422,116 @@ class TestMiddlewareAsgiWithTracerProvider(SimpleTestCase, TestBase):
|
||||
self.assertEqual(
|
||||
span.resource.attributes["resource-key"], "resource-value"
|
||||
)
|
||||
|
||||
|
||||
class TestMiddlewareAsgiWithCustomHeaders(SimpleTestCase, TestBase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
conf.settings.configure(ROOT_URLCONF=modules[__name__])
|
||||
super().setUpClass()
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
setup_test_environment()
|
||||
|
||||
tracer_provider, exporter = self.create_tracer_provider()
|
||||
self.exporter = exporter
|
||||
_django_instrumentor.instrument(tracer_provider=tracer_provider)
|
||||
self.env_patch = patch.dict(
|
||||
"os.environ",
|
||||
{
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3",
|
||||
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3",
|
||||
},
|
||||
)
|
||||
self.env_patch.start()
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
self.env_patch.stop()
|
||||
teardown_test_environment()
|
||||
_django_instrumentor.uninstrument()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super().tearDownClass()
|
||||
conf.settings = conf.LazySettings()
|
||||
|
||||
async def test_http_custom_request_headers_in_span_attributes(self):
|
||||
expected = {
|
||||
"http.request.header.custom_test_header_1": (
|
||||
"test-header-value-1",
|
||||
),
|
||||
"http.request.header.custom_test_header_2": (
|
||||
"test-header-value-2",
|
||||
),
|
||||
}
|
||||
await self.async_client.get(
|
||||
"/traced/",
|
||||
**{
|
||||
"custom-test-header-1": "test-header-value-1",
|
||||
"custom-test-header-2": "test-header-value-2",
|
||||
},
|
||||
)
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
self.assertSpanHasAttributes(span, expected)
|
||||
self.memory_exporter.clear()
|
||||
|
||||
async def test_http_custom_request_headers_not_in_span_attributes(self):
|
||||
not_expected = {
|
||||
"http.request.header.custom_test_header_2": (
|
||||
"test-header-value-2",
|
||||
),
|
||||
}
|
||||
await self.async_client.get(
|
||||
"/traced/",
|
||||
**{
|
||||
"custom-test-header-1": "test-header-value-1",
|
||||
},
|
||||
)
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
for key, _ in not_expected.items():
|
||||
self.assertNotIn(key, span.attributes)
|
||||
self.memory_exporter.clear()
|
||||
|
||||
async def test_http_custom_response_headers_in_span_attributes(self):
|
||||
expected = {
|
||||
"http.response.header.custom_test_header_1": (
|
||||
"test-header-value-1",
|
||||
),
|
||||
"http.response.header.custom_test_header_2": (
|
||||
"test-header-value-2",
|
||||
),
|
||||
}
|
||||
await self.async_client.get("/traced_custom_header/")
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
self.assertSpanHasAttributes(span, expected)
|
||||
self.memory_exporter.clear()
|
||||
|
||||
async def test_http_custom_response_headers_not_in_span_attributes(self):
|
||||
not_expected = {
|
||||
"http.response.header.custom_test_header_3": (
|
||||
"test-header-value-3",
|
||||
),
|
||||
}
|
||||
await self.async_client.get("/traced_custom_header/")
|
||||
spans = self.exporter.get_finished_spans()
|
||||
self.assertEqual(len(spans), 1)
|
||||
|
||||
span = spans[0]
|
||||
self.assertEqual(span.kind, SpanKind.SERVER)
|
||||
for key, _ in not_expected.items():
|
||||
self.assertNotIn(key, span.attributes)
|
||||
self.memory_exporter.clear()
|
||||
|
@ -31,6 +31,13 @@ def route_span_name(
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
def response_with_custom_header(request):
|
||||
response = HttpResponse()
|
||||
response["custom-test-header-1"] = "test-header-value-1"
|
||||
response["custom-test-header-2"] = "test-header-value-2"
|
||||
return response
|
||||
|
||||
|
||||
async def async_traced(request): # pylint: disable=unused-argument
|
||||
return HttpResponse()
|
||||
|
||||
@ -61,3 +68,10 @@ async def async_route_span_name(
|
||||
request, *args, **kwargs
|
||||
): # pylint: disable=unused-argument
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
async def async_with_custom_header(request):
|
||||
response = HttpResponse()
|
||||
response.headers["custom-test-header-1"] = "test-header-value-1"
|
||||
response.headers["custom-test-header-2"] = "test-header-value-2"
|
||||
return response
|
||||
|
Reference in New Issue
Block a user