Skip to content

Commit 14558ae

Browse files
committed
Address feedback
1 parent 1eeccd2 commit 14558ae

6 files changed

Lines changed: 49 additions & 2 deletions

File tree

sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/statsbeat/_manager.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ def __init__(self) -> None:
156156
self._initialized: bool = False # type: ignore
157157
self._metrics: Optional[_StatsbeatMetrics] = None # type: ignore
158158
self._meter_provider: Optional[MeterProvider] = None # type: ignore
159+
self._warmup_timer: Optional[threading.Timer] = None
159160

160161
# Set during first initialization, preserved in shutdown for potential re-initialization
161162
self._config: Optional[StatsbeatConfig] = None # type: ignore
@@ -274,10 +275,14 @@ def _flush() -> None:
274275

275276
timer = threading.Timer(_STATSBEAT_INITIAL_EXPORT_WARMUP_SECONDS, _flush)
276277
timer.daemon = True
278+
self._warmup_timer = timer
277279
timer.start()
278280

279281
def _cleanup(self, shutdown_meter_provider: bool = True) -> None:
280282
# Clean up resources with optional meter provider shutdown
283+
if hasattr(self, '_warmup_timer') and self._warmup_timer:
284+
self._warmup_timer.cancel()
285+
self._warmup_timer = None
281286
if shutdown_meter_provider and self._meter_provider:
282287
try:
283288
self._meter_provider.shutdown()

sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/statsbeat/_state.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"LIVE_METRICS_FEATURE_SET": False,
2121
"CUSTOMER_SDKSTATS_FEATURE_SET": False,
2222
"BROWSER_SDK_LOADER_FEATURE_SET": False,
23+
"FEATURE_ATTRIBUTE_BITS": 0,
2324
}
2425
_STATSBEAT_STATE_LOCK = threading.Lock()
2526
_STATSBEAT_FAILURE_COUNT_THRESHOLD = 3
@@ -115,3 +116,12 @@ def get_statsbeat_browser_sdk_loader_feature_set(): # pylint: disable=name-too-
115116
def set_statsbeat_browser_sdk_loader_feature_set(): # pylint: disable=name-too-long
116117
with _STATSBEAT_STATE_LOCK:
117118
_STATSBEAT_STATE["BROWSER_SDK_LOADER_FEATURE_SET"] = True
119+
120+
121+
def get_statsbeat_feature_attribute_bits() -> int:
122+
return int(_STATSBEAT_STATE["FEATURE_ATTRIBUTE_BITS"])
123+
124+
125+
def set_statsbeat_feature_attribute_bits(feature_bits: int) -> None:
126+
with _STATSBEAT_STATE_LOCK:
127+
_STATSBEAT_STATE["FEATURE_ATTRIBUTE_BITS"] = int(feature_bits)

sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/statsbeat/_statsbeat_metrics.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
from azure.monitor.opentelemetry.exporter.statsbeat._state import (
3434
_REQUESTS_MAP_LOCK,
3535
_REQUESTS_MAP,
36+
get_statsbeat_feature_attribute_bits,
37+
set_statsbeat_feature_attribute_bits,
3638
get_statsbeat_live_metrics_feature_set,
3739
get_statsbeat_custom_events_feature_set,
3840
get_statsbeat_customer_sdkstats_feature_set,
@@ -133,7 +135,7 @@ def __init__(
133135
_StatsbeatMetrics._COMMON_ATTRIBUTES["version"] = _get_version()
134136

135137
self._ikey = instrumentation_key
136-
self._feature = _StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] or _StatsbeatFeature.NONE
138+
self._feature = get_statsbeat_feature_attribute_bits()
137139
if not disable_offline_storage:
138140
self._feature |= _StatsbeatFeature.DISK_RETRY
139141
if has_credential:
@@ -166,6 +168,7 @@ def __init__(
166168

167169
_StatsbeatMetrics._NETWORK_ATTRIBUTES["host"] = _shorten_host(endpoint)
168170
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = self._feature
171+
set_statsbeat_feature_attribute_bits(self._feature)
169172
_StatsbeatMetrics._INSTRUMENTATION_ATTRIBUTES["feature"] = _utils.get_instrumentations()
170173

171174
self._vm_retry = True # True if we want to attempt to find if in VM
@@ -264,22 +267,27 @@ def _get_feature_metric(self, options: CallbackOptions) -> Iterable[Observation]
264267
return observations
265268
# Feature metric
266269
# Check if any features were enabled during runtime
267-
feature_bits = int(_StatsbeatMetrics._FEATURE_ATTRIBUTES.get("feature") or 0)
270+
feature_bits = get_statsbeat_feature_attribute_bits()
268271
if feature_bits:
269272
self._feature |= feature_bits
270273
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = self._feature
274+
set_statsbeat_feature_attribute_bits(self._feature)
271275
if get_statsbeat_custom_events_feature_set():
272276
self._feature |= _StatsbeatFeature.CUSTOM_EVENTS_EXTENSION
273277
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = self._feature
278+
set_statsbeat_feature_attribute_bits(self._feature)
274279
if get_statsbeat_live_metrics_feature_set():
275280
self._feature |= _StatsbeatFeature.LIVE_METRICS
276281
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = self._feature
282+
set_statsbeat_feature_attribute_bits(self._feature)
277283
if get_statsbeat_customer_sdkstats_feature_set():
278284
self._feature |= _StatsbeatFeature.CUSTOMER_SDKSTATS
279285
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = self._feature
286+
set_statsbeat_feature_attribute_bits(self._feature)
280287
if get_statsbeat_browser_sdk_loader_feature_set():
281288
self._feature |= _StatsbeatFeature.BROWSER_SDK_LOADER
282289
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = self._feature
290+
set_statsbeat_feature_attribute_bits(self._feature)
283291

284292
# Don't send observation if no features enabled
285293
if self._feature is not _StatsbeatFeature.NONE:

sdk/monitor/azure-monitor-opentelemetry-exporter/tests/statsbeat/test_manager.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ def setUp(self):
270270
self.manager._metrics = None
271271
if hasattr(self.manager, "_meter_provider"):
272272
self.manager._meter_provider = None
273+
if hasattr(self.manager, "_warmup_timer"):
274+
self.manager._warmup_timer = None
273275

274276
def tearDown(self):
275277
"""Clean up after tests."""
@@ -673,6 +675,8 @@ def test_cleanup_with_shutdown(self):
673675
self.manager._initialized = True
674676
mock_meter_provider = Mock()
675677
self.manager._meter_provider = mock_meter_provider
678+
mock_timer = Mock()
679+
self.manager._warmup_timer = mock_timer
676680
self.manager._metrics = Mock()
677681
config_mock = Mock()
678682
self.manager._config = config_mock
@@ -682,8 +686,10 @@ def test_cleanup_with_shutdown(self):
682686
self.assertFalse(self.manager._initialized)
683687
self.assertIsNone(self.manager._meter_provider)
684688
self.assertIsNone(self.manager._metrics)
689+
self.assertIsNone(self.manager._warmup_timer)
685690
# Config is intact for potential re-initialization
686691
self.assertEqual(self.manager._config, config_mock)
692+
mock_timer.cancel.assert_called_once()
687693
mock_meter_provider.shutdown.assert_called_once()
688694

689695
def test_cleanup_without_shutdown(self):
@@ -692,6 +698,8 @@ def test_cleanup_without_shutdown(self):
692698
self.manager._initialized = True
693699
mock_meter_provider = Mock()
694700
self.manager._meter_provider = mock_meter_provider
701+
mock_timer = Mock()
702+
self.manager._warmup_timer = mock_timer
695703
self.manager._metrics = Mock()
696704
config_mock = Mock()
697705
self.manager._config = config_mock
@@ -701,8 +709,10 @@ def test_cleanup_without_shutdown(self):
701709
self.assertFalse(self.manager._initialized)
702710
self.assertIsNone(self.manager._meter_provider)
703711
self.assertIsNone(self.manager._metrics)
712+
self.assertIsNone(self.manager._warmup_timer)
704713
# Config is intact for potential re-initialization
705714
self.assertEqual(self.manager._config, config_mock)
715+
mock_timer.cancel.assert_called_once()
706716
mock_meter_provider.shutdown.assert_not_called()
707717

708718
def test_cleanup_meter_provider_exception(self):

sdk/monitor/azure-monitor-opentelemetry-exporter/tests/statsbeat/test_metrics.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
_REQUESTS_MAP,
2525
_STATSBEAT_STATE,
2626
_STATSBEAT_STATE_LOCK,
27+
get_statsbeat_feature_attribute_bits,
28+
set_statsbeat_feature_attribute_bits,
2729
)
2830
from azure.monitor.opentelemetry.exporter.statsbeat._statsbeat_metrics import (
2931
_shorten_host,
@@ -87,6 +89,7 @@ def setUp(self):
8789
_STATSBEAT_STATE["CUSTOM_EVENTS_FEATURE_SET"] = False
8890
_STATSBEAT_STATE["LIVE_METRICS_FEATURE_SET"] = False
8991
_STATSBEAT_STATE["CUSTOMER_SDKSTATS_FEATURE_SET"] = False
92+
_STATSBEAT_STATE["FEATURE_ATTRIBUTE_BITS"] = 0
9093

9194
_StatsbeatMetrics._COMMON_ATTRIBUTES = dict(_StatsbeatMetrics_COMMON_ATTRS)
9295
_StatsbeatMetrics._NETWORK_ATTRIBUTES = dict(_StatsbeatMetrics_NETWORK_ATTRS)
@@ -126,6 +129,14 @@ def test_statsbeat_metric_init(self):
126129
self.assertEqual(metric._attach_metric.name, _ATTACH_METRIC_NAME[0])
127130
self.assertEqual(metric._feature_metric.name, _FEATURE_METRIC_NAME[0])
128131

132+
def test_statsbeat_feature_attribute_bits_getter_default(self):
133+
self.assertEqual(get_statsbeat_feature_attribute_bits(), 0)
134+
135+
def test_statsbeat_feature_attribute_bits_setter_and_getter(self):
136+
feature_bits = _StatsbeatFeature.DISK_RETRY | _StatsbeatFeature.LIVE_METRICS
137+
set_statsbeat_feature_attribute_bits(feature_bits)
138+
self.assertEqual(get_statsbeat_feature_attribute_bits(), feature_bits)
139+
129140
@mock.patch("azure.monitor.opentelemetry.exporter._utils._is_attach_enabled")
130141
def test_statsbeat_metric_init_attach_enabled(self, attach_mock):
131142
mp = MeterProvider()
@@ -717,6 +728,7 @@ def test_get_feature_metric_instrumentation(self):
717728
)
718729
metric._feature = _StatsbeatFeature.NONE
719730
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = _StatsbeatFeature.NONE
731+
set_statsbeat_feature_attribute_bits(_StatsbeatFeature.NONE)
720732
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
721733
attributes.update(_StatsbeatMetrics._INSTRUMENTATION_ATTRIBUTES)
722734
self.assertEqual(attributes["type"], _FEATURE_TYPES.INSTRUMENTATION)
@@ -749,6 +761,7 @@ def test_get_feature_metric_instrumentation_none(self):
749761
)
750762
metric._feature = _StatsbeatFeature.NONE
751763
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = _StatsbeatFeature.NONE
764+
set_statsbeat_feature_attribute_bits(_StatsbeatFeature.NONE)
752765
self.assertEqual(_StatsbeatMetrics._INSTRUMENTATION_ATTRIBUTES["feature"], 0)
753766
with mock.patch("azure.monitor.opentelemetry.exporter._utils.get_instrumentations") as instrumentations:
754767
instrumentations.return_value = 0

sdk/monitor/azure-monitor-opentelemetry-exporter/tests/statsbeat/test_statsbeat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def setUp(self):
4343
_STATSBEAT_STATE["CUSTOM_EVENTS_FEATURE_SET"] = False
4444
_STATSBEAT_STATE["LIVE_METRICS_FEATURE_SET"] = False
4545
_STATSBEAT_STATE["CUSTOMER_SDKSTATS_FEATURE_SET"] = False
46+
_STATSBEAT_STATE["FEATURE_ATTRIBUTE_BITS"] = 0
4647
_StatsbeatMetrics._FEATURE_ATTRIBUTES = dict(_StatsbeatMetrics_FEATURE_ATTRIBUTES)
4748

4849
def tearDown(self):

0 commit comments

Comments
 (0)