open-telemetry / open-telemetry/opentelemetry-python-contrib
Issue: ImportError when using OpenTelemetry ASGI Instrumentation in FastAPI
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 1.1k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 16
Description
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.
Steps to Reproduce
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/init.py and reproduce the import using pip install fastapi opentelemetry-instrumentation-asgi. Check the imported ASGI symbols and middleware setup; done means a FastAPI application starts without the ImportError and the OpenTelemetry ASGI middleware is applied.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- fastapi, python
- Domain
- backend, observability
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100