Skip to content

fix: Fix missing metric response attributes in HTTPX instrumentation #3615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- `opentelemetry-instrumentation-httpx`: fix missing metric response attributes when tracing is disabled
([#3615](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3615))
- `opentelemetry-instrumentation-asgi`: fix excluded_urls in instrumentation-asgi
([#3567](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3567))
- `opentelemetry-resource-detector-containerid`: make it more quiet on platforms without cgroups
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,6 @@ def _apply_request_client_attributes_to_span(

def _apply_response_client_attributes_to_span(
span: Span,
metric_attributes: dict[str, typing.Any],
status_code: int,
http_version: str,
semconv: _StabilityMode,
Expand All @@ -433,6 +432,30 @@ def _apply_response_client_attributes_to_span(
http_status_code = http_status_to_status_code(status_code)
span.set_status(http_status_code)

if http_status_code == StatusCode.ERROR and _report_new(semconv):
# http semconv transition: new error.type
span_attributes[ERROR_TYPE] = str(status_code)

if http_version and _report_new(semconv):
# http semconv transition: http.flavor -> network.protocol.version
_set_http_network_protocol_version(
span_attributes,
http_version.replace("HTTP/", ""),
semconv,
)

for key, val in span_attributes.items():
span.set_attribute(key, val)


def _apply_response_client_attributes_to_metrics(
span: Span | None,
metric_attributes: dict[str, typing.Any],
status_code: int,
http_version: str,
semconv: _StabilityMode,
) -> None:
"""Apply response attributes to metric attributes."""
# Set HTTP status code in metric attributes
_set_status(
span,
Expand All @@ -443,26 +466,12 @@ def _apply_response_client_attributes_to_span(
sem_conv_opt_in_mode=semconv,
)

if http_status_code == StatusCode.ERROR and _report_new(semconv):
# http semconv transition: new error.type
span_attributes[ERROR_TYPE] = str(status_code)

if http_version and _report_new(semconv):
# http semconv transition: http.flavor -> network.protocol.version
_set_http_network_protocol_version(
metric_attributes,
http_version.replace("HTTP/", ""),
semconv,
)
if _report_new(semconv):
_set_http_network_protocol_version(
span_attributes,
http_version.replace("HTTP/", ""),
semconv,
)

for key, val in span_attributes.items():
span.set_attribute(key, val)


class SyncOpenTelemetryTransport(httpx.BaseTransport):
Expand Down Expand Up @@ -592,11 +601,19 @@ def handle_request(
_extract_response(response)
)

# Always apply response attributes to metrics
_apply_response_client_attributes_to_metrics(
span,
metric_attributes,
status_code,
http_version,
self._sem_conv_opt_in_mode,
)

if span.is_recording():
# apply http client response attributes according to semconv
_apply_response_client_attributes_to_span(
span,
metric_attributes,
status_code,
http_version,
self._sem_conv_opt_in_mode,
Expand Down Expand Up @@ -777,11 +794,19 @@ async def handle_async_request(
_extract_response(response)
)

# Always apply response attributes to metrics
_apply_response_client_attributes_to_metrics(
span,
metric_attributes,
status_code,
http_version,
self._sem_conv_opt_in_mode,
)

if span.is_recording():
# apply http client response attributes according to semconv
_apply_response_client_attributes_to_span(
span,
metric_attributes,
status_code,
http_version,
self._sem_conv_opt_in_mode,
Expand Down Expand Up @@ -1001,11 +1026,19 @@ def _handle_request_wrapper( # pylint: disable=too-many-locals
_extract_response(response)
)

# Always apply response attributes to metrics
_apply_response_client_attributes_to_metrics(
span,
metric_attributes,
status_code,
http_version,
sem_conv_opt_in_mode,
)

if span.is_recording():
# apply http client response attributes according to semconv
_apply_response_client_attributes_to_span(
span,
metric_attributes,
status_code,
http_version,
sem_conv_opt_in_mode,
Expand Down Expand Up @@ -1109,11 +1142,19 @@ async def _handle_async_request_wrapper( # pylint: disable=too-many-locals
_extract_response(response)
)

# Always apply response attributes to metrics
_apply_response_client_attributes_to_metrics(
span,
metric_attributes,
status_code,
http_version,
sem_conv_opt_in_mode,
)

if span.is_recording():
# apply http client response attributes according to semconv
_apply_response_client_attributes_to_span(
span,
metric_attributes,
status_code,
http_version,
sem_conv_opt_in_mode,
Expand Down
Loading