Skip to content

Commit

Permalink
opentelemetry-instrumentation: don't fail if an instrumentor raises I…
Browse files Browse the repository at this point in the history
…mportError (#2923)
  • Loading branch information
xrmx authored Oct 25, 2024
1 parent 779ec9e commit 8582da5
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Deprecation of pkg_resource in favor of importlib.metadata
([#2871](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2871))
- `opentelemetry-instrumentation` Don't fail distro loading if instrumentor raises ImportError, instead skip them
([#2923](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2923))

## Version 1.27.0/0.48b0 (2024-08-28)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@ def _load_instrumentors(distro):
# 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 ImportError:
# in scenarios using the kubernetes operator to do autoinstrumentation some
# instrumentors (usually requiring binary extensions) may fail to load
# because the injected autoinstrumentation code does not match the application
# environment regarding python version, libc, etc... In this case it's better
# to skip the single instrumentation rather than failing to load everything
# so treat differently ImportError than the rest of exceptions
_logger.exception(
"Importing of %s failed, skipping it", entry_point.name
)
continue
except Exception as exc: # pylint: disable=broad-except
_logger.exception("Instrumenting of %s failed", entry_point.name)
raise exc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,70 @@ def test_load_instrumentors_dep_conflict(self, iter_mock, dep_mock): # pylint:
)
distro_mock.load_instrumentor.assert_called_once()

@patch(
"opentelemetry.instrumentation.auto_instrumentation._load.get_dist_dependency_conflicts"
)
@patch(
"opentelemetry.instrumentation.auto_instrumentation._load.entry_points"
)
def test_load_instrumentors_import_error_does_not_stop_everything(
self, iter_mock, dep_mock
):
ep_mock1 = Mock(name="instr1")
ep_mock2 = Mock(name="instr2")

distro_mock = Mock()
distro_mock.load_instrumentor.side_effect = [ImportError, None]

# Mock entry points in order
iter_mock.side_effect = [
(),
(ep_mock1, ep_mock2),
(),
]
dep_mock.return_value = None

_load._load_instrumentors(distro_mock)

distro_mock.load_instrumentor.assert_has_calls(
[
call(ep_mock1, skip_dep_check=True),
call(ep_mock2, skip_dep_check=True),
]
)
self.assertEqual(distro_mock.load_instrumentor.call_count, 2)

@patch(
"opentelemetry.instrumentation.auto_instrumentation._load.get_dist_dependency_conflicts"
)
@patch(
"opentelemetry.instrumentation.auto_instrumentation._load.entry_points"
)
def test_load_instrumentors_raises_exception(self, iter_mock, dep_mock):
ep_mock1 = Mock(name="instr1")
ep_mock2 = Mock(name="instr2")

distro_mock = Mock()
distro_mock.load_instrumentor.side_effect = [ValueError, None]

# Mock entry points in order
iter_mock.side_effect = [
(),
(ep_mock1, ep_mock2),
(),
]
dep_mock.return_value = None

with self.assertRaises(ValueError):
_load._load_instrumentors(distro_mock)

distro_mock.load_instrumentor.assert_has_calls(
[
call(ep_mock1, skip_dep_check=True),
]
)
self.assertEqual(distro_mock.load_instrumentor.call_count, 1)

def test_load_instrumentors_no_entry_point_mocks(self):
distro_mock = Mock()
_load._load_instrumentors(distro_mock)
Expand Down

0 comments on commit 8582da5

Please sign in to comment.