Skip to content

Commit 5e0550a

Browse files
authored
Add custom events extension tracking in feature statsbeat (#33667)
1 parent fea09db commit 5e0550a

File tree

5 files changed

+88
-1
lines changed

5 files changed

+88
-1
lines changed

sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
([#33432](https://github.com/Azure/azure-sdk-for-python/pull/33432))
1515
- Shutdown statsbeat on customer getting 400 error code
1616
([#33489](https://github.com/Azure/azure-sdk-for-python/pull/33489))
17+
- Track custom events extension in feature statsbeat
18+
([#33667](https://github.com/Azure/azure-sdk-for-python/pull/33667))
1719
- Readme examples are updated with correct imports
1820
([#33691](https://github.com/Azure/azure-sdk-for-python/pull/33691))
1921

sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/logs/_exporter.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
BaseExporter,
2727
ExportResult,
2828
)
29+
from azure.monitor.opentelemetry.exporter.statsbeat._state import (
30+
get_statsbeat_shutdown,
31+
get_statsbeat_custom_events_feature_set,
32+
is_statsbeat_enabled,
33+
set_statsbeat_custom_events_feature_set,
34+
)
2935

3036
_logger = logging.getLogger(__name__)
3137

@@ -127,6 +133,7 @@ def _convert_log_to_envelope(log_data: LogData) -> TelemetryItem:
127133

128134
# Event telemetry
129135
if _log_data_is_event(log_data):
136+
_set_statsbeat_custom_events_feature()
130137
envelope.name = 'Microsoft.ApplicationInsights.Event'
131138
data = TelemetryEventData(
132139
name=str(log_record.body)[:32768],
@@ -196,3 +203,7 @@ def _is_ignored_attribute(key: str) -> bool:
196203
_APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE,
197204
)
198205
)
206+
207+
def _set_statsbeat_custom_events_feature():
208+
if is_statsbeat_enabled() and not get_statsbeat_shutdown() and not get_statsbeat_custom_events_feature_set():
209+
set_statsbeat_custom_events_feature_set()

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
@@ -13,6 +13,7 @@
1313
"INITIAL_FAILURE_COUNT": 0,
1414
"INITIAL_SUCCESS": False,
1515
"SHUTDOWN": False,
16+
"CUSTOM_EVENTS_FEATURE_SET": False,
1617
}
1718
_STATSBEAT_STATE_LOCK = threading.Lock()
1819
_STATSBEAT_FAILURE_COUNT_THRESHOLD = 3
@@ -47,3 +48,12 @@ def get_statsbeat_initial_success():
4748

4849
def get_statsbeat_shutdown():
4950
return _STATSBEAT_STATE["SHUTDOWN"]
51+
52+
53+
def get_statsbeat_custom_events_feature_set():
54+
return _STATSBEAT_STATE["CUSTOM_EVENTS_FEATURE_SET"]
55+
56+
57+
def set_statsbeat_custom_events_feature_set():
58+
with _STATSBEAT_STATE_LOCK:
59+
_STATSBEAT_STATE["CUSTOM_EVENTS_FEATURE_SET"] = True

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from azure.monitor.opentelemetry.exporter.statsbeat._state import (
2828
_REQUESTS_MAP_LOCK,
2929
_REQUESTS_MAP,
30+
get_statsbeat_custom_events_feature_set,
3031
)
3132
from azure.monitor.opentelemetry.exporter import _utils
3233

@@ -51,6 +52,7 @@ class _StatsbeatFeature:
5152
NONE = 0
5253
DISK_RETRY = 1
5354
AAD = 2
55+
CUSTOM_EVENTS_EXTENSION = 4
5456

5557

5658
class _AttachTypes:
@@ -102,6 +104,8 @@ def __init__(
102104
self._feature |= _StatsbeatFeature.DISK_RETRY
103105
if has_credential:
104106
self._feature |= _StatsbeatFeature.AAD
107+
if get_statsbeat_custom_events_feature_set():
108+
self._feature |= _StatsbeatFeature.CUSTOM_EVENTS_EXTENSION
105109
self._ikey = instrumentation_key
106110
self._meter_provider = meter_provider
107111
self._meter = self._meter_provider.get_meter(__name__)
@@ -215,6 +219,11 @@ def _get_feature_metric(self, options: CallbackOptions) -> Iterable[Observation]
215219
if not self._meets_long_interval_threshold(_FEATURE_METRIC_NAME[0]):
216220
return observations
217221
# Feature metric
222+
# Check if any features were enabled during runtime
223+
if get_statsbeat_custom_events_feature_set():
224+
self._feature |= _StatsbeatFeature.CUSTOM_EVENTS_EXTENSION
225+
_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"] = self._feature
226+
218227
# Don't send observation if no features enabled
219228
if self._feature is not _StatsbeatFeature.NONE:
220229
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)

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

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def func(*_args, **_kwargs):
5959
class TestStatsbeat(unittest.TestCase):
6060
def setUp(self):
6161
_statsbeat._STATSBEAT_METRICS = None
62+
_STATSBEAT_STATE["SHUTDOWN"] = False
6263

6364
@mock.patch.object(MeterProvider, 'shutdown')
6465
@mock.patch.object(MeterProvider, 'force_flush')
@@ -217,11 +218,11 @@ def test_collect_statsbeat_metrics_no_aad(
217218
)
218219

219220
def test_shutdown_statsbeat_metrics(self):
220-
_STATSBEAT_STATE["SHUTDOWN"] = False
221221
metric_mock = mock.Mock()
222222
mp_mock = mock.Mock()
223223
metric_mock._meter_provider = mp_mock
224224
_statsbeat._STATSBEAT_METRICS = metric_mock
225+
self.assertFalse(_STATSBEAT_STATE["SHUTDOWN"])
225226
_statsbeat.shutdown_statsbeat_metrics()
226227
mp_mock.shutdown.assert_called_once()
227228
self.assertIsNone(_statsbeat._STATSBEAT_METRICS)
@@ -274,6 +275,11 @@ def setUp(self):
274275
_StatsbeatMetrics_INSTRUMENTATION_ATTRIBUTES
275276
)
276277
_REQUESTS_MAP.clear()
278+
_STATSBEAT_STATE["INITIAL_FAILURE_COUNT"] = 0
279+
_STATSBEAT_STATE["INITIAL_SUCCESS"] = False
280+
_STATSBEAT_STATE["SHUTDOWN"] = False
281+
_STATSBEAT_STATE["CUSTOM_EVENTS_FEATURE_SET"] = False
282+
277283

278284
def test_statsbeat_metric_init(self):
279285
mp = MeterProvider()
@@ -685,6 +691,55 @@ def test_get_feature_metric_aad(self):
685691
self.assertEqual(len(observations), 1)
686692
self.assertEqual(_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"], _StatsbeatFeature.AAD)
687693

694+
# pylint: disable=protected-access
695+
def test_get_feature_metric_custom_events_init(self):
696+
mp = MeterProvider()
697+
ikey = "1aa11111-bbbb-1ccc-8ddd-eeeeffff3334"
698+
endpoint = "https://westus-1.in.applicationinsights.azure.com/"
699+
_STATSBEAT_STATE["CUSTOM_EVENTS_FEATURE_SET"] = True
700+
metric = _StatsbeatMetrics(
701+
mp,
702+
ikey,
703+
endpoint,
704+
True,
705+
0,
706+
False,
707+
)
708+
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
709+
attributes.update(_StatsbeatMetrics._FEATURE_ATTRIBUTES)
710+
self.assertEqual(attributes["feature"], 4)
711+
self.assertEqual(attributes["type"], _FEATURE_TYPES.FEATURE)
712+
observations = metric._get_feature_metric(options=None)
713+
for obs in observations:
714+
self.assertEqual(obs.value, 1)
715+
self.assertEqual(obs.attributes, attributes)
716+
717+
# pylint: disable=protected-access
718+
def test_get_feature_metric_custom_events_runtime(self):
719+
mp = MeterProvider()
720+
ikey = "1aa11111-bbbb-1ccc-8ddd-eeeeffff3334"
721+
endpoint = "https://westus-1.in.applicationinsights.azure.com/"
722+
metric = _StatsbeatMetrics(
723+
mp,
724+
ikey,
725+
endpoint,
726+
True,
727+
0,
728+
False,
729+
)
730+
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
731+
attributes.update(_StatsbeatMetrics._FEATURE_ATTRIBUTES)
732+
self.assertEqual(attributes["feature"], 0)
733+
self.assertEqual(attributes["type"], _FEATURE_TYPES.FEATURE)
734+
_STATSBEAT_STATE["CUSTOM_EVENTS_FEATURE_SET"] = True
735+
observations = metric._get_feature_metric(options=None)
736+
attributes.update(_StatsbeatMetrics._FEATURE_ATTRIBUTES)
737+
self.assertEqual(attributes["feature"], 4)
738+
self.assertEqual(metric._feature, 4)
739+
for obs in observations:
740+
self.assertEqual(obs.value, 1)
741+
self.assertEqual(obs.attributes, attributes)
742+
688743
# pylint: disable=protected-access
689744
def test_get_feature_metric_instrumentation(self):
690745
mp = MeterProvider()

0 commit comments

Comments
 (0)