Skip to content

Commit 1080ee0

Browse files
committed
add test to check osparc-trace-id is in response header
1 parent 67332de commit 1080ee0

File tree

3 files changed

+73
-6
lines changed

3 files changed

+73
-6
lines changed

packages/service-library/src/servicelib/aiohttp/tracing.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
middleware as aiohttp_server_opentelemetry_middleware, # pylint:disable=no-name-in-module
1616
)
1717
from opentelemetry.sdk.resources import Resource
18-
from opentelemetry.sdk.trace import TracerProvider
18+
from opentelemetry.sdk.trace import SpanProcessor, TracerProvider
1919
from opentelemetry.sdk.trace.export import BatchSpanProcessor
2020
from servicelib.logging_utils import log_context
2121
from servicelib.tracing import get_trace_id_header
@@ -52,6 +52,14 @@
5252
HAS_AIO_PIKA = False
5353

5454

55+
def _create_span_processor(tracing_destination: str) -> SpanProcessor:
56+
otlp_exporter = OTLPSpanExporterHTTP(
57+
endpoint=tracing_destination,
58+
)
59+
span_processor = BatchSpanProcessor(otlp_exporter)
60+
return span_processor
61+
62+
5563
def _startup(
5664
app: web.Application,
5765
tracing_settings: TracingSettings,
@@ -92,12 +100,8 @@ def _startup(
92100
tracing_destination,
93101
)
94102

95-
otlp_exporter = OTLPSpanExporterHTTP(
96-
endpoint=tracing_destination,
97-
)
98-
99103
# Add the span processor to the tracer provider
100-
tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter)) # type: ignore[attr-defined] # https://github.com/open-telemetry/opentelemetry-python/issues/3713
104+
tracer_provider.add_span_processor(_create_span_processor()) # type: ignore[attr-defined] # https://github.com/open-telemetry/opentelemetry-python/issues/3713
101105
# Instrument aiohttp server
102106
# Explanation for custom middleware call DK 10/2024:
103107
# OpenTelemetry Aiohttp autoinstrumentation is meant to be used by only calling `AioHttpServerInstrumentor().instrument()`
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,21 @@
11
# pylint: disable=redefined-outer-name
22
# pylint: disable=unused-argument
3+
4+
5+
from collections.abc import Iterator
6+
from unittest.mock import patch
7+
8+
import pytest
9+
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
10+
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
11+
from pytest_mock import MockerFixture
12+
13+
14+
@pytest.fixture
15+
def mock_otel_collector(mocker: MockerFixture) -> Iterator[InMemorySpanExporter]:
16+
memory_exporter = InMemorySpanExporter()
17+
span_processor = SimpleSpanProcessor(memory_exporter)
18+
with patch(
19+
"servicelib.aiohttp.tracing._create_span_processor", return_value=span_processor
20+
):
21+
yield memory_exporter

packages/service-library/tests/aiohttp/test_tracing.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
import pytest
1111
from aiohttp import web
1212
from aiohttp.test_utils import TestClient
13+
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
1314
from pydantic import ValidationError
1415
from servicelib.aiohttp.tracing import get_tracing_lifespan
16+
from servicelib.tracing import _OSPARC_TRACE_ID_HEADER
1517
from settings_library.tracing import TracingSettings
1618

1719

@@ -148,3 +150,45 @@ async def test_tracing_setup_package_detection(
148150
tracing_settings=tracing_settings,
149151
)(app):
150152
pass
153+
154+
155+
@pytest.mark.parametrize(
156+
"tracing_settings_in",
157+
[
158+
("http://opentelemetry-collector", 4318),
159+
],
160+
indirect=True,
161+
)
162+
@pytest.mark.parametrize(
163+
"response", [web.Response(text="Hello, world!"), web.HTTPNotFound()]
164+
)
165+
async def test_trace_id_in_response_header(
166+
mock_otel_collector: InMemorySpanExporter,
167+
aiohttp_client: Callable,
168+
set_and_clean_settings_env_vars: Callable,
169+
tracing_settings_in,
170+
uninstrument_opentelemetry: Iterator[None],
171+
response: web.Response | web.HTTPException,
172+
) -> None:
173+
app = web.Application()
174+
service_name = "simcore_service_webserver"
175+
tracing_settings = TracingSettings()
176+
177+
async def handler(request: web.Request) -> web.Response:
178+
if isinstance(response, web.HTTPException):
179+
raise response
180+
return response
181+
182+
app.router.add_get("/", handler)
183+
184+
async for _ in get_tracing_lifespan(
185+
app,
186+
service_name=service_name,
187+
tracing_settings=tracing_settings,
188+
add_response_trace_id_header=True,
189+
)(app):
190+
client = await aiohttp_client(app)
191+
response = await client.get("/")
192+
assert _OSPARC_TRACE_ID_HEADER in response.headers
193+
trace_id = response.headers[_OSPARC_TRACE_ID_HEADER]
194+
assert len(trace_id) == 32 # Ensure trace ID is a 32-character hex string

0 commit comments

Comments
 (0)