opentelemetry-python-contrib
opentelemetry-python-contrib copied to clipboard
Issue: ImportError when using OpenTelemetry ASGI Instrumentation in FastAPI
Describe your environment
name: opentelemetry channels:
- conda-forge dependencies:
- _libgcc_mutex=0.1=conda_forge
- _openmp_mutex=4.5=2_gnu
- bzip2=1.0.8=hd590300_5
- ca-certificates=2024.6.2=hbcca054_0
- ld_impl_linux-64=2.40=hf3520f5_7
- libffi=3.4.2=h7f98852_5
- libgcc-ng=13.2.0=h77fa898_13
- libgomp=13.2.0=h77fa898_13
- libnsl=2.0.1=hd590300_0
- libsqlite=3.46.0=hde9e2c9_0
- libuuid=2.38.1=h0b41bf4_0
- libxcrypt=4.4.36=hd590300_1
- libzlib=1.3.1=h4ab18f5_1
- ncurses=6.5=h59595ed_0
- openssl=3.3.1=h4ab18f5_1
- pip=24.0=pyhd8ed1ab_0
- python=3.9.19=h0755675_0_cpython
- readline=8.2=h8228510_1
- setuptools=70.1.1=pyhd8ed1ab_0
- tk=8.6.13=noxft_h4845f30_101
- tzdata=2024a=h0c530f3_0
- wheel=0.43.0=pyhd8ed1ab_1
- xz=5.2.6=h166bdaf_0
- pip:
- annotated-types==0.7.0
- anyio==4.4.0
- asgiref==3.7.2
- azure-core==1.30.2
- azure-core-tracing-opentelemetry==1.0.0b11
- azure-monitor-opentelemetry==1.6.0
- azure-monitor-opentelemetry-exporter==1.0.0b27
- blinker==1.8.2
- certifi==2024.6.2
- charset-normalizer==3.3.2
- click==8.1.7
- deprecated==1.2.14
- dnspython==2.6.1
- email-validator==2.2.0
- exceptiongroup==1.2.1
- fastapi==0.111.0
- fastapi-cli==0.0.4
- fixedint==0.1.6
- flask==3.0.3
- h11==0.14.0
- httpcore==1.0.5
- httptools==0.6.1
- httpx==0.27.0
- idna==3.7
- importlib-metadata==7.1.0
- isodate==0.6.1
- itsdangerous==2.2.0
- jinja2==3.1.4
- markdown-it-py==3.0.0
- markupsafe==2.1.5
- mdurl==0.1.2
- msrest==0.7.1
- oauthlib==3.2.2
- opentelemetry-api==1.25.0
- opentelemetry-instrumentation==0.46b0
- opentelemetry-instrumentation-asgi==0.46b0
- opentelemetry-instrumentation-dbapi==0.46b0
- opentelemetry-instrumentation-django==0.46b0
- opentelemetry-instrumentation-fastapi==0.46b0
- opentelemetry-instrumentation-flask==0.46b0
- opentelemetry-instrumentation-psycopg2==0.46b0
- opentelemetry-instrumentation-requests==0.46b0
- opentelemetry-instrumentation-urllib==0.46b0
- opentelemetry-instrumentation-urllib3==0.46b0
- opentelemetry-instrumentation-wsgi==0.46b0
- opentelemetry-resource-detector-azure==0.1.5
- opentelemetry-sdk==1.25.0
- opentelemetry-semantic-conventions==0.46b0
- opentelemetry-test-utils==0.46b0
- opentelemetry-util-http==0.46b0
- orjson==3.10.5
- packaging==24.1
- psutil==5.9.8
- pydantic==2.7.4
- pydantic-core==2.18.4
- pygments==2.18.0
- python-dotenv==1.0.1
- python-multipart==0.0.9
- pyyaml==6.0.1
- requests==2.32.3
- requests-oauthlib==2.0.0
- rich==13.7.1
- shellingham==1.5.4
- six==1.16.0
- sniffio==1.3.1
- starlette==0.37.2
- typer==0.12.3
- typing-extensions==4.12.2
- ujson==5.10.0
- urllib3==2.2.2
- uvicorn==0.30.1
- uvloop==0.19.0
- watchfiles==0.22.0
- websockets==12.0
- werkzeug==3.0.3
- wrapt==1.16.0
- zipp==3.19.2 prefix: /home/amcg809/mambaforge/envs/opentelemetry
What happened?
What happened? When attempting to use the opentelemetry-instrumentation-asgi package in a FastAPI application, an ImportError occurs due to missing imports for ClientRequestHook, ClientResponseHook, and ServerRequestHook.
https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/init.py
Steps to Reproduce
Run the file https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/init.py
with the package pip install fastapi opentelemetry-instrumentation-asgi
Expected Result
The application should run without any import errors, and the OpenTelemetry ASGI middleware should be applied to the FastAPI application.
Actual Result
ImportError: cannot import name 'ClientRequestHook' from 'opentelemetry.instrumentation.asgi'
Additional context
Additional context The ClientRequestHook, ClientResponseHook, and ServerRequestHook are not available in the opentelemetry-instrumentation-asgi package, causing the import error.
Solution To resolve this issue, you can remove the imports for ClientRequestHook, ClientResponseHook, and ServerRequestHook and adjust the middleware setup accordingly. Here is the updated code:
// ... existing code ... from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware // ... existing code ...
class FastAPIInstrumentor(BaseInstrumentor): // ... existing code ...
@staticmethod
def instrument_app(
app: fastapi.FastAPI,
server_request_hook=None,
client_request_hook=None,
client_response_hook=None,
tracer_provider=None,
meter_provider=None,
excluded_urls=None,
):
"""Instrument an uninstrumented FastAPI application."""
// ... existing code ...
// ... existing code ...
def _instrument(self, **kwargs):
self._original_fastapi = fastapi.FastAPI
_InstrumentedFastAPI._tracer_provider = kwargs.get("tracer_provider")
_InstrumentedFastAPI._server_request_hook = kwargs.get(
"server_request_hook"
)
_InstrumentedFastAPI._client_request_hook = kwargs.get(
"client_request_hook"
)
_InstrumentedFastAPI._client_response_hook = kwargs.get(
"client_response_hook"
)
_excluded_urls = kwargs.get("excluded_urls")
_InstrumentedFastAPI._excluded_urls = (
_excluded_urls_from_env
if _excluded_urls is None
else parse_excluded_urls(_excluded_urls)
)
_InstrumentedFastAPI._meter_provider = kwargs.get("meter_provider")
fastapi.FastAPI = _InstrumentedFastAPI
// ... existing code ...
class _InstrumentedFastAPI(fastapi.FastAPI): _tracer_provider = None _meter_provider = None _excluded_urls = None _server_request_hook = None _client_request_hook = None _client_response_hook = None _instrumented_fastapi_apps = set()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
tracer = get_tracer(
__name__,
__version__,
_InstrumentedFastAPI._tracer_provider,
schema_url="https://opentelemetry.io/schemas/1.11.0",
)
meter = get_meter(
__name__,
__version__,
_InstrumentedFastAPI._meter_provider,
schema_url="https://opentelemetry.io/schemas/1.11.0",
)
self.add_middleware(
OpenTelemetryMiddleware,
excluded_urls=_InstrumentedFastAPI._excluded_urls,
default_span_details=_get_default_span_details,
server_request_hook=_InstrumentedFastAPI._server_request_hook,
client_request_hook=_InstrumentedFastAPI._client_request_hook,
client_response_hook=_InstrumentedFastAPI._client_response_hook,
tracer=tracer,
meter=meter,
)
self._is_instrumented_by_opentelemetry = True
_InstrumentedFastAPI._instrumented_fastapi_apps.add(self)
// ... existing code ...
Explanation
- Import Change: Removed the imports for ClientRequestHook, ClientResponseHook, and ServerRequestHook.
- Method Signatures: Updated the method signatures to remove the specific hook types.
- Middleware Setup: Adjusted the middleware setup to use the OpenTelemetryMiddleware directly without the removed hooks.
Would you like to implement a fix?
Yes