diff --git a/instana/instrumentation/fastapi_inst.py b/instana/instrumentation/fastapi_inst.py index 5c15139b..92fa93b2 100644 --- a/instana/instrumentation/fastapi_inst.py +++ b/instana/instrumentation/fastapi_inst.py @@ -13,10 +13,31 @@ from ..util import running_in_gunicorn from .asgi import InstanaASGIMiddleware from starlette.middleware import Middleware + from fastapi import HTTPException + from fastapi.exception_handlers import http_exception_handler + + from instana.singletons import async_tracer if hasattr(fastapi, '__version__') and \ (LooseVersion(fastapi.__version__) >= LooseVersion('0.51.0')): + async def instana_exception_handler(request, exc): + """ + We capture FastAPI HTTPException, log the error and pass it on + to the default exception handler. + """ + try: + span = async_tracer.active_span + + if span is not None: + if hasattr(exc, 'detail'): + span.set_tag('http.error', exc.detail) + span.set_tag('http.status_code', exc.status_code) + except Exception: + logger.debug("FastAPI instana_exception_handler: ", exc_info=True) + + return await http_exception_handler(request, exc) + @wrapt.patch_function_wrapper('fastapi.applications', 'FastAPI.__init__') def init_with_instana(wrapped, instance, args, kwargs): middleware = kwargs.get('middleware') @@ -25,6 +46,13 @@ def init_with_instana(wrapped, instance, args, kwargs): elif isinstance(middleware, list): middleware.append(Middleware(InstanaASGIMiddleware)) + exception_handlers = kwargs.get('exception_handlers') + if exception_handlers is None: + kwargs['exception_handlers'] = dict() + + if isinstance(kwargs['exception_handlers'], dict): + kwargs['exception_handlers'][HTTPException] = instana_exception_handler + return wrapped(*args, **kwargs) logger.debug("Instrumenting FastAPI") diff --git a/setup.py b/setup.py index 615632fe..f2530a86 100644 --- a/setup.py +++ b/setup.py @@ -79,14 +79,14 @@ def check_setuptools(): 'nose>=1.0', 'pyramid>=1.2', 'pytest>=4.6', - 'urllib3[secure]>=1.15' + 'urllib3[secure]>=1.15,<=1.25.11' ], 'test-cassandra': [ 'cassandra-driver==3.20.2', 'mock>=2.0.0', 'nose>=1.0', 'pytest>=4.6', - 'urllib3[secure]>=1.15' + 'urllib3[secure]>=1.15<=1.25.11' ], 'test-couchbase': [ 'couchbase==2.5.9', @@ -122,7 +122,7 @@ def check_setuptools(): 'suds-jurko>=0.6', 'tornado>=4.5.3,<6.0', 'uvicorn>=0.12.2;python_version>="3.6"', - 'urllib3[secure]>=1.15' + 'urllib3[secure]>=1.15,<=1.25.11' ], }, test_suite='nose.collector',