Skip to content

Commit 7b7cdbc

Browse files
authored
Implement distro detection for statsbeat feature (#33761)
1 parent 0acd340 commit 7b7cdbc

12 files changed

Lines changed: 87 additions & 6 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
([#33667](https://github.com/Azure/azure-sdk-for-python/pull/33667))
2323
- Readme examples are updated with correct imports
2424
([#33691](https://github.com/Azure/azure-sdk-for-python/pull/33691))
25+
- Implement distro detection for statsbeat feature
26+
([#33761](https://github.com/Azure/azure-sdk-for-python/pull/33761))
2527

2628
## 1.0.0b19 (2023-11-20)
2729

sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
_REQUEST_ENVELOPE_NAME = "Microsoft.ApplicationInsights.Request"
4747
_REMOTE_DEPENDENCY_ENVELOPE_NAME = "Microsoft.ApplicationInsights.RemoteDependency"
4848

49+
# Feature constants
50+
_APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE = "APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE"
51+
_AZURE_MONITOR_DISTRO_VERSION_ARG = "distro_version"
52+
4953
# Statsbeat
5054

5155
# (OpenTelemetry metric name, Statsbeat metric name)
@@ -119,6 +123,8 @@
119123
"urllib",
120124
"urllib3",
121125
_AZURE_SDK_OPENTELEMETRY_NAME,
126+
"cassandra",
127+
"tortoiseorm",
122128
]
123129

124130
_INSTRUMENTATIONS_BIT_MAP = {_INSTRUMENTATIONS_LIST[i]: _BASE**i for i in range(len(_INSTRUMENTATIONS_LIST))}

sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
TelemetryItem,
3030
)
3131
from azure.monitor.opentelemetry.exporter._constants import (
32+
_AZURE_MONITOR_DISTRO_VERSION_ARG,
3233
_INVALID_STATUS_CODES,
3334
_REACHED_INGESTION_STATUS_CODES,
3435
_REDIRECT_STATUS_CODES,
@@ -100,6 +101,7 @@ def __init__(self, **kwargs: Any) -> None:
100101
self._storage_directory = kwargs.get('storage_directory', default_storage_directory) # Storage path in which to store retry files.
101102
self._storage_retention_period = kwargs.get('storage_retention_period', 48 * 60 * 60) # Retention period in seconds (default 48 hrs)
102103
self._timeout = kwargs.get('timeout', 10.0) # networking timeout in seconds
104+
self._distro_version = kwargs.get(_AZURE_MONITOR_DISTRO_VERSION_ARG, '') # If set, indicates the exporter is instantiated via Azure monitor OpenTelemetry distro. Versions corresponds to distro version.
103105

104106
config = AzureMonitorClientConfiguration(self._endpoint, **kwargs)
105107
policies = [

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
BaseExporter,
2727
ExportResult,
2828
)
29+
from azure.monitor.opentelemetry.exporter._constants import (
30+
_APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE,
31+
)
2932
from azure.monitor.opentelemetry.exporter.statsbeat._state import (
3033
get_statsbeat_shutdown,
3134
get_statsbeat_custom_events_feature_set,
@@ -40,7 +43,6 @@
4043

4144
__all__ = ["AzureMonitorLogExporter"]
4245

43-
_APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE = "APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE"
4446

4547
class AzureMonitorLogExporter(BaseExporter, LogExporter):
4648
"""Azure Monitor Log exporter for OpenTelemetry."""

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def collect_statsbeat_metrics(exporter) -> None:
6262
exporter._disable_offline_storage,
6363
long_interval_threshold,
6464
exporter._credential is not None,
65+
exporter._distro_version,
6566
)
6667
# Export some initial stats on program start
6768
mp.force_flush()

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class _StatsbeatFeature:
5353
DISK_RETRY = 1
5454
AAD = 2
5555
CUSTOM_EVENTS_EXTENSION = 4
56+
DISTRO = 8
5657

5758

5859
class _AttachTypes:
@@ -97,13 +98,16 @@ def __init__(
9798
disable_offline_storage: bool,
9899
long_interval_threshold: int,
99100
has_credential: bool,
101+
distro_version: str = "",
100102
) -> None:
101103
self._ikey = instrumentation_key
102104
self._feature = _StatsbeatFeature.NONE
103105
if not disable_offline_storage:
104106
self._feature |= _StatsbeatFeature.DISK_RETRY
105107
if has_credential:
106108
self._feature |= _StatsbeatFeature.AAD
109+
if distro_version:
110+
self._feature |= _StatsbeatFeature.DISTRO
107111
if get_statsbeat_custom_events_feature_set():
108112
self._feature |= _StatsbeatFeature.CUSTOM_EVENTS_EXTENSION
109113
self._ikey = instrumentation_key

sdk/monitor/azure-monitor-opentelemetry-exporter/tests/logs/test_logs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717

1818
from azure.monitor.opentelemetry.exporter.export._base import ExportResult
1919
from azure.monitor.opentelemetry.exporter.export.logs._exporter import (
20-
_APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE,
2120
AzureMonitorLogExporter,
2221
_get_log_export_result,
2322
_get_severity_level,
2423
)
24+
from azure.monitor.opentelemetry.exporter._constants import (
25+
_APPLICATION_INSIGHTS_EVENT_MARKER_ATTRIBUTE,
26+
)
2527
from azure.monitor.opentelemetry.exporter._generated.models import ContextTagKeys
2628
from azure.monitor.opentelemetry.exporter._utils import (
2729
azure_monitor_context,

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

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def test_collect_statsbeat_metrics_aad(
176176
exporter._instrumentation_key = TEST_IKEY
177177
exporter._disable_offline_storage = False
178178
exporter._credential = TEST_CREDENTIAL
179+
exporter._distro_version = ""
179180
_statsbeat.collect_statsbeat_metrics(exporter)
180181
mock_statsbeat_metrics.assert_called_once_with(
181182
mock.ANY,
@@ -184,6 +185,7 @@ def test_collect_statsbeat_metrics_aad(
184185
False,
185186
_DEFAULT_STATS_LONG_EXPORT_INTERVAL / _DEFAULT_STATS_SHORT_EXPORT_INTERVAL,
186187
True,
188+
"",
187189
)
188190

189191

@@ -207,6 +209,7 @@ def test_collect_statsbeat_metrics_no_aad(
207209
exporter._instrumentation_key = TEST_IKEY
208210
exporter._disable_offline_storage = False
209211
exporter._credential = TEST_CREDENTIAL
212+
exporter._distro_version = ""
210213
_statsbeat.collect_statsbeat_metrics(exporter)
211214
mock_statsbeat_metrics.assert_called_once_with(
212215
mock.ANY,
@@ -215,6 +218,39 @@ def test_collect_statsbeat_metrics_no_aad(
215218
False,
216219
_DEFAULT_STATS_LONG_EXPORT_INTERVAL / _DEFAULT_STATS_SHORT_EXPORT_INTERVAL,
217220
False,
221+
"",
222+
)
223+
224+
@mock.patch('azure.monitor.opentelemetry.exporter.statsbeat._statsbeat._StatsbeatMetrics')
225+
@mock.patch.dict(
226+
"os.environ",
227+
{
228+
"APPLICATION_INSIGHTS_STATS_SHORT_EXPORT_INTERVAL": "",
229+
"APPLICATION_INSIGHTS_STATS_LONG_EXPORT_INTERVAL": "",
230+
},
231+
)
232+
def test_collect_statsbeat_metrics_distro_version(
233+
self,
234+
mock_statsbeat_metrics,
235+
):
236+
exporter = mock.Mock()
237+
TEST_ENDPOINT = "test endpoint"
238+
TEST_IKEY = "test ikey"
239+
TEST_CREDENTIAL = None
240+
exporter._endpoint = TEST_ENDPOINT
241+
exporter._instrumentation_key = TEST_IKEY
242+
exporter._disable_offline_storage = False
243+
exporter._credential = TEST_CREDENTIAL
244+
exporter._distro_version = "1.0.0"
245+
_statsbeat.collect_statsbeat_metrics(exporter)
246+
mock_statsbeat_metrics.assert_called_once_with(
247+
mock.ANY,
248+
TEST_IKEY,
249+
TEST_ENDPOINT,
250+
False,
251+
_DEFAULT_STATS_LONG_EXPORT_INTERVAL / _DEFAULT_STATS_SHORT_EXPORT_INTERVAL,
252+
False,
253+
"1.0.0",
218254
)
219255

220256
def test_shutdown_statsbeat_metrics(self):
@@ -634,7 +670,7 @@ def test_get_feature_metric_does_not_meet_threshold(self):
634670
self.assertEqual(metric._long_interval_count_map[_FEATURE_METRIC_NAME[0]], 1)
635671

636672
# pylint: disable=protected-access
637-
def test_get_feature_metric(self):
673+
def test_get_feature_metric_storage(self):
638674
mp = MeterProvider()
639675
ikey = "1aa11111-bbbb-1ccc-8ddd-eeeeffff3334"
640676
endpoint = "https://westus-1.in.applicationinsights.azure.com/"
@@ -648,7 +684,7 @@ def test_get_feature_metric(self):
648684
)
649685
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
650686
attributes.update(_StatsbeatMetrics._FEATURE_ATTRIBUTES)
651-
self.assertEqual(attributes["feature"], 1)
687+
self.assertEqual(attributes["feature"], _StatsbeatFeature.DISK_RETRY)
652688
self.assertEqual(attributes["type"], _FEATURE_TYPES.FEATURE)
653689
observations = metric._get_feature_metric(options=None)
654690
for obs in observations:
@@ -740,6 +776,25 @@ def test_get_feature_metric_custom_events_runtime(self):
740776
self.assertEqual(obs.value, 1)
741777
self.assertEqual(obs.attributes, attributes)
742778

779+
# pylint: disable=protected-access
780+
def test_get_feature_metric_distro(self):
781+
mp = MeterProvider()
782+
ikey = "1aa11111-bbbb-1ccc-8ddd-eeeeffff3334"
783+
endpoint = "https://westus-1.in.applicationinsights.azure.com/"
784+
metric = _StatsbeatMetrics(
785+
mp,
786+
ikey,
787+
endpoint,
788+
True,
789+
0,
790+
False,
791+
"1.0.0"
792+
)
793+
self.assertEqual(_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"], _StatsbeatFeature.DISTRO)
794+
observations = metric._get_feature_metric(options=None)
795+
self.assertEqual(len(observations), 1)
796+
self.assertEqual(_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"], _StatsbeatFeature.DISTRO)
797+
743798
# pylint: disable=protected-access
744799
def test_get_feature_metric_instrumentation(self):
745800
mp = MeterProvider()

sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_base_exporter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def test_constructor(self):
101101
api_version="2021-02-10_Preview",
102102
connection_string="InstrumentationKey=4321abcd-5678-4efa-8abc-1234567890ab;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/",
103103
disable_offline_storage=False,
104+
distro_version="1.0.0",
104105
storage_maintenance_period=30,
105106
storage_max_size=1000,
106107
storage_min_retry_interval=100,
@@ -115,6 +116,7 @@ def test_constructor(self):
115116
base._endpoint,
116117
"https://westus-0.in.applicationinsights.azure.com/",
117118
)
119+
self.assertEqual(base._distro_version, "1.0.0")
118120
self.assertIsNotNone(base.storage)
119121
self.assertEqual(base.storage._max_size, 1000)
120122
self.assertEqual(base.storage._retention_period, 2000)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
### Other Changes
1212

13-
- Shutdown statsbeat on customer exporter 400 status code
14-
([#31881](https://github.com/Azure/azure-sdk-for-python/pull/31881))
13+
- Implement distro detection for statsbeat feature
14+
([#33761](https://github.com/Azure/azure-sdk-for-python/pull/33761))
1515

1616
## 1.1.1 (2023-12-04)
1717

0 commit comments

Comments
 (0)