Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

### Other Changes

- Modify the logic to add providers when azure monitor config is disabled
Comment thread
rads-1996 marked this conversation as resolved.
- Add support for local mypy, pylint, black checks
([#14](https://github.com/microsoft/opentelemetry-distro-python/pull/14))
- Add mypy and pyright checks
Expand Down
63 changes: 30 additions & 33 deletions src/microsoft/opentelemetry/_distro.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,39 +99,32 @@ def use_microsoft_opentelemetry(**kwargs: object) -> None:
else:
otel_kwargs[key] = value

# ---- Core OTel provider initialisation ----
resource = otel_kwargs.get(RESOURCE_ARG) or Resource.create()
disable_tracing = otel_kwargs.get(DISABLE_TRACING_ARG, False)
disable_logging = otel_kwargs.get(DISABLE_LOGGING_ARG, False)
disable_metrics = otel_kwargs.get(DISABLE_METRICS_ARG, False)
Comment thread
jeremydvoss marked this conversation as resolved.

tracer_provider: Optional[TracerProvider] = None
meter_provider: Optional[MeterProvider] = None
logger_provider: Optional[Any] = None

if not disable_tracing:
tracer_provider = _setup_tracing(resource, otel_kwargs)

if not disable_metrics:
meter_provider = _setup_metrics(resource, otel_kwargs)

if not disable_logging:
logger_provider = _setup_logging(resource, otel_kwargs)

# ---- Instrumentations (always, regardless of exporter) ----
_setup_instrumentations(otel_kwargs)

# ---- Azure Monitor exporter (optional) ----
# ---- Provider initialisation ----
setup_bare_providers = True
if enable_azure_monitor:
merged = {**otel_kwargs, **azure_monitor_kwargs}
_setup_azure_monitor(
tracer_provider=tracer_provider,
meter_provider=meter_provider,
logger_provider=logger_provider,
**merged,
)
else:
_logger.info("Azure Monitor exporter explicitly disabled.")
if _setup_azure_monitor(**merged):
setup_bare_providers = False

if setup_bare_providers:
Comment thread
hectorhdzg marked this conversation as resolved.
# Either Azure Monitor is disabled, or setup failed — create bare
# providers so the global tracer/meter/logger are still usable.
resource = otel_kwargs.get(RESOURCE_ARG) or Resource.create()
disable_tracing = otel_kwargs.get(DISABLE_TRACING_ARG, False)
disable_logging = otel_kwargs.get(DISABLE_LOGGING_ARG, False)
disable_metrics = otel_kwargs.get(DISABLE_METRICS_ARG, False)

if not disable_tracing:
_setup_tracing(resource, otel_kwargs)
if not disable_metrics:
_setup_metrics(resource, otel_kwargs)
if not disable_logging:
_setup_logging(resource, otel_kwargs)
if not enable_azure_monitor:
_logger.info("Azure Monitor exporter explicitly disabled.")

# ---- Instrumentations (always, after providers are set) ----
_setup_instrumentations(otel_kwargs)


# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -268,26 +261,30 @@ def _setup_instrumentations(otel_kwargs: Dict[str, Any]) -> None:
# ---------------------------------------------------------------------------


def _setup_azure_monitor(**kwargs: object) -> None:
def _setup_azure_monitor(**kwargs: object) -> bool:
"""Delegate Azure Monitor exporter setup.

Passes the already-initialised providers to Azure Monitor so it
can attach its exporters, samplers, and processors.

:returns: True if Azure Monitor was configured successfully, False otherwise.
"""
try:
from microsoft.opentelemetry._azure_monitor import configure_azure_monitor
except ImportError:
_logger.warning(
"Failed to import Azure Monitor components. Verify azure-monitor-opentelemetry-exporter is installed."
)
return
return False

try:
configure_azure_monitor(**kwargs)
_logger.info("Azure Monitor configured via azure-monitor-opentelemetry package")
return True
except Exception as ex: # pylint: disable=broad-exception-caught
_logger.warning(
"Failed to configure Azure Monitor: %s",
ex,
exc_info=True,
)
return False
66 changes: 31 additions & 35 deletions tests/test_distro.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,9 @@ class TestUseMicrosoftOpenTelemetry(unittest.TestCase):
"""Tests for use_microsoft_opentelemetry() orchestration."""

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_azure_monitor_enabled_by_default(self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock):
"""Azure Monitor is enabled by default; providers are created first."""
def test_azure_monitor_enabled_by_default(self, azure_monitor_mock):
"""Azure Monitor is enabled by default; providers are created through Azure Monitor setup."""
use_microsoft_opentelemetry()
tracing_mock.assert_called_once()
metrics_mock.assert_called_once()
logging_mock.assert_called_once()
azure_monitor_mock.assert_called_once()

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
Expand Down Expand Up @@ -115,10 +109,7 @@ def test_explicit_disable(self, tracing_mock, metrics_mock, logging_mock, azure_
azure_monitor_mock.assert_not_called()

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_enable_key_not_forwarded(self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock):
def test_enable_key_not_forwarded(self, azure_monitor_mock):
"""enable_azure_monitor is consumed, not forwarded."""
use_microsoft_opentelemetry(
azure_monitor_connection_string=TEST_CONNECTION_STRING,
Expand All @@ -127,33 +118,30 @@ def test_enable_key_not_forwarded(self, tracing_mock, metrics_mock, logging_mock
actual_kwargs = azure_monitor_mock.call_args[1]
self.assertNotIn("enable_azure_monitor", actual_kwargs)

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_disable_tracing_skips_tracing(self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock):
def test_disable_tracing_skips_tracing(self, tracing_mock, metrics_mock, logging_mock):
"""disable_tracing=True skips TracerProvider creation."""
use_microsoft_opentelemetry(disable_tracing=True, enable_azure_monitor=False)
tracing_mock.assert_not_called()
metrics_mock.assert_called_once()
logging_mock.assert_called_once()

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_disable_metrics_skips_metrics(self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock):
def test_disable_metrics_skips_metrics(self, tracing_mock, metrics_mock, logging_mock):
"""disable_metrics=True skips MeterProvider creation."""
use_microsoft_opentelemetry(disable_metrics=True, enable_azure_monitor=False)
tracing_mock.assert_called_once()
metrics_mock.assert_not_called()
logging_mock.assert_called_once()

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_disable_logging_skips_logging(self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock):
def test_disable_logging_skips_logging(self, tracing_mock, metrics_mock, logging_mock):
"""disable_logging=True skips LoggerProvider creation."""
use_microsoft_opentelemetry(disable_logging=True, enable_azure_monitor=False)
tracing_mock.assert_called_once()
Expand All @@ -171,8 +159,7 @@ def test_setup_tracing_creates_provider(self, set_tp_mock):
self.assertIsInstance(tp, TracerProvider)
set_tp_mock.assert_called_once_with(tp)

@patch("microsoft.opentelemetry._distro.set_tracer_provider")
def test_setup_tracing_adds_span_processors(self, set_tp_mock):
def test_setup_tracing_adds_span_processors(self):
"""_setup_tracing adds user-supplied span processors."""
sp = MagicMock()
tp = _setup_tracing(TEST_RESOURCE, {"span_processors": [sp]})
Expand Down Expand Up @@ -204,10 +191,11 @@ def test_delegates_to_configure_azure_monitor(self):
with patch.dict(sys.modules, mods):
from microsoft.opentelemetry._distro import _setup_azure_monitor

_setup_azure_monitor(
result = _setup_azure_monitor(
connection_string=TEST_CONNECTION_STRING,
resource=TEST_RESOURCE,
)
self.assertTrue(result)
mock_module.configure_azure_monitor.assert_called_once_with(
connection_string=TEST_CONNECTION_STRING,
resource=TEST_RESOURCE,
Expand Down Expand Up @@ -244,24 +232,38 @@ def test_forwards_standard_config_keys(self):
self.assertEqual(actual_kwargs["logger_name"], "test")

def test_exception_handled_gracefully(self):
"""If configure_azure_monitor raises, it is caught and logged."""
"""If configure_azure_monitor raises, it is caught and logged; returns False."""
mods, mock_module = self._make_mock_modules()
mock_module.configure_azure_monitor.side_effect = Exception("config error")
with patch.dict(sys.modules, mods):
from microsoft.opentelemetry._distro import _setup_azure_monitor

# Should not raise
_setup_azure_monitor(connection_string=TEST_CONNECTION_STRING)
result = _setup_azure_monitor(connection_string=TEST_CONNECTION_STRING)
self.assertFalse(result)

@patch("microsoft.opentelemetry._distro._setup_azure_monitor", return_value=False)
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_fallback_providers_created_on_azure_monitor_failure(
self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock
):
"""When Azure Monitor setup fails, bare providers are created as fallback."""
use_microsoft_opentelemetry(
azure_monitor_connection_string=TEST_CONNECTION_STRING,
)
azure_monitor_mock.assert_called_once()
tracing_mock.assert_called_once()
metrics_mock.assert_called_once()
logging_mock.assert_called_once()


class TestEnableKwargsPassthrough(unittest.TestCase):
"""Tests that azure_monitor_ kwargs are remapped and passed through."""

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_enable_live_metrics_passed_through(self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock):
def test_enable_live_metrics_passed_through(self, azure_monitor_mock):
"""azure_monitor_enable_live_metrics is remapped and forwarded."""
use_microsoft_opentelemetry(
azure_monitor_connection_string=TEST_CONNECTION_STRING,
Expand All @@ -271,11 +273,8 @@ def test_enable_live_metrics_passed_through(self, tracing_mock, metrics_mock, lo
self.assertEqual(actual_kwargs["enable_live_metrics"], False)

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_enable_performance_counters_passed_through(
self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock
self, azure_monitor_mock
):
"""azure_monitor_enable_performance_counters is remapped and forwarded."""
use_microsoft_opentelemetry(
Expand All @@ -290,10 +289,7 @@ class TestAllConfigOptions(unittest.TestCase):
"""End-to-end test that every documented configuration option works."""

@patch("microsoft.opentelemetry._distro._setup_azure_monitor")
@patch("microsoft.opentelemetry._distro._setup_logging")
@patch("microsoft.opentelemetry._distro._setup_metrics")
@patch("microsoft.opentelemetry._distro._setup_tracing")
def test_all_options_end_to_end(self, tracing_mock, metrics_mock, logging_mock, azure_monitor_mock):
def test_all_options_end_to_end(self, azure_monitor_mock):
"""Every documented kwarg is accepted, remapped if needed, and forwarded."""
from logging import Formatter

Expand Down
Loading