mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-08-01 09:13:23 +08:00
FastAPI: capture custom request response headers in span attributes (#1032)
This commit is contained in:
@ -15,7 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
([#999])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/999)
|
([#999])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/999)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- `opentelemetry-instrumentation-fastapi` Capture custom request/response headers in span attributes
|
||||||
|
([#1032])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1032)
|
||||||
- `opentelemetry-instrumentation-django` Capture custom request/response headers in span attributes
|
- `opentelemetry-instrumentation-django` Capture custom request/response headers in span attributes
|
||||||
([#1024])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1024)
|
([#1024])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1024)
|
||||||
- `opentelemetry-instrumentation-asgi` Capture custom request/response headers in span attributes
|
- `opentelemetry-instrumentation-asgi` Capture custom request/response headers in span attributes
|
||||||
|
@ -91,6 +91,57 @@ The client response hook is called with the internal span and an ASGI event whic
|
|||||||
|
|
||||||
OpenTelemetryMiddleware().(application, server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook)
|
OpenTelemetryMiddleware().(application, server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook)
|
||||||
|
|
||||||
|
Capture HTTP request and response headers
|
||||||
|
*****************************************
|
||||||
|
You can configure the agent to capture predefined HTTP headers as span attributes, according to the `semantic convention <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-request-and-response-headers>`_.
|
||||||
|
|
||||||
|
Request headers
|
||||||
|
***************
|
||||||
|
To capture predefined HTTP request headers as span attributes, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST``
|
||||||
|
to a comma-separated list of HTTP header names.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST="content-type,custom_request_header"
|
||||||
|
|
||||||
|
will extract ``content-type`` and ``custom_request_header`` from request headers and add them as span attributes.
|
||||||
|
|
||||||
|
It is recommended that you should give the correct names of the headers to be captured in the environment variable.
|
||||||
|
Request header names in ASGI are case insensitive. So, giving header name as ``CUStom-Header`` in environment variable will be able capture header with name ``custom-header``.
|
||||||
|
|
||||||
|
The name of the added span attribute will follow the format ``http.request.header.<header_name>`` where ``<header_name>`` being the normalized HTTP header name (lowercase, with - characters replaced by _ ).
|
||||||
|
The value of the attribute will be single item list containing all the header values.
|
||||||
|
|
||||||
|
Example of the added span attribute,
|
||||||
|
``http.request.header.custom_request_header = ["<value1>,<value2>"]``
|
||||||
|
|
||||||
|
Response headers
|
||||||
|
****************
|
||||||
|
To capture predefined HTTP response headers as span attributes, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE``
|
||||||
|
to a comma-separated list of HTTP header names.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE="content-type,custom_response_header"
|
||||||
|
|
||||||
|
will extract ``content-type`` and ``custom_response_header`` from response headers and add them as span attributes.
|
||||||
|
|
||||||
|
It is recommended that you should give the correct names of the headers to be captured in the environment variable.
|
||||||
|
Response header names captured in ASGI are case insensitive. So, giving header name as ``CUStomHeader`` in environment variable will be able capture header with name ``customheader``.
|
||||||
|
|
||||||
|
The name of the added span attribute will follow the format ``http.response.header.<header_name>`` where ``<header_name>`` being the normalized HTTP header name (lowercase, with - characters replaced by _ ).
|
||||||
|
The value of the attribute will be single item list containing all the header values.
|
||||||
|
|
||||||
|
Example of the added span attribute,
|
||||||
|
``http.response.header.custom_response_header = ["<value1>,<value2>"]``
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Environment variable names to caputre http headers are still experimental, and thus are subject to change.
|
||||||
|
|
||||||
API
|
API
|
||||||
---
|
---
|
||||||
"""
|
"""
|
||||||
|
@ -74,6 +74,58 @@ The client response hook is called with the internal span and an ASGI event whic
|
|||||||
|
|
||||||
FastAPIInstrumentor().instrument(server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook)
|
FastAPIInstrumentor().instrument(server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook)
|
||||||
|
|
||||||
|
|
||||||
|
Capture HTTP request and response headers
|
||||||
|
*****************************************
|
||||||
|
You can configure the agent to capture predefined HTTP headers as span attributes, according to the `semantic convention <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-request-and-response-headers>`_.
|
||||||
|
|
||||||
|
Request headers
|
||||||
|
***************
|
||||||
|
To capture predefined HTTP request headers as span attributes, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST``
|
||||||
|
to a comma-separated list of HTTP header names.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST="content-type,custom_request_header"
|
||||||
|
|
||||||
|
will extract ``content-type`` and ``custom_request_header`` from request headers and add them as span attributes.
|
||||||
|
|
||||||
|
It is recommended that you should give the correct names of the headers to be captured in the environment variable.
|
||||||
|
Request header names in FastAPI are case insensitive. So, giving header name as ``CUStom-Header`` in environment variable will be able capture header with name ``custom-header``.
|
||||||
|
|
||||||
|
The name of the added span attribute will follow the format ``http.request.header.<header_name>`` where ``<header_name>`` being the normalized HTTP header name (lowercase, with - characters replaced by _ ).
|
||||||
|
The value of the attribute will be single item list containing all the header values.
|
||||||
|
|
||||||
|
Example of the added span attribute,
|
||||||
|
``http.request.header.custom_request_header = ["<value1>,<value2>"]``
|
||||||
|
|
||||||
|
Response headers
|
||||||
|
****************
|
||||||
|
To capture predefined HTTP response headers as span attributes, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE``
|
||||||
|
to a comma-separated list of HTTP header names.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE="content-type,custom_response_header"
|
||||||
|
|
||||||
|
will extract ``content-type`` and ``custom_response_header`` from response headers and add them as span attributes.
|
||||||
|
|
||||||
|
It is recommended that you should give the correct names of the headers to be captured in the environment variable.
|
||||||
|
Response header names captured in FastAPI are case insensitive. So, giving header name as ``CUStomHeader`` in environment variable will be able capture header with name ``customheader``.
|
||||||
|
|
||||||
|
The name of the added span attribute will follow the format ``http.response.header.<header_name>`` where ``<header_name>`` being the normalized HTTP header name (lowercase, with - characters replaced by _ ).
|
||||||
|
The value of the attribute will be single item list containing all the header values.
|
||||||
|
|
||||||
|
Example of the added span attribute,
|
||||||
|
``http.response.header.custom_response_header = ["<value1>,<value2>"]``
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Environment variable names to caputre http headers are still experimental, and thus are subject to change.
|
||||||
|
|
||||||
API
|
API
|
||||||
---
|
---
|
||||||
"""
|
"""
|
||||||
|
@ -16,6 +16,7 @@ import unittest
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import fastapi
|
import fastapi
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
import opentelemetry.instrumentation.fastapi as otel_fastapi
|
import opentelemetry.instrumentation.fastapi as otel_fastapi
|
||||||
@ -23,8 +24,13 @@ from opentelemetry import trace
|
|||||||
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
|
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
|
||||||
from opentelemetry.sdk.resources import Resource
|
from opentelemetry.sdk.resources import Resource
|
||||||
from opentelemetry.semconv.trace import SpanAttributes
|
from opentelemetry.semconv.trace import SpanAttributes
|
||||||
|
from opentelemetry.test.globals_test import reset_trace_globals
|
||||||
from opentelemetry.test.test_base import TestBase
|
from opentelemetry.test.test_base import TestBase
|
||||||
from opentelemetry.util.http import get_excluded_urls
|
from opentelemetry.util.http import (
|
||||||
|
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST,
|
||||||
|
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE,
|
||||||
|
get_excluded_urls,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestFastAPIManualInstrumentation(TestBase):
|
class TestFastAPIManualInstrumentation(TestBase):
|
||||||
@ -375,3 +381,314 @@ class TestWrappedApplication(TestBase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parent_span.context.span_id, span_list[3].context.span_id
|
parent_span.context.span_id, span_list[3].context.span_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestHTTPAppWithCustomHeaders(TestBase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
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()
|
||||||
|
self.app = self._create_app()
|
||||||
|
otel_fastapi.FastAPIInstrumentor().instrument_app(self.app)
|
||||||
|
self.client = TestClient(self.app)
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
super().tearDown()
|
||||||
|
self.env_patch.stop()
|
||||||
|
with self.disable_logging():
|
||||||
|
otel_fastapi.FastAPIInstrumentor().uninstrument_app(self.app)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_app():
|
||||||
|
app = fastapi.FastAPI()
|
||||||
|
|
||||||
|
@app.get("/foobar")
|
||||||
|
async def _():
|
||||||
|
headers = {
|
||||||
|
"custom-test-header-1": "test-header-value-1",
|
||||||
|
"custom-test-header-2": "test-header-value-2",
|
||||||
|
}
|
||||||
|
content = {"message": "hello world"}
|
||||||
|
return JSONResponse(content=content, headers=headers)
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
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",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
resp = self.client.get(
|
||||||
|
"/foobar",
|
||||||
|
headers={
|
||||||
|
"custom-test-header-1": "test-header-value-1",
|
||||||
|
"custom-test-header-2": "test-header-value-2",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 3)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
|
||||||
|
self.assertSpanHasAttributes(server_span, expected)
|
||||||
|
|
||||||
|
def test_http_custom_request_headers_not_in_span_attributes(self):
|
||||||
|
not_expected = {
|
||||||
|
"http.request.header.custom_test_header_3": (
|
||||||
|
"test-header-value-3",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
resp = self.client.get(
|
||||||
|
"/foobar",
|
||||||
|
headers={
|
||||||
|
"custom-test-header-1": "test-header-value-1",
|
||||||
|
"custom-test-header-2": "test-header-value-2",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 3)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
|
||||||
|
for key, _ in not_expected.items():
|
||||||
|
self.assertNotIn(key, server_span.attributes)
|
||||||
|
|
||||||
|
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",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
resp = self.client.get("/foobar")
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 3)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
self.assertSpanHasAttributes(server_span, expected)
|
||||||
|
|
||||||
|
def test_http_custom_response_headers_not_in_span_attributes(self):
|
||||||
|
not_expected = {
|
||||||
|
"http.reponse.header.custom_test_header_3": (
|
||||||
|
"test-header-value-3",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
resp = self.client.get("/foobar")
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 3)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
|
||||||
|
for key, _ in not_expected.items():
|
||||||
|
self.assertNotIn(key, server_span.attributes)
|
||||||
|
|
||||||
|
|
||||||
|
class TestWebSocketAppWithCustomHeaders(TestBase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
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()
|
||||||
|
self.app = self._create_app()
|
||||||
|
otel_fastapi.FastAPIInstrumentor().instrument_app(self.app)
|
||||||
|
self.client = TestClient(self.app)
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
super().tearDown()
|
||||||
|
self.env_patch.stop()
|
||||||
|
with self.disable_logging():
|
||||||
|
otel_fastapi.FastAPIInstrumentor().uninstrument_app(self.app)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_app():
|
||||||
|
app = fastapi.FastAPI()
|
||||||
|
|
||||||
|
@app.websocket("/foobar_web")
|
||||||
|
async def _(websocket: fastapi.WebSocket):
|
||||||
|
message = await websocket.receive()
|
||||||
|
if message.get("type") == "websocket.connect":
|
||||||
|
await websocket.send(
|
||||||
|
{
|
||||||
|
"type": "websocket.accept",
|
||||||
|
"headers": [
|
||||||
|
(b"custom-test-header-1", b"test-header-value-1"),
|
||||||
|
(b"custom-test-header-2", b"test-header-value-2"),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
await websocket.send_json({"message": "hello world"})
|
||||||
|
await websocket.close()
|
||||||
|
if message.get("type") == "websocket.disconnect":
|
||||||
|
pass
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
def test_web_socket_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",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
with self.client.websocket_connect(
|
||||||
|
"/foobar_web",
|
||||||
|
headers={
|
||||||
|
"custom-test-header-1": "test-header-value-1",
|
||||||
|
"custom-test-header-2": "test-header-value-2",
|
||||||
|
},
|
||||||
|
) as websocket:
|
||||||
|
data = websocket.receive_json()
|
||||||
|
self.assertEqual(data, {"message": "hello world"})
|
||||||
|
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 5)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
|
||||||
|
self.assertSpanHasAttributes(server_span, expected)
|
||||||
|
|
||||||
|
def test_web_socket_custom_request_headers_not_in_span_attributes(self):
|
||||||
|
not_expected = {
|
||||||
|
"http.request.header.custom_test_header_3": (
|
||||||
|
"test-header-value-3",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
with self.client.websocket_connect(
|
||||||
|
"/foobar_web",
|
||||||
|
headers={
|
||||||
|
"custom-test-header-1": "test-header-value-1",
|
||||||
|
"custom-test-header-2": "test-header-value-2",
|
||||||
|
},
|
||||||
|
) as websocket:
|
||||||
|
data = websocket.receive_json()
|
||||||
|
self.assertEqual(data, {"message": "hello world"})
|
||||||
|
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 5)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
|
||||||
|
for key, _ in not_expected.items():
|
||||||
|
self.assertNotIn(key, server_span.attributes)
|
||||||
|
|
||||||
|
def test_web_socket_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",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
with self.client.websocket_connect("/foobar_web") as websocket:
|
||||||
|
data = websocket.receive_json()
|
||||||
|
self.assertEqual(data, {"message": "hello world"})
|
||||||
|
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 5)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
|
||||||
|
self.assertSpanHasAttributes(server_span, expected)
|
||||||
|
|
||||||
|
def test_web_socket_custom_response_headers_not_in_span_attributes(self):
|
||||||
|
not_expected = {
|
||||||
|
"http.reponse.header.custom_test_header_3": (
|
||||||
|
"test-header-value-3",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
with self.client.websocket_connect("/foobar_web") as websocket:
|
||||||
|
data = websocket.receive_json()
|
||||||
|
self.assertEqual(data, {"message": "hello world"})
|
||||||
|
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 5)
|
||||||
|
|
||||||
|
server_span = [
|
||||||
|
span for span in span_list if span.kind == trace.SpanKind.SERVER
|
||||||
|
][0]
|
||||||
|
|
||||||
|
for key, _ in not_expected.items():
|
||||||
|
self.assertNotIn(key, server_span.attributes)
|
||||||
|
|
||||||
|
|
||||||
|
class TestNonRecordingSpanWithCustomHeaders(TestBase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.env_patch.start()
|
||||||
|
self.app = fastapi.FastAPI()
|
||||||
|
|
||||||
|
@self.app.get("/foobar")
|
||||||
|
async def _():
|
||||||
|
return {"message": "hello world"}
|
||||||
|
|
||||||
|
reset_trace_globals()
|
||||||
|
tracer_provider = trace.NoOpTracerProvider()
|
||||||
|
trace.set_tracer_provider(tracer_provider=tracer_provider)
|
||||||
|
|
||||||
|
self._instrumentor = otel_fastapi.FastAPIInstrumentor()
|
||||||
|
self._instrumentor.instrument_app(self.app)
|
||||||
|
self.client = TestClient(self.app)
|
||||||
|
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
super().tearDown()
|
||||||
|
with self.disable_logging():
|
||||||
|
self._instrumentor.uninstrument_app(self.app)
|
||||||
|
|
||||||
|
def test_custom_header_not_present_in_non_recording_span(self):
|
||||||
|
resp = self.client.get(
|
||||||
|
"/foobar",
|
||||||
|
headers={
|
||||||
|
"custom-test-header-1": "test-header-value-1",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
span_list = self.memory_exporter.get_finished_spans()
|
||||||
|
self.assertEqual(len(span_list), 0)
|
||||||
|
Reference in New Issue
Block a user