From ef8d84147d9464f88d8e98773114acbc0affc477 Mon Sep 17 00:00:00 2001 From: Phillip Verheyden Date: Mon, 26 May 2025 09:26:29 -0500 Subject: [PATCH 1/4] Allow reraising the root exception if instrumentation fails I would rather completely fail startup in my services if instrumentation fails for whatever reason instead of just logging an exception and continuing. Use case: from opentelemetry import autoinstrumentation autoinstrumentation.initialize(reraise=True) --- CHANGELOG.md | 2 ++ .../auto_instrumentation/__init__.py | 12 +++++++++--- .../tests/auto_instrumentation/test_initialize.py | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f69127240f..f80fce35d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `opentelemetry-instrumentation-aiohttp-client` Add support for HTTP metrics ([#3517](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3517)) +- `opentelemetry-instrumentation` Allow re-raising exception when instrumentation fails + ([#3545](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3545)) ### Deprecated diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py index 69af0b4cea..84bab6deac 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py @@ -118,8 +118,12 @@ def run() -> None: execl(executable, executable, *args.command_args) -def initialize(): - """Setup auto-instrumentation, called by the sitecustomize module""" +def initialize(*, swallow_exceptions=True): + """ + Setup auto-instrumentation, called by the sitecustomize module + + :param swallow_exceptions: Whether or not to propagate instrumentation exceptions to the caller. Exceptions are logged and swallowed by default. + """ # prevents auto-instrumentation of subprocesses if code execs another python process if "PYTHONPATH" in environ: environ["PYTHONPATH"] = _python_path_without_directory( @@ -131,5 +135,7 @@ def initialize(): distro.configure() _load_configurators() _load_instrumentors(distro) - except Exception: # pylint: disable=broad-except + except Exception as e: # pylint: disable=broad-except _logger.exception("Failed to auto initialize OpenTelemetry") + if not swallow_exceptions: + raise ValueError("Failed to auto initialize OpenTelemetry") from e diff --git a/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py b/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py index 6d05a69c8e..e6222f3683 100644 --- a/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py +++ b/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py @@ -59,3 +59,18 @@ def test_handles_exceptions(self, load_distro_mock, logger_mock): logger_mock.exception.assert_called_once_with( "Failed to auto initialize OpenTelemetry" ) + + @patch("opentelemetry.instrumentation.auto_instrumentation._logger") + @patch("opentelemetry.instrumentation.auto_instrumentation._load_distro") + def test_reraises_exceptions(self, load_distro_mock, logger_mock): + # pylint:disable=no-self-use + load_distro_mock.side_effect = ValueError + with self.assertRaises(ValueError) as em: + auto_instrumentation.initialize(swallow_exceptions=False) + logger_mock.exception.assert_called_once_with( + "Failed to auto initialize OpenTelemetry" + ) + + self.assertEqual( + "Failed to auto initialize OpenTelemetry", str(em.exception) + ) From 29cfe32155b62b305cebe95a241dadf89afb819f Mon Sep 17 00:00:00 2001 From: Phillip Verheyden Date: Tue, 27 May 2025 13:44:22 -0500 Subject: [PATCH 2/4] Fix lint --- .../instrumentation/auto_instrumentation/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py index 84bab6deac..a41913c60e 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py @@ -135,7 +135,9 @@ def initialize(*, swallow_exceptions=True): distro.configure() _load_configurators() _load_instrumentors(distro) - except Exception as e: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except _logger.exception("Failed to auto initialize OpenTelemetry") if not swallow_exceptions: - raise ValueError("Failed to auto initialize OpenTelemetry") from e + raise ValueError( + "Failed to auto initialize OpenTelemetry" + ) from exc From a8e242422a4b8f2ef6b0592cf2b5476b0548f326 Mon Sep 17 00:00:00 2001 From: Phillip Verheyden Date: Tue, 27 May 2025 20:35:59 -0500 Subject: [PATCH 3/4] Type hinting, re-raise original exception --- .../instrumentation/auto_instrumentation/__init__.py | 6 ++---- .../tests/auto_instrumentation/test_initialize.py | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py index a41913c60e..19fd9db393 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py @@ -118,7 +118,7 @@ def run() -> None: execl(executable, executable, *args.command_args) -def initialize(*, swallow_exceptions=True): +def initialize(*, swallow_exceptions: bool = True): """ Setup auto-instrumentation, called by the sitecustomize module @@ -138,6 +138,4 @@ def initialize(*, swallow_exceptions=True): except Exception as exc: # pylint: disable=broad-except _logger.exception("Failed to auto initialize OpenTelemetry") if not swallow_exceptions: - raise ValueError( - "Failed to auto initialize OpenTelemetry" - ) from exc + raise exc diff --git a/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py b/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py index e6222f3683..715da0d2f6 100644 --- a/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py +++ b/opentelemetry-instrumentation/tests/auto_instrumentation/test_initialize.py @@ -64,13 +64,11 @@ def test_handles_exceptions(self, load_distro_mock, logger_mock): @patch("opentelemetry.instrumentation.auto_instrumentation._load_distro") def test_reraises_exceptions(self, load_distro_mock, logger_mock): # pylint:disable=no-self-use - load_distro_mock.side_effect = ValueError + load_distro_mock.side_effect = ValueError("inner exception") with self.assertRaises(ValueError) as em: auto_instrumentation.initialize(swallow_exceptions=False) logger_mock.exception.assert_called_once_with( "Failed to auto initialize OpenTelemetry" ) - self.assertEqual( - "Failed to auto initialize OpenTelemetry", str(em.exception) - ) + self.assertEqual("inner exception", str(em.exception)) From 773d4ce042d82432f6c3ff361c83be4b620dae57 Mon Sep 17 00:00:00 2001 From: Phillip Verheyden Date: Tue, 27 May 2025 20:36:59 -0500 Subject: [PATCH 4/4] One more type hint to indicate None return --- .../instrumentation/auto_instrumentation/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py index 19fd9db393..8571d0e5a2 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py @@ -118,7 +118,7 @@ def run() -> None: execl(executable, executable, *args.command_args) -def initialize(*, swallow_exceptions: bool = True): +def initialize(*, swallow_exceptions: bool = True) -> None: """ Setup auto-instrumentation, called by the sitecustomize module