diff --git a/opentelemetry-instrumentation/README.rst b/opentelemetry-instrumentation/README.rst index 18b31f428fa..6f74d2232f7 100644 --- a/opentelemetry-instrumentation/README.rst +++ b/opentelemetry-instrumentation/README.rst @@ -16,14 +16,6 @@ Installation This package provides a couple of commands that help automatically instruments a program: -.. note:: - You need to install a distro package to get auto instrumentation working. The ``opentelemetry-distro`` - package contains the default distro and automatically configures some of the common options for users. - For more info about ``opentelemetry-distro`` check `here `__ - :: - - pip install opentelemetry-distro[otlp] - opentelemetry-bootstrap ----------------------- diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index d89b60ec56c..2ebb891dc27 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -12,124 +12,54 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys + from logging import getLogger -from os import environ, path +from os import environ from os.path import abspath, dirname, pathsep from re import sub from pkg_resources import iter_entry_points -from opentelemetry.environment_variables import ( - OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, -) from opentelemetry.instrumentation.dependencies import ( get_dist_dependency_conflicts, ) -from opentelemetry.instrumentation.distro import BaseDistro, DefaultDistro - -logger = getLogger(__file__) - +from opentelemetry.instrumentation.environment_variables import ( + OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, +) -def _load_distros() -> BaseDistro: - for entry_point in iter_entry_points("opentelemetry_distro"): - try: - distro = entry_point.load()() - if not isinstance(distro, BaseDistro): - logger.debug( - "%s is not an OpenTelemetry Distro. Skipping", - entry_point.name, - ) - continue - logger.debug( - "Distribution %s will be configured", entry_point.name - ) - return distro - except Exception as exc: # pylint: disable=broad-except - logger.exception( - "Distribution %s configuration failed", entry_point.name - ) - raise exc - return DefaultDistro() +_logger = getLogger(__file__) -def _load_instrumentors(distro): - package_to_exclude = environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, []) - if isinstance(package_to_exclude, str): - package_to_exclude = package_to_exclude.split(",") - # to handle users entering "requests , flask" or "requests, flask" with spaces - package_to_exclude = [x.strip() for x in package_to_exclude] +for entry_point in iter_entry_points("opentelemetry-pre-instrument"): + entry_point.load()() - for entry_point in iter_entry_points("opentelemetry_instrumentor"): - if entry_point.name in package_to_exclude: - logger.debug( - "Instrumentation skipped for library %s", entry_point.name - ) - continue +try: + disabled_instrumentations = set( + environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, "").split() + ) - try: - conflict = get_dist_dependency_conflicts(entry_point.dist) - if conflict: - logger.debug( - "Skipping instrumentation %s: %s", - entry_point.name, - conflict, - ) - continue + for entry_point in iter_entry_points("opentelemetry-instrumentor"): + if entry_point.name in disabled_instrumentations: + _logger.debug("Instrumentation skipped for %s", entry_point.name) - # tell instrumentation to not run dep checks again as we already did it above - distro.load_instrumentor(entry_point, skip_dep_check=True) - logger.debug("Instrumented %s", entry_point.name) - except Exception as exc: # pylint: disable=broad-except - logger.exception("Instrumenting of %s failed", entry_point.name) - raise exc + conflicts = get_dist_dependency_conflicts(entry_point.dist) + if conflicts is not None: -def _load_configurators(): - configured = None - for entry_point in iter_entry_points("opentelemetry_configurator"): - if configured is not None: - logger.warning( - "Configuration of %s not loaded, %s already loaded", + _logger.debug( + "Skipping instrumentation %s: %s", entry_point.name, - configured, + conflicts, ) - continue - try: - entry_point.load()().configure() # type: ignore - configured = entry_point.name - except Exception as exc: # pylint: disable=broad-except - logger.exception("Configuration of %s failed", entry_point.name) - raise exc - - -def initialize(): - try: - distro = _load_distros() - distro.configure() - _load_configurators() - _load_instrumentors(distro) - except Exception: # pylint: disable=broad-except - logger.exception("Failed to auto initialize opentelemetry") - finally: - environ["PYTHONPATH"] = sub( - r"{}{}?".format(dirname(abspath(__file__)), pathsep), - "", - environ["PYTHONPATH"], - ) - - -if ( - hasattr(sys, "argv") - and sys.argv[0].split(path.sep)[-1] == "celery" - and "worker" in sys.argv[1:] -): - from celery.signals import worker_process_init # pylint:disable=E0401 - @worker_process_init.connect(weak=False) - def init_celery(*args, **kwargs): - initialize() + entry_point.load().instrument(skip_dep_check=True) +finally: + environ["PYTHONPATH"] = sub( + r"{}{}?".format(dirname(abspath(__file__)), pathsep), + "", + environ["PYTHONPATH"], + ) -else: - initialize() +for entry_point in iter_entry_points("opentelemetry-post-instrument"): + entry_point.load()() diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py deleted file mode 100644 index cc1c99c1e03..00000000000 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. -# type: ignore - -""" -OpenTelemetry Base Distribution (Distro) -""" - -from abc import ABC, abstractmethod -from logging import getLogger - -from pkg_resources import EntryPoint - -from opentelemetry.instrumentation.instrumentor import BaseInstrumentor - -_LOG = getLogger(__name__) - - -class BaseDistro(ABC): - """An ABC for distro""" - - _instance = None - - def __new__(cls, *args, **kwargs): - - if cls._instance is None: - cls._instance = object.__new__(cls, *args, **kwargs) - - return cls._instance - - @abstractmethod - def _configure(self, **kwargs): - """Configure the distribution""" - - def configure(self, **kwargs): - """Configure the distribution""" - self._configure(**kwargs) - - def load_instrumentor( # pylint: disable=no-self-use - self, entry_point: EntryPoint, **kwargs - ): - """Takes a collection of instrumentation entry points - and activates them by instantiating and calling instrument() - on each one. - - Distros can override this method to customize the behavior by - inspecting each entry point and configuring them in special ways, - passing additional arguments, load a replacement/fork instead, - skip loading entirely, etc. - """ - instrumentor: BaseInstrumentor = entry_point.load() - instrumentor().instrument(**kwargs) - - -class DefaultDistro(BaseDistro): - def _configure(self, **kwargs): - pass - - -__all__ = ["BaseDistro", "DefaultDistro"] diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/environment_variables/__init__.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/environment_variables/__init__.py new file mode 100644 index 00000000000..a31dcde3e9e --- /dev/null +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/environment_variables/__init__.py @@ -0,0 +1,21 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + + +OTEL_PYTHON_DISABLED_INSTRUMENTATIONS = "OTEL_PYTHON_DISABLED_INSTRUMENTATIONS" +""" +.. envvar:: OTEL_PYTHON_DISABLED_INSTRUMENTATIONS + +Space-separated string of `opentelemetry-instrumentor` entry point names. +""" diff --git a/opentelemetry-instrumentation/tests/test_distro.py b/opentelemetry-instrumentation/tests/test_distro.py deleted file mode 100644 index 399b3f8a654..00000000000 --- a/opentelemetry-instrumentation/tests/test_distro.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# 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. -# type: ignore - -from unittest import TestCase - -from pkg_resources import EntryPoint - -from opentelemetry.instrumentation.distro import BaseDistro -from opentelemetry.instrumentation.instrumentor import BaseInstrumentor - - -class MockInstrumetor(BaseInstrumentor): - def instrumentation_dependencies(self): - return [] - - def _instrument(self, **kwargs): - pass - - def _uninstrument(self, **kwargs): - pass - - -class MockEntryPoint(EntryPoint): - def __init__(self, obj): # pylint: disable=super-init-not-called - self._obj = obj - - def load(self, *args, **kwargs): # pylint: disable=signature-differs - return self._obj - - -class MockDistro(BaseDistro): - def _configure(self, **kwargs): - pass - - -class TestDistro(TestCase): - def test_load_instrumentor(self): - # pylint: disable=protected-access - distro = MockDistro() - - instrumentor = MockInstrumetor() - entry_point = MockEntryPoint(MockInstrumetor) - - self.assertFalse(instrumentor._is_instrumented_by_opentelemetry) - distro.load_instrumentor(entry_point) - self.assertTrue(instrumentor._is_instrumented_by_opentelemetry)