Skip to content
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

httpx: fix handling of async hooks #2823

Merged
merged 6 commits into from
Aug 26, 2024
Merged
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
12 changes: 7 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## Added
### Added

- `opentelemetry-instrumentation-kafka-python` Instrument temporary fork, kafka-python-ng
inside kafka-python's instrumentation
([#2537](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2537))

## Breaking changes
### Breaking changes

- `opentelemetry-bootstrap` Remove `opentelemetry-instrumentation-aws-lambda` from the defaults instrumentations
([#2786](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2786))

## Fixed
### Fixed

- `opentelemetry-instrumentation-httpx` fix handling of async hooks
([#2823](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2823))
- `opentelemetry-instrumentation-system-metrics` fix `process.runtime.cpu.utilization` values to be shown in range of 0 to 1
([2812](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2812))
([#2812](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2812))
- `opentelemetry-instrumentation-fastapi` fix `fastapi` auto-instrumentation by removing `fastapi-slim` support, `fastapi-slim` itself is discontinued from maintainers
([2783](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2783))
([#2783](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2783))
- `opentelemetry-instrumentation-aws-lambda` Avoid exception when a handler is not present.
([#2750](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2750))
- `opentelemetry-instrumentation-django` Fix regression - `http.target` re-added back to old semconv duration metrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ async def async_response_hook(span, request, response):
"""
import logging
import typing
from asyncio import iscoroutinefunction
from types import TracebackType

import httpx
Expand Down Expand Up @@ -731,15 +732,19 @@ def _instrument(self, **kwargs):
self._original_async_client = httpx.AsyncClient
request_hook = kwargs.get("request_hook")
response_hook = kwargs.get("response_hook")
async_request_hook = kwargs.get("async_request_hook", request_hook)
async_response_hook = kwargs.get("async_response_hook", response_hook)
async_request_hook = kwargs.get("async_request_hook")
async_response_hook = kwargs.get("async_response_hook")
if callable(request_hook):
_InstrumentedClient._request_hook = request_hook
if callable(async_request_hook):
if callable(async_request_hook) and iscoroutinefunction(
async_request_hook
):
_InstrumentedAsyncClient._request_hook = async_request_hook
if callable(response_hook):
_InstrumentedClient._response_hook = response_hook
if callable(async_response_hook):
if callable(async_response_hook) and iscoroutinefunction(
async_response_hook
):
_InstrumentedAsyncClient._response_hook = async_response_hook
tracer_provider = kwargs.get("tracer_provider")
_InstrumentedClient._tracer_provider = tracer_provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -780,9 +780,15 @@ def test_custom_tracer_provider(self):
HTTPXClientInstrumentor().uninstrument()

def test_response_hook(self):
response_hook_key = (
"async_response_hook"
if asyncio.iscoroutinefunction(self.response_hook)
else "response_hook"
)
response_hook_kwargs = {response_hook_key: self.response_hook}
HTTPXClientInstrumentor().instrument(
tracer_provider=self.tracer_provider,
response_hook=self.response_hook,
**response_hook_kwargs,
)
client = self.create_client()
result = self.perform_request(self.URL, client=client)
Expand Down Expand Up @@ -823,9 +829,15 @@ def test_response_hook_sync_async_kwargs(self):
HTTPXClientInstrumentor().uninstrument()

def test_request_hook(self):
request_hook_key = (
"async_request_hook"
if asyncio.iscoroutinefunction(self.request_hook)
else "request_hook"
)
request_hook_kwargs = {request_hook_key: self.request_hook}
HTTPXClientInstrumentor().instrument(
tracer_provider=self.tracer_provider,
request_hook=self.request_hook,
**request_hook_kwargs,
)
client = self.create_client()
result = self.perform_request(self.URL, client=client)
Expand Down Expand Up @@ -1214,3 +1226,36 @@ def test_basic_multiple(self):
self.perform_request(self.URL, client=self.client)
self.perform_request(self.URL, client=self.client2)
self.assert_span(num_spans=2)

def test_async_response_hook_does_nothing_if_not_coroutine(self):
HTTPXClientInstrumentor().instrument(
tracer_provider=self.tracer_provider,
async_response_hook=_response_hook,
)
client = self.create_client()
result = self.perform_request(self.URL, client=client)

self.assertEqual(result.text, "Hello!")
span = self.assert_span()
self.assertEqual(
dict(span.attributes),
{
SpanAttributes.HTTP_METHOD: "GET",
SpanAttributes.HTTP_URL: self.URL,
SpanAttributes.HTTP_STATUS_CODE: 200,
},
)
HTTPXClientInstrumentor().uninstrument()

def test_async_request_hook_does_nothing_if_not_coroutine(self):
HTTPXClientInstrumentor().instrument(
tracer_provider=self.tracer_provider,
async_request_hook=_request_hook,
)
client = self.create_client()
result = self.perform_request(self.URL, client=client)

self.assertEqual(result.text, "Hello!")
span = self.assert_span()
self.assertEqual(span.name, "GET")
HTTPXClientInstrumentor().uninstrument()
emdneto marked this conversation as resolved.
Show resolved Hide resolved