Skip to content

Commit

Permalink
feat: Enable passing explicit urls to exclude from instrumentation in…
Browse files Browse the repository at this point in the history
… fastapi
  • Loading branch information
cdvv7788 committed May 2, 2021
1 parent cb35cc4 commit f728abb
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ Usage
FastAPIInstrumentor.instrument_app(app)
You can also pass the list of urls to exclude explicitly to the instrumentation call:

.. code-block:: python
from opentelemetry.util.http import ExcludeList
FastAPIInstrumentor.instrument_app(app, ExcludeList("client/.*/info,healthcheck"))
References
----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,19 @@ class FastAPIInstrumentor(BaseInstrumentor):
_original_fastapi = None

@staticmethod
def instrument_app(app: fastapi.FastAPI, tracer_provider=None):
"""Instrument an uninstrumented FastAPI application.
"""
def instrument_app(
app: fastapi.FastAPI,
tracer_provider=None,
excluded_urls=None,
):
"""Instrument an uninstrumented FastAPI application."""
if not getattr(app, "is_instrumented_by_opentelemetry", False):
if excluded_urls is None:
excluded_urls = _excluded_urls

app.add_middleware(
OpenTelemetryMiddleware,
excluded_urls=_excluded_urls,
excluded_urls=excluded_urls,
span_details_callback=_get_route_details,
tracer_provider=tracer_provider,
)
Expand All @@ -47,6 +53,7 @@ def instrument_app(app: fastapi.FastAPI, tracer_provider=None):
def _instrument(self, **kwargs):
self._original_fastapi = fastapi.FastAPI
_InstrumentedFastAPI._tracer_provider = kwargs.get("tracer_provider")
_InstrumentedFastAPI._excluded_urls = kwargs.get("excluded_urls")
fastapi.FastAPI = _InstrumentedFastAPI

def _uninstrument(self, **kwargs):
Expand All @@ -55,12 +62,18 @@ def _uninstrument(self, **kwargs):

class _InstrumentedFastAPI(fastapi.FastAPI):
_tracer_provider = None
_excluded_urls = None

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
excluded_urls = (
_InstrumentedFastAPI._excluded_urls
if _InstrumentedFastAPI._excluded_urls is not None
else _excluded_urls
)
self.add_middleware(
OpenTelemetryMiddleware,
excluded_urls=_excluded_urls,
excluded_urls=excluded_urls,
span_details_callback=_get_route_details,
tracer_provider=_InstrumentedFastAPI._tracer_provider,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from opentelemetry.sdk.resources import Resource
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.test_base import TestBase
from opentelemetry.util.http import get_excluded_urls
from opentelemetry.util.http import get_excluded_urls, ExcludeList


class TestFastAPIManualInstrumentation(TestBase):
Expand All @@ -31,6 +31,17 @@ def _create_app(self):
self._instrumentor.instrument_app(app)
return app

def _create_app_explicit_excluded_urls(self):
app = self._create_fastapi_app()
to_exclude = "/user/123,/foobar"
excluded_urls = [
excluded_url.strip() for excluded_url in to_exclude.split(",")
]
self._instrumentor.instrument_app(
app, excluded_urls=ExcludeList(excluded_urls)
)
return app

def setUp(self):
super().setUp()
self.env_patch = patch.dict(
Expand Down Expand Up @@ -84,6 +95,17 @@ def test_fastapi_excluded_urls(self):
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)

def test_fastapi_excluded_urls_not_env(self):
"""Ensure that given fastapi routes are excluded when passed explicitly (not in the environment)"""
app = self._create_app_explicit_excluded_urls()
client = TestClient(app)
client.get("/user/123")
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)
client.get("/foobar")
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)

@staticmethod
def _create_fastapi_app():
app = fastapi.FastAPI()
Expand Down Expand Up @@ -124,6 +146,24 @@ def _create_app(self):
self._instrumentor.instrument(tracer_provider=tracer_provider)
return self._create_fastapi_app()

def _create_app_explicit_excluded_urls(self):
resource = Resource.create({"key1": "value1", "key2": "value2"})
tracer_provider, exporter = self.create_tracer_provider(
resource=resource
)
self.memory_exporter = exporter

to_exclude = "/user/123,/foobar"
excluded_urls = [
excluded_url.strip() for excluded_url in to_exclude.split(",")
]
self._instrumentor.uninstrument() # Disable previous instrumentation (setUp)
self._instrumentor.instrument(
tracer_provider=tracer_provider,
excluded_urls=ExcludeList(excluded_urls),
)
return self._create_fastapi_app()

def test_request(self):
self._client.get("/foobar")
spans = self.memory_exporter.get_finished_spans()
Expand Down

0 comments on commit f728abb

Please sign in to comment.