From 0e22758cc1022f4509800ba72a2bfe38f98e61d6 Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Thu, 8 Jul 2021 14:56:34 -0700 Subject: [PATCH 01/10] Enforce 1 distro+configurator for auto instrumentation --- .../auto_instrumentation/sitecustomize.py | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index d89b60ec56..25f2a78969 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -23,6 +23,7 @@ from opentelemetry.environment_variables import ( OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, ) +from opentelemetry.instrumentation.configurator import BaseConfigurator from opentelemetry.instrumentation.dependencies import ( get_dist_dependency_conflicts, ) @@ -32,24 +33,40 @@ def _load_distros() -> BaseDistro: - for entry_point in iter_entry_points("opentelemetry_distro"): + entry_points = iter_entry_points("opentelemetry_distro") + loaded_distro = None + loaded_distro_name = None + for entry_point in entry_points: + if loaded_distro_name is not None: + logger.error( + "Multiple distros were found: (%s). Only one should be installed.", + ",".join([loaded_distro_name, entry_point.module_name] + [ep.module_name for ep in entry_points]), + ) + raise RuntimeError("Cannot Auto Instrument with multiple distros installed.") + + loaded_distro_name = entry_point.module_name + try: - distro = entry_point.load()() - if not isinstance(distro, BaseDistro): + loaded_distro = entry_point.load()() + if not isinstance(loaded_distro, BaseDistro): logger.debug( "%s is not an OpenTelemetry Distro. Skipping", - entry_point.name, + entry_point.module_name, ) continue logger.debug( - "Distribution %s will be configured", entry_point.name + "Distribution %s will be configured", loaded_distro_name ) - return distro except Exception as exc: # pylint: disable=broad-except logger.exception( - "Distribution %s configuration failed", entry_point.name + "Distribution %s configuration failed", loaded_distro_name ) raise exc + + if loaded_distro is not None: + return loaded_distro + + logger.warning("Initializing Auto Instrumentation without using a distro.") return DefaultDistro() @@ -96,7 +113,14 @@ def _load_configurators(): ) continue try: - entry_point.load()().configure() # type: ignore + configurator: BaseConfigurator = entry_point.load()() + if not isinstance(configurator, BaseConfigurator): + logger.debug( + "%s is not an OpenTelemetry Configurator. Skipping", + entry_point.name, + ) + continue + configurator.configure() configured = entry_point.name except Exception as exc: # pylint: disable=broad-except logger.exception("Configuration of %s failed", entry_point.name) From 00f5532a2445bb9775ea1fd90b3c09e95f7f037e Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Thu, 8 Jul 2021 16:47:54 -0700 Subject: [PATCH 02/10] Changelog for enforcing 1 distro+configurator --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d2a12f78f..9c1c1ab5a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.3.0-0.22b0...HEAD) +- `opentelemetry-instrumentation` Enforce 1 distro+configurator for auto instrumentation + ([#571](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/571)) - `opentelemetry-sdk-extension-aws` Update AWS entry points to match spec ([#566](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/566)) - Include Flask 2.0 as compatible with existing flask instrumentation From 6f057bd07af11b5834175cdb894eedc28647eca5 Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Thu, 8 Jul 2021 16:52:20 -0700 Subject: [PATCH 03/10] Update documentation to reflect distro strictness --- opentelemetry-instrumentation/README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/opentelemetry-instrumentation/README.rst b/opentelemetry-instrumentation/README.rst index 6f74d2232f..1d0e349263 100644 --- a/opentelemetry-instrumentation/README.rst +++ b/opentelemetry-instrumentation/README.rst @@ -38,6 +38,11 @@ opentelemetry-instrument opentelemetry-instrument python program.py +**NOTE:** `opentelemetry-instrument` will check for compatible "distros" (like `opentelemetry-distro`) +when automatically instrumenting. If multiple distros are found, instrumentation will fail. Check out +`Github Issue #551 `_ for +more. + The instrument command will try to automatically detect packages used by your python program and when possible, apply automatic tracing instrumentation on them. This means your program will get automatic distributed tracing for free without having to make any code changes From 070c37e45edadd6940a1391fc6315fb51bc14677 Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 9 Jul 2021 11:42:41 -0700 Subject: [PATCH 04/10] Simplify distro loading logic --- .../auto_instrumentation/sitecustomize.py | 56 +++++++------------ 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index 25f2a78969..6b5e14ec34 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -34,38 +34,31 @@ def _load_distros() -> BaseDistro: entry_points = iter_entry_points("opentelemetry_distro") - loaded_distro = None - loaded_distro_name = None - for entry_point in entry_points: - if loaded_distro_name is not None: - logger.error( - "Multiple distros were found: (%s). Only one should be installed.", - ",".join([loaded_distro_name, entry_point.module_name] + [ep.module_name for ep in entry_points]), - ) - raise RuntimeError("Cannot Auto Instrument with multiple distros installed.") + try: + first_distro = entry_points[0] - loaded_distro_name = entry_point.module_name + more_distros = [ep.module_name for ep in entry_points] - try: - loaded_distro = entry_point.load()() - if not isinstance(loaded_distro, BaseDistro): - logger.debug( - "%s is not an OpenTelemetry Distro. Skipping", - entry_point.module_name, + if more_distros: + logger.error( + "Multiple distros were found: (%s). Only one should be installed.", + ",".join([first_distro.module_name] + more_distros), ) - continue + raise RuntimeError("Cannot Auto Instrument with multiple distros installed.") + + loaded_distro = first_distro.load()() + if isinstance(loaded_distro, BaseDistro): logger.debug( - "Distribution %s will be configured", loaded_distro_name + "Distribution %s will be configured", loaded_distro.module_name ) - except Exception as exc: # pylint: disable=broad-except - logger.exception( - "Distribution %s configuration failed", loaded_distro_name - ) - raise exc - - if loaded_distro is not None: - return loaded_distro - + return loaded_distro + except IndexError: + logger.warning("Initializing Auto Instrumentation without using a distro.") + except Exception as exc: # pylint: disable=broad-except + logger.exception( + "Distribution %s configuration failed", loaded_distro.module_name + ) + raise exc logger.warning("Initializing Auto Instrumentation without using a distro.") return DefaultDistro() @@ -113,14 +106,7 @@ def _load_configurators(): ) continue try: - configurator: BaseConfigurator = entry_point.load()() - if not isinstance(configurator, BaseConfigurator): - logger.debug( - "%s is not an OpenTelemetry Configurator. Skipping", - entry_point.name, - ) - continue - configurator.configure() + 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) From 6f34f1d457a99e794f37fb710c522216e75baa19 Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 9 Jul 2021 11:49:28 -0700 Subject: [PATCH 05/10] Quick variable reference fixes --- .../instrumentation/auto_instrumentation/sitecustomize.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index 6b5e14ec34..de54cd94ed 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -35,7 +35,7 @@ def _load_distros() -> BaseDistro: entry_points = iter_entry_points("opentelemetry_distro") try: - first_distro = entry_points[0] + first_distro = next(entry_points) more_distros = [ep.module_name for ep in entry_points] @@ -49,14 +49,14 @@ def _load_distros() -> BaseDistro: loaded_distro = first_distro.load()() if isinstance(loaded_distro, BaseDistro): logger.debug( - "Distribution %s will be configured", loaded_distro.module_name + "Distribution %s will be configured", first_distro.module_name ) return loaded_distro except IndexError: logger.warning("Initializing Auto Instrumentation without using a distro.") except Exception as exc: # pylint: disable=broad-except logger.exception( - "Distribution %s configuration failed", loaded_distro.module_name + "Distribution %s configuration failed", first_distro.module_name ) raise exc logger.warning("Initializing Auto Instrumentation without using a distro.") From eaae961f9d755e13f6a78d56e74e82a193605a63 Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 9 Jul 2021 11:51:01 -0700 Subject: [PATCH 06/10] Do not need BaseConfigurator import --- .../instrumentation/auto_instrumentation/sitecustomize.py | 1 - 1 file changed, 1 deletion(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index de54cd94ed..dd98d81496 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -23,7 +23,6 @@ from opentelemetry.environment_variables import ( OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, ) -from opentelemetry.instrumentation.configurator import BaseConfigurator from opentelemetry.instrumentation.dependencies import ( get_dist_dependency_conflicts, ) From 68484fe2eba0a40473c43ba35e9d8562d2931e41 Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 9 Jul 2021 12:02:59 -0700 Subject: [PATCH 07/10] Remove type check for BaseDistro --- .../instrumentation/auto_instrumentation/sitecustomize.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index dd98d81496..9320bba9b6 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -45,12 +45,7 @@ def _load_distros() -> BaseDistro: ) raise RuntimeError("Cannot Auto Instrument with multiple distros installed.") - loaded_distro = first_distro.load()() - if isinstance(loaded_distro, BaseDistro): - logger.debug( - "Distribution %s will be configured", first_distro.module_name - ) - return loaded_distro + return first_distro.load()() except IndexError: logger.warning("Initializing Auto Instrumentation without using a distro.") except Exception as exc: # pylint: disable=broad-except From afaab233cb0b0187702349ee6f80c92c226afa8e Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 9 Jul 2021 13:59:31 -0700 Subject: [PATCH 08/10] Use StopIteration because we use generator next now --- .../instrumentation/auto_instrumentation/sitecustomize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index 9320bba9b6..47f5e6675c 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -46,7 +46,7 @@ def _load_distros() -> BaseDistro: raise RuntimeError("Cannot Auto Instrument with multiple distros installed.") return first_distro.load()() - except IndexError: + except StopIteration: logger.warning("Initializing Auto Instrumentation without using a distro.") except Exception as exc: # pylint: disable=broad-except logger.exception( From 40a5e1be0622c75d56505605a9b1c5c01cc6f42f Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 9 Jul 2021 14:02:03 -0700 Subject: [PATCH 09/10] Better logic for stopiteration catch --- .../auto_instrumentation/sitecustomize.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index 47f5e6675c..48dbc9286c 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -40,21 +40,24 @@ def _load_distros() -> BaseDistro: if more_distros: logger.error( - "Multiple distros were found: (%s). Only one should be installed.", - ",".join([first_distro.module_name] + more_distros), - ) - raise RuntimeError("Cannot Auto Instrument with multiple distros installed.") + "Multiple distros were found: (%s). Only one should be installed.", + ",".join([first_distro.module_name] + more_distros), + ) + raise RuntimeError( + "Cannot Auto Instrument with multiple distros installed." + ) return first_distro.load()() except StopIteration: - logger.warning("Initializing Auto Instrumentation without using a distro.") + logger.warning( + "Initializing Auto Instrumentation without using a distro." + ) + return DefaultDistro() except Exception as exc: # pylint: disable=broad-except logger.exception( "Distribution %s configuration failed", first_distro.module_name ) raise exc - logger.warning("Initializing Auto Instrumentation without using a distro.") - return DefaultDistro() def _load_instrumentors(distro): From cacaa0bc5553ffdf7df0e872cda3af88df15b80c Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Mon, 12 Jul 2021 12:46:32 -0700 Subject: [PATCH 10/10] Add small documentation and interface updates --- opentelemetry-instrumentation/README.rst | 6 ++++-- .../auto_instrumentation/sitecustomize.py | 15 ++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/opentelemetry-instrumentation/README.rst b/opentelemetry-instrumentation/README.rst index 1d0e349263..c445f6ed60 100644 --- a/opentelemetry-instrumentation/README.rst +++ b/opentelemetry-instrumentation/README.rst @@ -39,9 +39,11 @@ opentelemetry-instrument opentelemetry-instrument python program.py **NOTE:** `opentelemetry-instrument` will check for compatible "distros" (like `opentelemetry-distro`) -when automatically instrumenting. If multiple distros are found, instrumentation will fail. Check out +when automatically instrumenting. A "distro" is defined as a class that successfully inherits from the +[BaseDistro](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/opentelemetry-instrumentation/src/opentelemetry/instrumentation/distro.py#L30). +If multiple distros are found, auto-instrumentation will fail. Check out `Github Issue #551 `_ for -more. +more details. The instrument command will try to automatically detect packages used by your python program and when possible, apply automatic tracing instrumentation on them. This means your program diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index 48dbc9286c..c1799a1085 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -31,11 +31,17 @@ logger = getLogger(__file__) -def _load_distros() -> BaseDistro: +def _load_distro() -> BaseDistro: entry_points = iter_entry_points("opentelemetry_distro") try: first_distro = next(entry_points) + except StopIteration: + logger.warning( + "Failed to find even one installed distro. Initializing Auto Instrumentation without using a distro." + ) + return DefaultDistro() + try: more_distros = [ep.module_name for ep in entry_points] if more_distros: @@ -48,11 +54,6 @@ def _load_distros() -> BaseDistro: ) return first_distro.load()() - except StopIteration: - logger.warning( - "Initializing Auto Instrumentation without using a distro." - ) - return DefaultDistro() except Exception as exc: # pylint: disable=broad-except logger.exception( "Distribution %s configuration failed", first_distro.module_name @@ -112,7 +113,7 @@ def _load_configurators(): def initialize(): try: - distro = _load_distros() + distro = _load_distro() distro.configure() _load_configurators() _load_instrumentors(distro)