diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a96a69a..43dafd04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ ([#269](https://github.com/microsoft/opentelemetry-distro-python/pull/269)) ### Bugs Fixed +- Restore MOT version propagation after OneSettings initialization order caused the exporter version to take precedence over the Microsoft OpenTelemetry distro version + ([#275](https://github.com/microsoft/opentelemetry-distro-python/pull/275)) - Restrict A365 identity and baggage enrichment to recognized GenAI spans while preserving supported span-start signals. ([#265](https://github.com/microsoft/opentelemetry-distro-python/pull/265)) - Preserve existing span attributes when recording custom scope attributes. ([#266](https://github.com/microsoft/opentelemetry-distro-python/pull/266)) diff --git a/src/microsoft/opentelemetry/_distro.py b/src/microsoft/opentelemetry/_distro.py index 2d7a8792..54dedc24 100644 --- a/src/microsoft/opentelemetry/_distro.py +++ b/src/microsoft/opentelemetry/_distro.py @@ -24,13 +24,6 @@ entry_points, ) -_get_configuration_manager: Optional[Callable[[], Any]] -try: - from azure.monitor.opentelemetry.exporter._configuration._state import ( # pylint: disable=import-error,no-name-in-module - get_configuration_manager as _get_configuration_manager, - ) -except ImportError: - _get_configuration_manager = None from microsoft.opentelemetry._constants import ( DISABLE_LOGGING_ARG, @@ -78,6 +71,14 @@ os.environ.setdefault(MICROSOFT_OPENTELEMETRY_VERSION_ENV, VERSION) +_get_configuration_manager: Optional[Callable[[], Any]] +try: + from azure.monitor.opentelemetry.exporter._configuration._state import ( # pylint: disable=import-error,no-name-in-module + get_configuration_manager as _get_configuration_manager, + ) +except ImportError: + _get_configuration_manager = None + # pylint: disable=wrong-import-position from microsoft.opentelemetry._genai.main_agent import ( GenAIMainAgentLogRecordProcessor, diff --git a/tests/test_distro.py b/tests/test_distro.py index b0518ddf..53c7cd38 100644 --- a/tests/test_distro.py +++ b/tests/test_distro.py @@ -11,6 +11,7 @@ 2. Optionally delegates Azure Monitor exporter setup. """ +import importlib import os import unittest from unittest.mock import MagicMock, patch @@ -22,7 +23,9 @@ from microsoft.opentelemetry._constants import ( _A365_DISABLED_INSTRUMENTATIONS, _SUPPORTED_INSTRUMENTED_LIBRARIES, + MICROSOFT_OPENTELEMETRY_VERSION_ENV, ) +import microsoft.opentelemetry._distro as distro_module from microsoft.opentelemetry._distro import ( use_microsoft_opentelemetry, _append_a365_components, @@ -41,6 +44,43 @@ class TestUseMicrosoftOpenTelemetry(unittest.TestCase): """Tests for use_microsoft_opentelemetry() orchestration.""" + def test_distro_version_is_set_before_exporter_import(self): + """Exporter imports cannot claim the shared profile before the MOT version is available.""" + from azure.monitor.opentelemetry.exporter._configuration import _state as configuration_state + + manager = MagicMock() + observed_versions = [] + original_getter = configuration_state.get_configuration_manager + original_manager = configuration_state._configuration_manager # pylint: disable=protected-access + original_module_getattr = configuration_state.__dict__.get("__getattr__") + + def observe_configuration_state_import(name): + if name != "get_configuration_manager": + raise AttributeError(name) + observed_versions.append(os.environ.get(MICROSOFT_OPENTELEMETRY_VERSION_ENV)) + return lambda: manager + + try: + with patch.dict(os.environ): + os.environ.pop(MICROSOFT_OPENTELEMETRY_VERSION_ENV, None) + importlib.reload(configuration_state) + del configuration_state.get_configuration_manager + configuration_state.__dict__["__getattr__"] = observe_configuration_state_import + + importlib.reload(distro_module) + distro_module._initialize_configuration_manager() # pylint: disable=protected-access + finally: + configuration_state.__dict__["get_configuration_manager"] = original_getter + configuration_state._configuration_manager = original_manager # pylint: disable=protected-access + if original_module_getattr is None: + configuration_state.__dict__.pop("__getattr__", None) + else: + configuration_state.__dict__["__getattr__"] = original_module_getattr + importlib.reload(distro_module) + + self.assertEqual(observed_versions, [VERSION]) + manager.initialize.assert_called_once_with(component="mot", version=VERSION) + @patch("microsoft.opentelemetry._distro._append_azure_monitor_components", return_value=(None, None, None)) @patch("microsoft.opentelemetry._distro._get_configuration_manager") def test_initializes_config_manager_before_exporters(self, get_config_manager_mock, append_mock):