Skip to content

Commit c3a7962

Browse files
committed
add test and sampling strategy to aiohttp tracing instrumentation
1 parent 8e3a187 commit c3a7962

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from opentelemetry.sdk.resources import Resource
1818
from opentelemetry.sdk.trace import SpanProcessor, TracerProvider
1919
from opentelemetry.sdk.trace.export import BatchSpanProcessor
20+
from opentelemetry.sdk.trace.sampling import ParentBased, TraceIdRatioBased
2021
from settings_library.tracing import TracingSettings
2122
from yarl import URL
2223

@@ -95,7 +96,11 @@ def _startup(
9596
)
9697
raise RuntimeError(msg)
9798
resource = Resource(attributes={"service.name": service_name})
98-
trace.set_tracer_provider(TracerProvider(resource=resource))
99+
sampler = ParentBased(
100+
root=TraceIdRatioBased(tracing_settings.TRACING_SAMPLING_PROBABILITY)
101+
)
102+
tracer_provider = TracerProvider(resource=resource, sampler=sampler)
103+
trace.set_tracer_provider(tracer_provider=tracer_provider)
99104
tracer_provider: trace.TracerProvider = trace.get_tracer_provider()
100105

101106
tracing_destination: str = (

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# pylint: disable=unused-argument
33
# pylint: disable=unused-variable
44

5+
import asyncio
56
import importlib
67
from collections.abc import Callable
78
from functools import partial
@@ -40,11 +41,17 @@ def set_and_clean_settings_env_vars(
4041
monkeypatch.setenv(
4142
"TRACING_OPENTELEMETRY_COLLECTOR_PORT", f"{tracing_settings_in[1]}"
4243
)
44+
sampling_probability_mocked = False
45+
if tracing_settings_in[2]:
46+
sampling_probability_mocked = True
47+
monkeypatch.setenv("TRACING_SAMPLING_PROBABILITY", tracing_settings_in[2])
4348
yield
4449
if endpoint_mocked:
4550
monkeypatch.delenv("TRACING_OPENTELEMETRY_COLLECTOR_ENDPOINT")
4651
if port_mocked:
4752
monkeypatch.delenv("TRACING_OPENTELEMETRY_COLLECTOR_PORT")
53+
if sampling_probability_mocked:
54+
monkeypatch.delenv("TRACING_SAMPLING_PROBABILITY")
4855

4956

5057
@pytest.mark.parametrize(
@@ -201,3 +208,61 @@ async def handler(handler_data: dict, request: web.Request) -> web.Response:
201208
assert (
202209
trace_id == handler_data[_OSPARC_TRACE_ID_HEADER]
203210
) # Ensure trace IDs match
211+
212+
213+
@pytest.mark.parametrize(
214+
"tracing_settings_in",
215+
[
216+
("http://opentelemetry-collector", 4318, 0.05),
217+
],
218+
indirect=True,
219+
)
220+
async def test_tracing_sampling_probability_effective(
221+
mock_otel_collector: InMemorySpanExporter,
222+
aiohttp_client: Callable,
223+
set_and_clean_settings_env_vars: Callable[[], None],
224+
tracing_settings_in,
225+
):
226+
"""
227+
This test checks that the TRACING_SAMPLING_PROBABILITY setting in TracingSettings
228+
is effective by sending 1000 requests and verifying that the number of collected traces
229+
is close to 0.05 * 1000 (with some tolerance).
230+
"""
231+
n_requests = 1000
232+
tolerance_probability = 0.5
233+
234+
app = web.Application()
235+
service_name = "simcore_service_webserver"
236+
tracing_settings = TracingSettings()
237+
238+
async def handler(request: web.Request) -> web.Response:
239+
return web.Response(text="ok")
240+
241+
app.router.add_get("/", handler)
242+
243+
async for _ in get_tracing_lifespan(
244+
app=app,
245+
service_name=service_name,
246+
tracing_settings=tracing_settings,
247+
)(app):
248+
client = await aiohttp_client(app)
249+
250+
async def make_request():
251+
await client.get("/")
252+
253+
await asyncio.gather(*(make_request() for _ in range(n_requests)))
254+
spans = mock_otel_collector.get_finished_spans()
255+
trace_ids = set()
256+
for span in spans:
257+
if span.context is not None:
258+
trace_ids.add(span.context.trace_id)
259+
num_traces = len(trace_ids)
260+
expected_num_traces = int(
261+
tracing_settings.TRACING_SAMPLING_PROBABILITY * n_requests
262+
)
263+
tolerance = int(tolerance_probability * expected_num_traces)
264+
assert (
265+
expected_num_traces - tolerance
266+
<= num_traces
267+
<= expected_num_traces + tolerance
268+
), f"Expected roughly {expected_num_traces} distinct trace ids, got {num_traces}"

0 commit comments

Comments
 (0)