Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions sdk/monitor/azure-monitor-opentelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
# Release History

## 1.6.7 (Unreleased)

### Features Added

### Breaking Changes
## 1.6.7 (2025-04-10)

### Bugs Fixed

### Other Changes
- Adapt to OpenTelemetry dependency resolver change.
([#40463](https://github.com/Azure/azure-sdk-for-python/pull/40463))

## 1.6.6 (2025-04-07)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from opentelemetry._events import _set_event_logger_provider
from opentelemetry._logs import set_logger_provider
from opentelemetry.instrumentation.dependencies import (
get_dist_dependency_conflicts,
DependencyConflictError,
Comment thread
jeremydvoss marked this conversation as resolved.
)
from opentelemetry.instrumentation.instrumentor import ( # type: ignore
BaseInstrumentor,
Expand Down Expand Up @@ -211,25 +211,8 @@ def _setup_live_metrics(configurations):
enable_live_metrics(**configurations)


class _EntryPointDistFinder:
@cached_property
def _mapping(self):
return {self._key_for(ep): dist for dist in distributions() for ep in dist.entry_points}

def dist_for(self, entry_point: EntryPoint):
dist = getattr(entry_point, "dist", None)
if dist:
return dist

return self._mapping.get(self._key_for(entry_point))

@staticmethod
def _key_for(entry_point: EntryPoint):
return f"{entry_point.group}:{entry_point.name}:{entry_point.value}"


def _setup_instrumentations(configurations: Dict[str, ConfigurationValue]):
entry_point_finder = _EntryPointDistFinder()
# entry_point_finder = _EntryPointDistFinder()
# use pkg_resources for now until https://github.com/open-telemetry/opentelemetry-python/pull/3168 is merged
for entry_point in entry_points(group="opentelemetry_instrumentor"):
lib_name = entry_point.name
Expand All @@ -239,20 +222,16 @@ def _setup_instrumentations(configurations: Dict[str, ConfigurationValue]):
_logger.debug("Instrumentation skipped for library %s", entry_point.name)
continue
try:
# Check if dependent libraries/version are installed
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm doing something wrong, the removal of this logic causes some messy log messages in our containers - e.g. tracebacks starting like:

Exception occurred when instrumenting: django.
Traceback (most recent call last):
  File "/app/.venv/lib/python3.12/site-packages/azure/monitor/opentelemetry/_configure.py", line 222, in _setup_instrumentations
    instrumentor: BaseInstrumentor = entry_point.load()
                                     ^^^^^^^^^^^^^^^^^^

for all the libraries that aren't installed. Do we now have to explicitly disable these when calling configure_azure_monitor? Are the defaults documented anywhere?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dylwil3 please create a new issue (so it won't get overlooked). Thanks!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - here it is: #40517

entry_point_dist = entry_point_finder.dist_for(entry_point) # type: ignore
conflict = get_dist_dependency_conflicts(entry_point_dist) # type: ignore
if conflict:
_logger.debug(
"Skipping instrumentation %s: %s",
entry_point.name,
conflict,
)
continue
# Load the instrumentor via entrypoint
instrumentor: BaseInstrumentor = entry_point.load()
# tell instrumentation to not run dep checks again as we already did it above
instrumentor().instrument(skip_dep_check=True)
instrumentor().instrument(raise_exception_on_conflict=True)
except DependencyConflictError as exc:
_logger.debug(
"Skipping instrumentation %s: %s",
entry_point.name,
exc.conflict,
)
continue
except Exception as ex: # pylint: disable=broad-except
_logger.warning(
"Exception occurred when instrumenting: %s.",
Expand Down
16 changes: 8 additions & 8 deletions sdk/monitor/azure-monitor-opentelemetry/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@
"azure-core<2.0.0,>=1.28.0",
"azure-core-tracing-opentelemetry~=1.0.0b11",
"azure-monitor-opentelemetry-exporter~=1.0.0b31",
"opentelemetry-instrumentation-django~=0.49b0",
"opentelemetry-instrumentation-fastapi~=0.49b0",
"opentelemetry-instrumentation-flask~=0.49b0",
"opentelemetry-instrumentation-psycopg2~=0.49b0",
"opentelemetry-instrumentation-requests~=0.49b0",
"opentelemetry-instrumentation-urllib~=0.49b0",
"opentelemetry-instrumentation-urllib3~=0.49b0",
"opentelemetry-instrumentation-django~=0.53b0",
"opentelemetry-instrumentation-fastapi~=0.53b0",
"opentelemetry-instrumentation-flask~=0.53b0",
"opentelemetry-instrumentation-psycopg2~=0.53b0",
"opentelemetry-instrumentation-requests~=0.53b0",
"opentelemetry-instrumentation-urllib~=0.53b0",
"opentelemetry-instrumentation-urllib3~=0.53b0",
"opentelemetry-resource-detector-azure~=0.1.4",
"opentelemetry-sdk~=1.28",
"opentelemetry-sdk~=1.32",
],
entry_points={
"opentelemetry_distro": [
Expand Down
29 changes: 11 additions & 18 deletions sdk/monitor/azure-monitor-opentelemetry/tests/test_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
import unittest
from unittest.mock import Mock, call, patch

from opentelemetry.instrumentation.dependencies import (
DependencyConflict,
DependencyConflictError,
)
from opentelemetry.sdk._logs import LoggingHandler
from opentelemetry.sdk.resources import Resource

Expand Down Expand Up @@ -533,12 +537,10 @@ def test_setup_live_metrics(

@patch("azure.monitor.opentelemetry._configure._ALL_SUPPORTED_INSTRUMENTED_LIBRARIES", ("test_instr2"))
@patch("azure.monitor.opentelemetry._configure._is_instrumentation_enabled")
@patch("azure.monitor.opentelemetry._configure.get_dist_dependency_conflicts")
@patch("azure.monitor.opentelemetry._configure.entry_points")
def test_setup_instrumentations_lib_not_supported(
self,
iter_mock,
dep_mock,
enabled_mock,
):
ep_mock = Mock()
Expand All @@ -550,10 +552,8 @@ def test_setup_instrumentations_lib_not_supported(
ep_mock.name = "test_instr1"
ep2_mock.name = "test_instr2"
ep2_mock.load.return_value = instr_class_mock
dep_mock.return_value = None
enabled_mock.return_value = True
_setup_instrumentations({})
dep_mock.assert_called_with(ep2_mock.dist)
ep_mock.load.assert_not_called()
ep2_mock.load.assert_called_once()
instrumentor_mock.instrument.assert_called_once()
Expand All @@ -579,12 +579,10 @@ def test_setup_instrumentations_additional_azure(
@patch("azure.monitor.opentelemetry._configure._ALL_SUPPORTED_INSTRUMENTED_LIBRARIES", ("test_instr"))
@patch("azure.monitor.opentelemetry._configure._is_instrumentation_enabled")
@patch("azure.monitor.opentelemetry._configure._logger")
@patch("azure.monitor.opentelemetry._configure.get_dist_dependency_conflicts")
@patch("azure.monitor.opentelemetry._configure.entry_points")
def test_setup_instrumentations_conflict(
self,
iter_mock,
dep_mock,
logger_mock,
enabled_mock,
):
Expand All @@ -595,23 +593,24 @@ def test_setup_instrumentations_conflict(
instr_class_mock.return_value = instrumentor_mock
ep_mock.name = "test_instr"
ep_mock.load.return_value = instr_class_mock
dep_mock.return_value = True
instrumentor_mock.instrument.side_effect = DependencyConflictError(
DependencyConflict(
required="test_instr"
)
)
enabled_mock.return_value = True
_setup_instrumentations({})
dep_mock.assert_called_with(ep_mock.dist)
ep_mock.load.assert_not_called()
instrumentor_mock.instrument.assert_not_called()
ep_mock.load.assert_called_once()
instrumentor_mock.instrument.assert_called_once()
logger_mock.debug.assert_called_once()

@patch("azure.monitor.opentelemetry._configure._ALL_SUPPORTED_INSTRUMENTED_LIBRARIES", ("test_instr"))
@patch("azure.monitor.opentelemetry._configure._is_instrumentation_enabled")
@patch("azure.monitor.opentelemetry._configure._logger")
@patch("azure.monitor.opentelemetry._configure.get_dist_dependency_conflicts")
@patch("azure.monitor.opentelemetry._configure.entry_points")
def test_setup_instrumentations_exception(
self,
iter_mock,
dep_mock,
logger_mock,
enabled_mock,
):
Expand All @@ -622,10 +621,8 @@ def test_setup_instrumentations_exception(
instr_class_mock.return_value = instrumentor_mock
ep_mock.name = "test_instr"
ep_mock.load.side_effect = Exception()
dep_mock.return_value = None
enabled_mock.return_value = True
_setup_instrumentations({})
dep_mock.assert_called_with(ep_mock.dist)
ep_mock.load.assert_called_once()
instrumentor_mock.instrument.assert_not_called()
logger_mock.warning.assert_called_once()
Expand All @@ -635,12 +632,10 @@ def test_setup_instrumentations_exception(
)
@patch("azure.monitor.opentelemetry._configure._is_instrumentation_enabled")
@patch("azure.monitor.opentelemetry._configure._logger")
@patch("azure.monitor.opentelemetry._configure.get_dist_dependency_conflicts")
@patch("azure.monitor.opentelemetry._configure.entry_points")
def test_setup_instrumentations_disabled(
self,
iter_mock,
dep_mock,
logger_mock,
enabled_mock,
):
Expand All @@ -653,10 +648,8 @@ def test_setup_instrumentations_disabled(
ep_mock.name = "test_instr1"
ep2_mock.name = "test_instr2"
ep2_mock.load.return_value = instr_class_mock
dep_mock.return_value = None
enabled_mock.side_effect = [False, True]
_setup_instrumentations({})
dep_mock.assert_called_with(ep2_mock.dist)
ep_mock.load.assert_not_called()
ep2_mock.load.assert_called_once()
instrumentor_mock.instrument.assert_called_once()
Expand Down
Loading