diff --git a/CHANGELOG.md b/CHANGELOG.md index 0312ed9764..2571db8503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python-contrib/compare/v0.16b1...HEAD) ### Added +- Remove Configuration + ([#285](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/285)) - `opentelemetry-instrumentation-sqlalchemy` Ensure spans have kind set to "CLIENT" ([#278](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/278)) - `opentelemetry-instrumentation-celery` Add support for Celery version 5.x @@ -41,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#273](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/273)) ### Changed +- Remove Configuration + ([#285](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/285)) - `opentelemetry-instrumentation-asgi`, `opentelemetry-instrumentation-wsgi` Return `None` for `CarrierGetter` if key not found ([#1374](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/233)) - `opentelemetry-instrumentation-grpc` Comply with updated spec, rework tests diff --git a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py index 58dee0ba7f..2eb88001ae 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py @@ -84,8 +84,6 @@ def _instrument(self, **kwargs): # For exemple EC2 uses AWSQueryConnection and S3 uses # AWSAuthConnection - # FIXME should the tracer provider be accessed via Configuration - # instead? # pylint: disable=attribute-defined-outside-init self._tracer = get_tracer( __name__, __version__, kwargs.get("tracer_provider") diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py index 26e21a1f7f..c4101ef181 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py @@ -13,10 +13,10 @@ # limitations under the License. from logging import getLogger +from os import environ from django.conf import settings -from opentelemetry.configuration import Configuration from opentelemetry.instrumentation.django.middleware import _DjangoMiddleware from opentelemetry.instrumentation.django.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -43,11 +43,7 @@ def _instrument(self, **kwargs): # FIXME this is probably a pattern that will show up in the rest of the # ext. Find a better way of implementing this. - # FIXME Probably the evaluation of strings into boolean values can be - # built inside the Configuration class itself with the magic method - # __bool__ - - if Configuration().DJANGO_INSTRUMENT is False: + if environ.get("OTEL_PYTHON_DJANGO_INSTRUMENT") == "False": return # This can not be solved, but is an inherent problem of this approach: diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py index edb585cdb4..6f6b16fe29 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py @@ -12,12 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -import time +from time import time from logging import getLogger +from os import environ +from re import compile as re_compile, search from django.conf import settings -from opentelemetry.configuration import Configuration from opentelemetry.context import attach, detach from opentelemetry.instrumentation.django.version import __version__ from opentelemetry.instrumentation.utils import extract_attributes_from_object @@ -51,6 +52,46 @@ ] +class _ExcludeList: + """Class to exclude certain paths (given as a list of regexes) from tracing requests""" + + def __init__(self, excluded_urls): + self._excluded_urls = excluded_urls + if self._excluded_urls: + self._regex = re_compile("|".join(excluded_urls)) + + def url_disabled(self, url: str) -> bool: + return bool(self._excluded_urls and search(self._regex, url)) + +_root = r"OTEL_PYTHON_{}" + + +def _get_traced_request_attrs(): + traced_request_attrs = environ.get( + _root.format("DJANGO_TRACED_REQUEST_ATTRS"), [] + ) + + if traced_request_attrs: + traced_request_attrs = [ + traced_request_attr.strip() + for traced_request_attr in traced_request_attrs.split(",") + ] + + return traced_request_attrs + + +def _get_excluded_urls(): + excluded_urls = environ.get(_root.format("DJANGO_EXCLUDED_URLS"), []) + + if excluded_urls: + excluded_urls = [ + excluded_url.strip() + for excluded_url in excluded_urls.split(",") + ] + + return _ExcludeList(excluded_urls) + + class _DjangoMiddleware(MiddlewareMixin): """Django Middleware for OpenTelemetry""" @@ -61,9 +102,8 @@ class _DjangoMiddleware(MiddlewareMixin): _environ_span_key = "opentelemetry-instrumentor-django.span_key" _environ_exception_key = "opentelemetry-instrumentor-django.exception_key" - _excluded_urls = Configuration()._excluded_urls("django") - - _traced_request_attrs = Configuration()._traced_request_attrs("django") + _traced_request_attrs = _get_traced_request_attrs() + _excluded_urls = _get_excluded_urls() @staticmethod def _get_span_name(request): @@ -111,7 +151,7 @@ def process_request(self, request): return # pylint:disable=W0212 - request._otel_start_time = time.time() + request._otel_start_time = time() environ = request.META @@ -215,7 +255,7 @@ def process_response(self, request, response): if metric_recorder is not None: # pylint:disable=W0212 metric_recorder.record_server_duration_range( - request._otel_start_time, time.time(), request._otel_labels + request._otel_start_time, time(), request._otel_labels ) except Exception as ex: # pylint: disable=W0703 _logger.warning("Error recording duration metrics: %s", ex) diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index b75a8cd0e9..3e634620f3 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -21,8 +21,10 @@ from django.test import Client from django.test.utils import setup_test_environment, teardown_test_environment -from opentelemetry.configuration import Configuration from opentelemetry.instrumentation.django import DjangoInstrumentor +from opentelemetry.instrumentation.django.middleware import ( + _get_excluded_urls, _get_traced_request_attrs +) from opentelemetry.sdk.util import get_dict_as_key from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -64,7 +66,6 @@ def setUp(self): super().setUp() setup_test_environment() _django_instrumentor.instrument() - Configuration._reset() # pylint: disable=protected-access self.env_patch = patch.dict( "os.environ", { @@ -75,11 +76,11 @@ def setUp(self): self.env_patch.start() self.exclude_patch = patch( "opentelemetry.instrumentation.django.middleware._DjangoMiddleware._excluded_urls", - Configuration()._excluded_urls("django"), + _get_excluded_urls(), ) self.traced_patch = patch( "opentelemetry.instrumentation.django.middleware._DjangoMiddleware._traced_request_attrs", - Configuration()._traced_request_attrs("django"), + _get_traced_request_attrs(), ) self.exclude_patch.start() self.traced_patch.start() diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index e9b1f16800..9d88b9f1e8 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -43,14 +43,15 @@ def on_get(self, req, resp): --- """ -import sys +from sys import exc_info from logging import getLogger +from re import compile as re_compile, search +from os import environ import falcon import opentelemetry.instrumentation.wsgi as otel_wsgi -from opentelemetry import configuration, context, propagators, trace -from opentelemetry.configuration import Configuration +from opentelemetry import context, propagators, trace from opentelemetry.instrumentation.falcon.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import ( @@ -68,8 +69,49 @@ def on_get(self, req, resp): _ENVIRON_TOKEN = "opentelemetry-falcon.token" _ENVIRON_EXC = "opentelemetry-falcon.exc" -cfg = configuration.Configuration() -_excluded_urls = cfg._excluded_urls("falcon") + +class _ExcludeList: + """Class to exclude certain paths (given as a list of regexes) from tracing requests""" + + def __init__(self, excluded_urls): + self._excluded_urls = excluded_urls + if self._excluded_urls: + self._regex = re_compile("|".join(excluded_urls)) + + def url_disabled(self, url: str) -> bool: + return bool(self._excluded_urls and search(self._regex, url)) + +_root = r"OTEL_PYTHON_{}" + + +def _get_traced_request_attrs(): + traced_request_attrs = environ.get( + _root.format("FALCON_TRACED_REQUEST_ATTRS"), [] + ) + + if traced_request_attrs: + traced_request_attrs = [ + traced_request_attr.strip() + for traced_request_attr in traced_request_attrs.split(",") + ] + + return traced_request_attrs + + +def _get_excluded_urls(): + excluded_urls = environ.get(_root.format("FALCON_EXCLUDED_URLS"), []) + + if excluded_urls: + excluded_urls = [ + excluded_url.strip() + for excluded_url in excluded_urls.split(",") + ] + + return _ExcludeList(excluded_urls) + + +_excluded_urls = _get_excluded_urls() +_traced_request_attrs = _get_traced_request_attrs() class FalconInstrumentor(BaseInstrumentor): @@ -149,7 +191,7 @@ class _TraceMiddleware: def __init__(self, tracer=None, traced_request_attrs=None): self.tracer = tracer - self._traced_request_attrs = cfg._traced_request_attrs("falcon") + self._traced_request_attrs = _traced_request_attrs def process_request(self, req, resp): span = req.env.get(_ENVIRON_SPAN_KEY) @@ -186,7 +228,7 @@ def process_response( status = "404" reason = "NotFound" - exc_type, exc, _ = sys.exc_info() + exc_type, exc, _ = exc_info() if exc_type and not req_succeeded: if "HTTPNotFound" in exc_type.__name__: status = "404" diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index 616db2837f..73baf83415 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -16,8 +16,9 @@ from falcon import testing -from opentelemetry.configuration import Configuration -from opentelemetry.instrumentation.falcon import FalconInstrumentor +from opentelemetry.instrumentation.falcon import ( + FalconInstrumentor, _get_excluded_urls, _get_traced_request_attrs +) from opentelemetry.test.test_base import TestBase from opentelemetry.trace.status import StatusCode @@ -30,7 +31,6 @@ def setUp(self): FalconInstrumentor().instrument() self.app = make_app() # pylint: disable=protected-access - Configuration()._reset() self.env_patch = patch.dict( "os.environ", { @@ -41,7 +41,7 @@ def setUp(self): self.env_patch.start() self.exclude_patch = patch( "opentelemetry.instrumentation.falcon._excluded_urls", - Configuration()._excluded_urls("falcon"), + _get_excluded_urls(), ) middleware = self.app._middleware[0][ # pylint:disable=W0212 0 @@ -49,7 +49,7 @@ def setUp(self): self.traced_patch = patch.object( middleware, "_traced_request_attrs", - Configuration()._traced_request_attrs("falcon"), + _get_traced_request_attrs(), ) self.exclude_patch.start() self.traced_patch.start() diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py index b938464065..02e9fd46d4 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py @@ -11,17 +11,43 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Optional -import fastapi +from re import compile as re_compile, search +from os import environ + from starlette.routing import Match +import fastapi -from opentelemetry.configuration import Configuration from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware from opentelemetry.instrumentation.fastapi.version import __version__ # noqa from opentelemetry.instrumentation.instrumentor import BaseInstrumentor -_excluded_urls = Configuration()._excluded_urls("fastapi") + +class _ExcludeList: + """Class to exclude certain paths (given as a list of regexes) from tracing requests""" + + def __init__(self, excluded_urls): + self._excluded_urls = excluded_urls + if self._excluded_urls: + self._regex = re_compile("|".join(excluded_urls)) + + def url_disabled(self, url: str) -> bool: + return bool(self._excluded_urls and search(self._regex, url)) + + +def _get_excluded_urls(): + excluded_urls = environ.get("OTEL_PYTHON_FASTAPI_EXCLUDED_URLS", []) + + if excluded_urls: + excluded_urls = [ + excluded_url.strip() + for excluded_url in excluded_urls.split(",") + ] + + return _ExcludeList(excluded_urls) + + +_excluded_urls = _get_excluded_urls() class FastAPIInstrumentor(BaseInstrumentor): diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py index 6d5a1b1808..13d90e410f 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py @@ -19,7 +19,6 @@ from fastapi.testclient import TestClient import opentelemetry.instrumentation.fastapi as otel_fastapi -from opentelemetry.configuration import Configuration from opentelemetry.test.test_base import TestBase @@ -31,7 +30,6 @@ def _create_app(self): def setUp(self): super().setUp() - Configuration()._reset() self.env_patch = patch.dict( "os.environ", {"OTEL_PYTHON_FASTAPI_EXCLUDED_URLS": "/exclude/123,healthzz"}, @@ -39,7 +37,7 @@ def setUp(self): self.env_patch.start() self.exclude_patch = patch( "opentelemetry.instrumentation.fastapi._excluded_urls", - Configuration()._excluded_urls("fastapi"), + otel_fastapi._get_excluded_urls(), ) self.exclude_patch.start() self._instrumentor = otel_fastapi.FastAPIInstrumentor() diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py index b5045f3a72..2d883e46d8 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -48,11 +48,13 @@ def hello(): """ from logging import getLogger +from re import compile as re_compile, search +from os import environ import flask import opentelemetry.instrumentation.wsgi as otel_wsgi -from opentelemetry import configuration, context, propagators, trace +from opentelemetry import context, propagators, trace from opentelemetry.instrumentation.flask.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.util import time_ns @@ -65,7 +67,31 @@ def hello(): _ENVIRON_TOKEN = "opentelemetry-flask.token" -_excluded_urls = configuration.Configuration()._excluded_urls("flask") +class _ExcludeList: + """Class to exclude certain paths (given as a list of regexes) from tracing requests""" + + def __init__(self, excluded_urls): + self._excluded_urls = excluded_urls + if self._excluded_urls: + self._regex = re_compile("|".join(excluded_urls)) + + def url_disabled(self, url: str) -> bool: + return bool(self._excluded_urls and search(self._regex, url)) + + +def _get_excluded_urls(): + excluded_urls = environ.get("OTEL_PYTHON_FLASK_EXCLUDED_URLS", []) + + if excluded_urls: + excluded_urls = [ + excluded_url.strip() + for excluded_url in excluded_urls.split(",") + ] + + return _ExcludeList(excluded_urls) + + +_excluded_urls = _get_excluded_urls() def get_default_span_name(): diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py index c2bc646e1b..c0e1e339cb 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py @@ -15,13 +15,10 @@ from werkzeug.test import Client from werkzeug.wrappers import BaseResponse -from opentelemetry.configuration import Configuration - class InstrumentationTest: def setUp(self): # pylint: disable=invalid-name super().setUp() # pylint: disable=no-member - Configuration._reset() # pylint: disable=protected-access @staticmethod def _hello_endpoint(helloid): diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index 495b4a739a..92e95105a3 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py @@ -17,8 +17,9 @@ from flask import Flask, request from opentelemetry import trace -from opentelemetry.configuration import Configuration -from opentelemetry.instrumentation.flask import FlaskInstrumentor +from opentelemetry.instrumentation.flask import ( + FlaskInstrumentor, _get_excluded_urls +) from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -63,7 +64,7 @@ def setUp(self): self.env_patch.start() self.exclude_patch = patch( "opentelemetry.instrumentation.flask._excluded_urls", - Configuration()._excluded_urls("flask"), + _get_excluded_urls(), ) self.exclude_patch.start() diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py index 40894e2c62..495c238943 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py @@ -1,4 +1,6 @@ from logging import getLogger +from re import compile as re_compile, search +from os import environ from pyramid.events import BeforeTraversal from pyramid.httpexceptions import HTTPException @@ -6,7 +8,7 @@ from pyramid.tweens import EXCVIEW import opentelemetry.instrumentation.wsgi as otel_wsgi -from opentelemetry import configuration, context, propagators, trace +from opentelemetry import context, propagators, trace from opentelemetry.instrumentation.pyramid.version import __version__ from opentelemetry.util import time_ns @@ -22,7 +24,30 @@ _logger = getLogger(__name__) -_excluded_urls = configuration.Configuration()._excluded_urls("pyramid") +class _ExcludeList: + """Class to exclude certain paths (given as a list of regexes) from tracing requests""" + + def __init__(self, excluded_urls): + self._excluded_urls = excluded_urls + if self._excluded_urls: + self._regex = re_compile("|".join(excluded_urls)) + + def url_disabled(self, url: str) -> bool: + return bool(self._excluded_urls and search(self._regex, url)) + + +def _get_excluded_urls(): + excluded_urls = environ.get("OTEL_PYTHON_PYRAMID_EXCLUDED_URLS", []) + + if excluded_urls: + excluded_urls = [ + excluded_url.strip() + for excluded_url in excluded_urls.split(",") + ] + + return _ExcludeList(excluded_urls) + +_excluded_urls = _get_excluded_urls() def includeme(config): diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/pyramid_base_test.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/pyramid_base_test.py index 21a6a1ab95..71269ad5be 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/pyramid_base_test.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/pyramid_base_test.py @@ -17,13 +17,10 @@ from werkzeug.test import Client from werkzeug.wrappers import BaseResponse -from opentelemetry.configuration import Configuration - class InstrumentationTest: def setUp(self): # pylint: disable=invalid-name super().setUp() # pylint: disable=no-member - Configuration._reset() # pylint: disable=protected-access @staticmethod def _hello_endpoint(request): diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py index e5bbcb056b..6dfa05fb0c 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py @@ -17,8 +17,8 @@ from pyramid.config import Configurator from opentelemetry import trace -from opentelemetry.configuration import Configuration from opentelemetry.instrumentation.pyramid import PyramidInstrumentor +from opentelemetry.instrumentation.pyramid.callbacks import _get_excluded_urls from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -63,7 +63,7 @@ def setUp(self): self.env_patch.start() self.exclude_patch = patch( "opentelemetry.instrumentation.pyramid.callbacks._excluded_urls", - Configuration()._excluded_urls("pyramid"), + _get_excluded_urls(), ) self.exclude_patch.start() diff --git a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py index 1725123b6d..2782c1bad4 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py @@ -11,17 +11,43 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Optional + +from re import compile as re_compile, search +from os import environ from starlette import applications from starlette.routing import Match -from opentelemetry.configuration import Configuration from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.starlette.version import __version__ # noqa -_excluded_urls = Configuration()._excluded_urls("starlette") + +class _ExcludeList: + """Class to exclude certain paths (given as a list of regexes) from tracing requests""" + + def __init__(self, excluded_urls): + self._excluded_urls = excluded_urls + if self._excluded_urls: + self._regex = re_compile("|".join(excluded_urls)) + + def url_disabled(self, url: str) -> bool: + return bool(self._excluded_urls and search(self._regex, url)) + + +def _get_excluded_urls(): + excluded_urls = environ.get("OTEL_PYTHON_STARLETTE_EXCLUDED_URLS", []) + + if excluded_urls: + excluded_urls = [ + excluded_url.strip() + for excluded_url in excluded_urls.split(",") + ] + + return _ExcludeList(excluded_urls) + + +_excluded_urls = _get_excluded_urls() class StarletteInstrumentor(BaseInstrumentor): diff --git a/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py b/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py index 1729741363..3df7896d12 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py @@ -21,7 +21,6 @@ from starlette.testclient import TestClient import opentelemetry.instrumentation.starlette as otel_starlette -from opentelemetry.configuration import Configuration from opentelemetry.test.test_base import TestBase @@ -33,7 +32,6 @@ def _create_app(self): def setUp(self): super().setUp() - Configuration()._reset() self.env_patch = patch.dict( "os.environ", {"OTEL_PYTHON_STARLETTE_EXCLUDED_URLS": "/exclude/123,healthzz"}, @@ -41,7 +39,7 @@ def setUp(self): self.env_patch.start() self.exclude_patch = patch( "opentelemetry.instrumentation.starlette._excluded_urls", - Configuration()._excluded_urls("starlette"), + otel_starlette._get_excluded_urls(), ) self.exclude_patch.start() self._instrumentor = otel_starlette.StarletteInstrumentor() diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py index d825fbb71b..8525000c1b 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -35,18 +35,17 @@ def get(self): tornado.ioloop.IOLoop.current().start() """ -import inspect -import typing from collections import namedtuple -from functools import partial, wraps +from functools import partial from logging import getLogger +from os import environ +from re import compile as re_compile, search import tornado.web import wrapt -from tornado.routing import Rule from wrapt import wrap_function_wrapper -from opentelemetry import configuration, context, propagators, trace +from opentelemetry import context, propagators, trace from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.tornado.version import __version__ from opentelemetry.instrumentation.utils import ( @@ -65,10 +64,50 @@ def get(self): _HANDLER_CONTEXT_KEY = "_otel_trace_context_key" _OTEL_PATCHED_KEY = "_otel_patched_key" -cfg = configuration.Configuration() -_excluded_urls = cfg._excluded_urls("tornado") -_traced_attrs = cfg._traced_request_attrs("tornado") +class _ExcludeList: + """Class to exclude certain paths (given as a list of regexes) from tracing requests""" + + def __init__(self, excluded_urls): + self._excluded_urls = excluded_urls + if self._excluded_urls: + self._regex = re_compile("|".join(excluded_urls)) + + def url_disabled(self, url: str) -> bool: + return bool(self._excluded_urls and search(self._regex, url)) + + +_root = r"OTEL_PYTHON_{}" + + +def _get_traced_request_attrs(): + traced_request_attrs = environ.get( + _root.format("TORNADO_TRACED_REQUEST_ATTRS"), [] + ) + + if traced_request_attrs: + traced_request_attrs = [ + traced_request_attr.strip() + for traced_request_attr in traced_request_attrs.split(",") + ] + + return traced_request_attrs + + +def _get_excluded_urls(): + excluded_urls = environ.get(_root.format("TORNADO_EXCLUDED_URLS"), []) + + if excluded_urls: + excluded_urls = [ + excluded_url.strip() + for excluded_url in excluded_urls.split(",") + ] + + return _ExcludeList(excluded_urls) + + +_excluded_urls = _get_excluded_urls() +_traced_request_attrs = _get_traced_request_attrs() carrier_getter = DictGetter() @@ -187,7 +226,9 @@ def _get_attributes_from_request(request): if request.remote_ip: attrs["net.peer.ip"] = request.remote_ip - return extract_attributes_from_object(request, _traced_attrs, attrs) + return extract_attributes_from_object( + request, _traced_request_attrs, attrs + ) def _get_operation_name(handler, request): diff --git a/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py b/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py index 21002c83cd..5159f8ab35 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py @@ -18,11 +18,12 @@ from tornado.testing import AsyncHTTPTestCase from opentelemetry import trace -from opentelemetry.configuration import Configuration from opentelemetry.instrumentation.tornado import ( TornadoInstrumentor, patch_handler_class, unpatch_handler_class, + _get_traced_request_attrs, + _get_excluded_urls, ) from opentelemetry.test.test_base import TestBase from opentelemetry.trace import SpanKind @@ -45,7 +46,6 @@ def setUp(self): TornadoInstrumentor().instrument() super().setUp() # pylint: disable=protected-access - Configuration()._reset() self.env_patch = patch.dict( "os.environ", { @@ -56,11 +56,11 @@ def setUp(self): self.env_patch.start() self.exclude_patch = patch( "opentelemetry.instrumentation.tornado._excluded_urls", - Configuration()._excluded_urls("tornado"), + _get_excluded_urls(), ) self.traced_patch = patch( - "opentelemetry.instrumentation.tornado._traced_attrs", - Configuration()._traced_request_attrs("tornado"), + "opentelemetry.instrumentation.tornado._traced_request_attrs", + _get_traced_request_attrs(), ) self.exclude_patch.start() self.traced_patch.start()