Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ async def do_request():
return loop.run_until_complete(do_request())


SCOPE = "opentelemetry.instrumentation.aiohttp_client"


# pylint: disable=too-many-public-methods
class TestAioHttpIntegration(TestBase):
_test_status_codes = (
Expand Down Expand Up @@ -122,7 +125,7 @@ def _assert_spans(self, spans, num_spans=1):
)

def _assert_metrics(self, num_metrics: int = 1):
metrics = self.get_sorted_metrics()
metrics = self.get_sorted_metrics(SCOPE)
self.assertEqual(len(metrics), num_metrics)
return metrics

Expand Down Expand Up @@ -917,7 +920,7 @@ def _assert_spans(self, num_spans: int):
return finished_spans

def _assert_metrics(self, num_metrics: int = 1):
metrics = self.get_sorted_metrics()
metrics = self.get_sorted_metrics(SCOPE)
self.assertEqual(len(metrics), num_metrics)
return metrics

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ def __repr__(self):
TRACE = "TRACE"


SCOPE = "opentelemetry.instrumentation.aiohttp_server"


@pytest.fixture(name="test_base", scope="function")
def fixture_test_base():
test_base = TestBase()
test_base.setUp()
try:
yield test_base
finally:
test_base.tearDown()


@pytest.fixture(name="tracer", scope="function")
def fixture_tracer():
test_base = TestBase()
Expand Down Expand Up @@ -149,15 +162,15 @@ async def test_status_code_instrumentation(
_, metrics_reader = meter
server, _ = server_fixture

assert len(memory_exporter.get_finished_spans()) == 0
metrics = _get_sorted_metrics(metrics_reader.get_metrics_data())
assert len(test_base.get_finished_spans()) == 0
metrics = test_base.get_sorted_metrics(SCOPE)
assert len(metrics) == 0

client = await aiohttp_client(server)
await client.get(url)

assert len(memory_exporter.get_finished_spans()) == 1
metrics = _get_sorted_metrics(metrics_reader.get_metrics_data())
assert len(test_base.get_finished_spans()) == 1
metrics = test_base.get_sorted_metrics(SCOPE)
assert len(metrics) == 2

[span] = memory_exporter.get_finished_spans()
Expand Down Expand Up @@ -275,7 +288,7 @@ async def handler(request):
spans = memory_exporter.get_finished_spans()
assert len(spans) == 0

metrics = _get_sorted_metrics(metrics_reader.get_metrics_data())
metrics = test_base.get_sorted_metrics(SCOPE)
assert len(metrics) == 0

AioHttpServerInstrumentor().uninstrument()
Expand Down Expand Up @@ -400,3 +413,249 @@ async def handler(request):
assert "http.response.header.custom_test_header_3" not in span.attributes

AioHttpServerInstrumentor().uninstrument()


# pylint: disable=too-many-locals
@pytest.mark.asyncio
async def test_semantic_conventions_metrics_old_default(
test_base: TestBase, aiohttp_server, monkeypatch
):
monkeypatch.setenv(
OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.DEFAULT.value
)
_OpenTelemetrySemanticConventionStability._initialized = False

AioHttpServerInstrumentor().instrument()
app = aiohttp.web.Application()
app.router.add_get("/test-path", default_handler)
server = await aiohttp_server(app)
client_session = aiohttp.ClientSession()
try:
url = f"http://{server.host}:{server.port}/test-path?query=test"
async with client_session.get( # pylint: disable=not-async-context-manager
url, headers={"User-Agent": "test-agent"}
) as response:
assert response.status == 200
spans = test_base.get_finished_spans()
assert len(spans) == 1
span = spans[0]

# Verify old semconv schema URL
assert (
span.instrumentation_scope.schema_url
== "https://opentelemetry.io/schemas/1.11.0"
)

# Old semconv span attributes present
assert span.attributes.get(HTTP_METHOD) == "GET"
assert span.attributes.get(HTTP_SCHEME) == "http"
assert span.attributes.get(NET_HOST_NAME) == server.host
assert span.attributes.get(NET_HOST_PORT) == server.port
assert span.attributes.get(HTTP_TARGET) == "/test-path?query=test"
assert span.attributes.get(HTTP_USER_AGENT) == "test-agent"
assert span.attributes.get(HTTP_FLAVOR) == "1.1"
assert span.attributes.get(HTTP_STATUS_CODE) == 200
assert span.attributes.get(HTTP_ROUTE) == "default_handler"
# New semconv span attributes NOT present
assert HTTP_REQUEST_METHOD not in span.attributes
assert URL_SCHEME not in span.attributes
assert SERVER_ADDRESS not in span.attributes
assert SERVER_PORT not in span.attributes
assert URL_PATH not in span.attributes
assert URL_QUERY not in span.attributes
assert USER_AGENT_ORIGINAL not in span.attributes
assert NETWORK_PROTOCOL_VERSION not in span.attributes
assert HTTP_RESPONSE_STATUS_CODE not in span.attributes

metrics = test_base.get_sorted_metrics(SCOPE)
expected_metric_names = [
"http.server.active_requests",
"http.server.duration",
]
recommended_metrics_attrs = {
"http.server.active_requests": _server_active_requests_count_attrs_old,
"http.server.duration": _server_duration_attrs_old,
}
for metric in metrics:
assert metric.name in expected_metric_names
if metric.name == "http.server.duration":
assert metric.unit == "ms"
for point in metric.data.data_points:
for attr in point.attributes:
assert attr in recommended_metrics_attrs[metric.name]

finally:
await client_session.close()
AioHttpServerInstrumentor().uninstrument()


# pylint: disable=too-many-locals
@pytest.mark.asyncio
async def test_semantic_conventions_metrics_new(
test_base: TestBase, meter, aiohttp_server, monkeypatch
):
monkeypatch.setenv(
OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.HTTP.value
)
_OpenTelemetrySemanticConventionStability._initialized = False

AioHttpServerInstrumentor().instrument()
app = aiohttp.web.Application()
app.router.add_get("/test-path", default_handler)
server = await aiohttp_server(app)
client_session = aiohttp.ClientSession()
try:
url = f"http://{server.host}:{server.port}/test-path?query=test"
async with client_session.get( # pylint: disable=not-async-context-manager
url, headers={"User-Agent": "test-agent"}
) as response:
assert response.status == 200
spans = test_base.get_finished_spans()
assert len(spans) == 1
span = spans[0]

# Verify new semconv schema URL
assert (
span.instrumentation_scope.schema_url
== "https://opentelemetry.io/schemas/1.21.0"
)

# New semconv span attributes present
assert span.attributes.get(HTTP_REQUEST_METHOD) == "GET"
assert span.attributes.get(URL_SCHEME) == "http"
assert span.attributes.get(SERVER_ADDRESS) == server.host
assert span.attributes.get(SERVER_PORT) == server.port
assert span.attributes.get(URL_PATH) == "/test-path"
assert span.attributes.get(URL_QUERY) == "query=test"
assert span.attributes.get(USER_AGENT_ORIGINAL) == "test-agent"
assert span.attributes.get(NETWORK_PROTOCOL_VERSION) == "1.1"
assert span.attributes.get(HTTP_RESPONSE_STATUS_CODE) == 200
assert span.attributes.get(HTTP_ROUTE) == "default_handler"
# Old semconv span attributes NOT present
assert HTTP_METHOD not in span.attributes
assert HTTP_SCHEME not in span.attributes
assert NET_HOST_NAME not in span.attributes
assert NET_HOST_PORT not in span.attributes
assert HTTP_TARGET not in span.attributes
assert HTTP_USER_AGENT not in span.attributes
assert HTTP_FLAVOR not in span.attributes
assert HTTP_STATUS_CODE not in span.attributes

metrics = test_base.get_sorted_metrics(SCOPE)
expected_metric_names = [
"http.server.active_requests",
"http.server.request.duration",
]
recommended_metrics_attrs = {
"http.server.active_requests": _server_active_requests_count_attrs_new,
"http.server.request.duration": _server_duration_attrs_new,
}
for metric in metrics:
assert metric.name in expected_metric_names
if metric.name == "http.server.request.duration":
assert metric.unit == "s"
for point in metric.data.data_points:
if (
isinstance(point, HistogramDataPoint)
and metric.name == "http.server.request.duration"
):
assert (
point.explicit_bounds
== HTTP_DURATION_HISTOGRAM_BUCKETS_NEW
)
for attr in point.attributes:
assert attr in recommended_metrics_attrs[metric.name]

finally:
await client_session.close()
AioHttpServerInstrumentor().uninstrument()


# pylint: disable=too-many-locals
# pylint: disable=too-many-statements
@pytest.mark.asyncio
async def test_semantic_conventions_metrics_both(
test_base: TestBase, meter, aiohttp_server, monkeypatch
):
monkeypatch.setenv(
OTEL_SEMCONV_STABILITY_OPT_IN, _StabilityMode.HTTP_DUP.value
)
_OpenTelemetrySemanticConventionStability._initialized = False

AioHttpServerInstrumentor().instrument()
app = aiohttp.web.Application()
app.router.add_get("/test-path", default_handler)
server = await aiohttp_server(app)
client_session = aiohttp.ClientSession()
try:
url = f"http://{server.host}:{server.port}/test-path?query=test"
async with client_session.get( # pylint: disable=not-async-context-manager
url, headers={"User-Agent": "test-agent"}
) as response:
assert response.status == 200
spans = test_base.get_finished_spans()
assert len(spans) == 1
span = spans[0]

# Verify new semconv schema URL (both mode uses new schema)
assert (
span.instrumentation_scope.schema_url
== "https://opentelemetry.io/schemas/1.21.0"
)

# Both old and new semconv span attributes present
assert span.attributes.get(HTTP_METHOD) == "GET"
assert span.attributes.get(HTTP_REQUEST_METHOD) == "GET"
assert span.attributes.get(HTTP_SCHEME) == "http"
assert span.attributes.get(URL_SCHEME) == "http"
assert span.attributes.get(NET_HOST_NAME) == server.host
assert span.attributes.get(SERVER_ADDRESS) == server.host
assert span.attributes.get(NET_HOST_PORT) == server.port
assert span.attributes.get(SERVER_PORT) == server.port
assert span.attributes.get(HTTP_TARGET) == "/test-path?query=test"
assert span.attributes.get(URL_PATH) == "/test-path"
assert span.attributes.get(URL_QUERY) == "query=test"
assert span.attributes.get(HTTP_USER_AGENT) == "test-agent"
assert span.attributes.get(USER_AGENT_ORIGINAL) == "test-agent"
assert span.attributes.get(HTTP_FLAVOR) == "1.1"
assert span.attributes.get(NETWORK_PROTOCOL_VERSION) == "1.1"
assert span.attributes.get(HTTP_STATUS_CODE) == 200
assert span.attributes.get(HTTP_RESPONSE_STATUS_CODE) == 200
assert span.attributes.get(HTTP_ROUTE) == "default_handler"

metrics = test_base.get_sorted_metrics(SCOPE)
assert len(metrics) == 3 # Both duration metrics + active requests
server_active_requests_count_attrs_both = list(
_server_active_requests_count_attrs_old
)
server_active_requests_count_attrs_both.extend(
_server_active_requests_count_attrs_new
)
recommended_metrics_attrs = {
"http.server.active_requests": server_active_requests_count_attrs_both,
"http.server.duration": _server_duration_attrs_old,
"http.server.request.duration": _server_duration_attrs_new,
}
for metric in metrics:
if metric.unit == "ms":
assert metric.name == "http.server.duration"
elif metric.unit == "s":
assert metric.name == "http.server.request.duration"
else:
assert metric.name == "http.server.active_requests"

for point in metric.data.data_points:
if (
isinstance(point, HistogramDataPoint)
and metric.name == "http.server.request.duration"
):
assert (
point.explicit_bounds
== HTTP_DURATION_HISTOGRAM_BUCKETS_NEW
)
for attr in point.attributes:
assert attr in recommended_metrics_attrs[metric.name]

finally:
await client_session.close()
AioHttpServerInstrumentor().uninstrument()
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from opentelemetry.test.test_base import TestBase
from opentelemetry.trace import get_tracer

SCOPE = "opentelemetry.instrumentation.asyncio"


class TestTraceFuture(TestBase):
@patch.dict(
Expand Down Expand Up @@ -41,12 +43,7 @@ async def future_cancelled():
self.assertEqual(spans[0].name, "root")
self.assertEqual(spans[1].name, "asyncio future")

metrics = (
self.memory_metrics_reader.get_metrics_data()
.resource_metrics[0]
.scope_metrics[0]
.metrics
)
metrics = self.get_sorted_metrics(SCOPE)
self.assertEqual(len(metrics), 2)

self.assertEqual(metrics[0].name, "asyncio.process.duration")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from .celery_test_tasks import app, task_add

SCOPE = "opentelemetry.instrumentation.celery"


class TestMetrics(TestBase):
def setUp(self):
Expand All @@ -34,7 +36,7 @@ def get_metrics(self):
if time.time() > timeout:
break
time.sleep(0.05)
return self.get_sorted_metrics()
return self.get_sorted_metrics(SCOPE)

def test_basic_metric(self):
CeleryInstrumentor().instrument()
Expand Down
Loading
Loading