Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- `opentelemetry-instrumentation-aiohttp-server`: Use `canonical` attribute of the `Resource` as a span name.
([#3896](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3896))

### Added

- `opentelemetry-instrumentation-aiohttp-client`: add support for url exclusions via `OTEL_PYTHON_EXCLUDED_URLS` / `OTEL_PYTHON_AIOHTTP_CLIENT_EXCLUDED_URLS`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,22 @@ def _parse_active_request_count_attrs(req_attrs):


def get_default_span_name(request: web.Request) -> str:
"""Default implementation for get_default_span_details
"""Returns the span name.
Args:
request: the request object itself.
Returns:
The span name.
The canonical name of a resource if possible or just request path.
"""
span_name = request.path.strip() or f"HTTP {request.method}"
return span_name
try:
resource = request.match_info.route.resource
assert resource
path = resource.canonical
except (AttributeError, AssertionError):
path = ""

if path:
return f"{request.method} {path}"
return f"{request.method}"


def _get_view_func(request: web.Request) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from opentelemetry.semconv._incubating.attributes.http_attributes import (
HTTP_METHOD,
HTTP_STATUS_CODE,
HTTP_TARGET,
HTTP_URL,
)
from opentelemetry.test.globals_test import (
Expand Down Expand Up @@ -106,7 +107,15 @@ async def fixture_server_fixture(tracer, aiohttp_server, suppress):
AioHttpServerInstrumentor().instrument()

app = aiohttp.web.Application()
app.add_routes([aiohttp.web.get("/test-path", default_handler)])
app.add_routes(
[
aiohttp.web.get("/test-path", default_handler),
aiohttp.web.get("/test-path/{url_param}", default_handler),
aiohttp.web.get(
"/object/{object_id}/action/{another_param}", default_handler
),
]
)
if suppress:
with suppress_http_instrumentation():
server = await aiohttp_server(app)
Expand Down Expand Up @@ -170,6 +179,60 @@ async def test_status_code_instrumentation(
)


@pytest.mark.asyncio
@pytest.mark.parametrize(
"span_name, example_paths",
[
(
"GET /test-path/{url_param}",
(
"/test-path/foo",
"/test-path/bar",
),
),
(
"GET /object/{object_id}/action/{another_param}",
(
"/object/1/action/bar",
"/object/234/action/baz",
),
),
(
"GET",
(
"/i/dont/exist",
"/me-neither",
),
),
],
)
async def test_url_params_instrumentation(
tracer,
server_fixture,
aiohttp_client,
span_name,
example_paths,
):
_, memory_exporter = tracer
server, _ = server_fixture

assert len(memory_exporter.get_finished_spans()) == 0

client = await aiohttp_client(server)
for path in example_paths:
await client.get(path)

assert len(memory_exporter.get_finished_spans()) == 2

for request_path, span in zip(
example_paths, memory_exporter.get_finished_spans()
):
assert span_name == span.name
assert request_path == span.attributes[HTTP_TARGET]
full_url = f"http://{server.host}:{server.port}{request_path}"
assert full_url == span.attributes[HTTP_URL]


@pytest.mark.asyncio
@pytest.mark.parametrize("suppress", [True])
async def test_suppress_instrumentation(
Expand Down