Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
### Bugs Fixed

### Other Changes
- Track live metrics disabling in feature SDKstats
Comment thread
rads-1996 marked this conversation as resolved.
([#47297](https://github.com/Azure/azure-sdk-for-python/pull/47297))

## 1.0.0b52 (2026-05-12)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@ def enable_live_metrics(**kwargs: Any) -> None: # pylint: disable=C4758
if config_manager:
config_manager.register_callback(get_quickpulse_configuration_callback)

# We can detect feature usage for statsbeat since we are in an opt-in model currently
# Once we move to live metrics on-by-default, we will have to check for both explicit usage
# and whether or not user is actually using live metrics (being on live metrics blade in UX)
set_statsbeat_live_metrics_feature_set()
# Live metrics disable tracking is handled via local config flow.


def get_quickpulse_configuration_callback(settings: Dict[str, str]) -> None:
Expand All @@ -74,8 +71,14 @@ def get_quickpulse_configuration_callback(settings: Dict[str, str]) -> None:
resource=manager._resource, # pylint:disable=protected-access
)
elif live_metrics_enabled is False and manager.is_initialized():
# Track explicit live metrics disable for statsbeat feature reporting.
# (Tracking the disable live metrics feature starting 06/03/2026)
set_statsbeat_live_metrics_feature_set()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: Can we add a comment or in the CHANGELOG the release date for when live metrics feature bit meaning switches to the opposite?

# Disable live metrics if it's currently enabled
manager.shutdown()
elif live_metrics_enabled is False:
# Track explicit live metrics disable even when quickpulse is already off.
set_statsbeat_live_metrics_feature_set()
Comment thread
rads-1996 marked this conversation as resolved.


def shutdown_live_metrics() -> bool:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

from opentelemetry.sdk.resources import Resource

from azure.monitor.opentelemetry.exporter._quickpulse._live_metrics import enable_live_metrics
from azure.monitor.opentelemetry.exporter._quickpulse._live_metrics import (
enable_live_metrics,
get_quickpulse_configuration_callback,
)


class TestLiveMetrics(unittest.TestCase):
Expand All @@ -35,8 +38,8 @@ def test_enable_live_metrics_basic(self, manager_mock, statsbeat_mock):
credential="test-credential",
)

# Verify statsbeat feature was set
statsbeat_mock.assert_called_once()
# Enable path should not explicitly track statsbeat feature.
statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
Expand All @@ -54,8 +57,8 @@ def test_enable_live_metrics_initialization_fails(self, manager_mock, statsbeat_
# Verify manager was initialized with connection string
mock_manager_instance.initialize.assert_called_once_with(connection_string="InstrumentationKey=test-key")

# Verify statsbeat feature was still set (regardless of initialization success)
statsbeat_mock.assert_called_once()
# Enable path should not explicitly track statsbeat feature.
statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
Expand All @@ -73,8 +76,8 @@ def test_enable_live_metrics_with_minimal_args(self, manager_mock, statsbeat_moc
# Verify initialization was attempted with no kwargs
mock_manager_instance.initialize.assert_called_once_with()

# Verify statsbeat feature was set
statsbeat_mock.assert_called_once()
# Enable path should not explicitly track statsbeat feature.
statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
Expand Down Expand Up @@ -142,8 +145,8 @@ def test_enable_live_metrics_empty_string_connection(self, manager_mock, statsbe
# Verify initialization was called with empty string
mock_manager_instance.initialize.assert_called_once_with(connection_string="")

# Verify statsbeat feature was set
statsbeat_mock.assert_called_once()
# Enable path should not explicitly track statsbeat feature.
statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
Expand Down Expand Up @@ -178,8 +181,8 @@ def test_enable_live_metrics_complex_resource(self, manager_mock, statsbeat_mock
connection_string="InstrumentationKey=test-key", resource=mock_resource
)

# Verify statsbeat feature was set
statsbeat_mock.assert_called_once()
# Enable path should not explicitly track statsbeat feature.
statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
Expand All @@ -205,8 +208,8 @@ def test_enable_live_metrics_multiple_calls(self, manager_mock, statsbeat_mock):
]
mock_manager_instance.initialize.assert_has_calls(expected_calls)

# Verify statsbeat feature was set twice
self.assertEqual(statsbeat_mock.call_count, 2)
# Enable path should not explicitly track statsbeat feature.
statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
Expand All @@ -233,8 +236,55 @@ def test_enable_live_metrics_kwargs_preservation(self, manager_mock, statsbeat_m
# Verify all kwargs were passed through to initialize
mock_manager_instance.initialize.assert_called_once_with(**custom_kwargs)

# Verify statsbeat feature was set
statsbeat_mock.assert_called_once()
# Enable path should not explicitly track statsbeat feature.
statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.evaluate_feature")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
def test_get_quickpulse_configuration_callback_disable_tracks_feature(
self, manager_mock, evaluate_mock, statsbeat_mock
):
mock_manager_instance = mock.Mock()
mock_manager_instance.is_initialized.return_value = True
manager_mock.return_value = mock_manager_instance
evaluate_mock.return_value = False

get_quickpulse_configuration_callback({})

statsbeat_mock.assert_called_once_with()
mock_manager_instance.shutdown.assert_called_once()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.evaluate_feature")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
def test_get_quickpulse_configuration_callback_enable_does_not_track_feature(
self, manager_mock, evaluate_mock, statsbeat_mock
):
mock_manager_instance = mock.Mock()
mock_manager_instance.is_initialized.return_value = True
manager_mock.return_value = mock_manager_instance
evaluate_mock.return_value = True

get_quickpulse_configuration_callback({})

statsbeat_mock.assert_not_called()

@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.set_statsbeat_live_metrics_feature_set")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.evaluate_feature")
@mock.patch("azure.monitor.opentelemetry.exporter._quickpulse._live_metrics.get_quickpulse_manager")
def test_get_quickpulse_configuration_callback_disable_tracks_feature_when_manager_off(
self, manager_mock, evaluate_mock, statsbeat_mock
):
mock_manager_instance = mock.Mock()
mock_manager_instance.is_initialized.return_value = False
manager_mock.return_value = mock_manager_instance
evaluate_mock.return_value = False

get_quickpulse_configuration_callback({})

statsbeat_mock.assert_called_once_with()
mock_manager_instance.shutdown.assert_not_called()


# cSpell:enable
Loading