Skip to content

Commit 56c346a

Browse files
authored
Add aks to statsbeat and prefix (#34427)
* Add aks to statsbeat and prefix * Fixed tests to run on vms
1 parent 9cda4c0 commit 56c346a

File tree

5 files changed

+98
-47
lines changed

5 files changed

+98
-47
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
- Add attachType character to sdkVersion prefix
1919
([#34226](https://github.com/Azure/azure-sdk-for-python/pull/34226))
20+
- Add AKS scenarios to statsbeat metric and sdkVersion prefix
21+
([#34427](https://github.com/Azure/azure-sdk-for-python/pull/34427))
2022

2123
## 1.0.0b22 (2024-02-01)
2224

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@
22
# Licensed under the MIT License.
33
# cSpell:disable
44

5+
from opentelemetry.semconv.metrics import MetricInstruments
6+
57
# Environment variables
68

79
_APPLICATIONINSIGHTS_STATSBEAT_DISABLED_ALL = "APPLICATIONINSIGHTS_STATSBEAT_DISABLED_ALL"
810
_APPLICATIONINSIGHTS_OPENTELEMETRY_RESOURCE_METRIC_DISABLED = \
911
"APPLICATIONINSIGHTS_OPENTELEMETRY_RESOURCE_METRIC_DISABLED"
12+
_WEBSITE_SITE_NAME = "WEBSITE_SITE_NAME"
13+
_WEBSITE_HOME_STAMPNAME = "WEBSITE_HOME_STAMPNAME"
14+
_WEBSITE_HOSTNAME = "WEBSITE_HOSTNAME"
15+
_FUNCTIONS_WORKER_RUNTIME = "FUNCTIONS_WORKER_RUNTIME"
16+
_AKS_ARM_NAMESPACE_ID = "AKS_ARM_NAMESPACE_ID"
1017

1118
# Network
1219

@@ -132,15 +139,14 @@
132139
# Standard metrics
133140

134141
# List of metric instrument names that are autocollected from instrumentations
135-
# TODO: switch to semconv constants
136142
_AUTOCOLLECTED_INSTRUMENT_NAMES = (
137-
"http.server.duration",
138-
"http.server.request.size",
139-
"http.server.response.size",
140-
"http.server.active_requests",
141-
"http.client.duration",
142-
"http.client.request.size",
143-
"http.client.response.size",
143+
MetricInstruments.HTTP_SERVER_DURATION,
144+
MetricInstruments.HTTP_SERVER_REQUEST_SIZE,
145+
MetricInstruments.HTTP_SERVER_RESPONSE_SIZE,
146+
MetricInstruments.HTTP_SERVER_ACTIVE_REQUESTS,
147+
MetricInstruments.HTTP_CLIENT_DURATION,
148+
MetricInstruments.HTTP_CLIENT_REQUEST_SIZE,
149+
MetricInstruments.HTTP_CLIENT_RESPONSE_SIZE,
144150
)
145151

146152
# Temporary solution for checking which instrumentations support metric collection

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717

1818
from azure.monitor.opentelemetry.exporter._generated.models import ContextTagKeys, TelemetryItem
1919
from azure.monitor.opentelemetry.exporter._version import VERSION as ext_version
20-
from azure.monitor.opentelemetry.exporter._constants import _INSTRUMENTATIONS_BIT_MAP
20+
from azure.monitor.opentelemetry.exporter._constants import (
21+
_INSTRUMENTATIONS_BIT_MAP,
22+
_WEBSITE_SITE_NAME,
23+
_FUNCTIONS_WORKER_RUNTIME,
24+
_AKS_ARM_NAMESPACE_ID,
25+
)
2126

2227

2328
opentelemetry_version = ""
@@ -35,16 +40,24 @@
3540
).version
3641

3742

43+
# Azure App Service
44+
3845
def _is_on_app_service():
39-
return environ.get("WEBSITE_SITE_NAME") is not None
46+
return environ.get(_WEBSITE_SITE_NAME) is not None
4047

4148
def _is_on_functions():
42-
return environ.get("FUNCTIONS_WORKER_RUNTIME") is not None
49+
return environ.get(_FUNCTIONS_WORKER_RUNTIME) is not None
4350

4451
def _is_attach_enabled():
4552
return isdir("/agents/python/")
4653

4754

55+
# AKS
56+
57+
def _is_on_aks():
58+
return _AKS_ARM_NAMESPACE_ID in environ
59+
60+
4861
def _get_sdk_version_prefix():
4962
sdk_version_prefix = ''
5063
rp = 'u'
@@ -55,9 +68,8 @@ def _get_sdk_version_prefix():
5568
# TODO: Add VM scenario outside statsbeat
5669
# elif _is_on_vm():
5770
# rp = 'v'
58-
# TODO: Add AKS scenario
59-
# elif _is_on_aks():
60-
# rp = 'k'
71+
elif _is_on_aks():
72+
rp = 'k'
6173

6274
os = 'u'
6375
system = platform.system()

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

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
3+
from enum import Enum
34
import json
45
import os
56
import platform
@@ -23,6 +24,10 @@
2324
_REQ_RETRY_NAME,
2425
_REQ_SUCCESS_NAME,
2526
_REQ_THROTTLE_NAME,
27+
_WEBSITE_HOME_STAMPNAME,
28+
_WEBSITE_HOSTNAME,
29+
_WEBSITE_SITE_NAME,
30+
_AKS_ARM_NAMESPACE_ID,
2631
)
2732
from azure.monitor.opentelemetry.exporter.statsbeat._state import (
2833
_REQUESTS_MAP_LOCK,
@@ -38,7 +43,12 @@
3843
_AIMS_FORMAT = "format=json"
3944

4045
_ENDPOINT_TYPES = ["breeze"]
41-
_RP_NAMES = ["appsvc", "functions", "vm", "unknown"]
46+
class _RP_Names(Enum):
47+
APP_SERVICE = "appsvc"
48+
FUNCTIONS = "functions"
49+
AKS = "aks"
50+
VM = "vm"
51+
UNKNOWN = "unknown"
4252

4353
_HOST_PATTERN = re.compile('^https?://(?:www\\.)?([^/.]+)')
4454

@@ -66,7 +76,7 @@ class _AttachTypes:
6676
class _StatsbeatMetrics:
6777

6878
_COMMON_ATTRIBUTES: Dict[str, Any] = {
69-
"rp": _RP_NAMES[3],
79+
"rp": _RP_Names.UNKNOWN.value,
7080
"attach": _AttachTypes.MANUAL,
7181
"cikey": None,
7282
"runtimeVersion": platform.python_version(),
@@ -161,27 +171,30 @@ def _get_attach_metric(self, options: CallbackOptions) -> Iterable[Observation]:
161171
# rp, rpId
162172
if _utils._is_on_app_service():
163173
# Web apps
164-
rp = _RP_NAMES[0]
174+
rp = _RP_Names.APP_SERVICE.value
165175
rpId = '{}/{}'.format(
166-
os.environ.get("WEBSITE_SITE_NAME"),
167-
os.environ.get("WEBSITE_HOME_STAMPNAME", '')
176+
os.environ.get(_WEBSITE_SITE_NAME),
177+
os.environ.get(_WEBSITE_HOME_STAMPNAME, '')
168178
)
169179
elif _utils._is_on_functions():
170180
# Function apps
171-
rp = _RP_NAMES[1]
172-
rpId = os.environ.get("WEBSITE_HOSTNAME", '')
181+
rp = _RP_Names.FUNCTIONS.value
182+
rpId = os.environ.get(_WEBSITE_HOSTNAME, '')
183+
elif _utils._is_on_aks():
184+
# AKS
185+
rp = _RP_Names.AKS.value
186+
rpId = os.environ.get(_AKS_ARM_NAMESPACE_ID, '')
173187
elif self._vm_retry and self._get_azure_compute_metadata():
174188
# VM
175-
rp = _RP_NAMES[2]
189+
rp = _RP_Names.VM.value
176190
rpId = '{}/{}'.format(
177191
self._vm_data.get("vmId", ''),
178192
self._vm_data.get("subscriptionId", ''))
179193
os_type = self._vm_data.get("osType", '')
180-
# TODO: add AKS scenario
181194
else:
182195
# Not in any rp or VM metadata failed
183-
rp = _RP_NAMES[3]
184-
rpId = _RP_NAMES[3]
196+
rp = _RP_Names.UNKNOWN.value
197+
rpId = _RP_Names.UNKNOWN.value
185198

186199
_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"] = rp
187200
_StatsbeatMetrics._COMMON_ATTRIBUTES["os"] = os_type or platform.system()

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

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
_StatsbeatFeature,
3939
_StatsbeatMetrics,
4040
_AttachTypes,
41-
_RP_NAMES,
41+
_RP_Names,
4242
)
4343

4444
class MockResponse(object):
@@ -334,7 +334,7 @@ def test_statsbeat_metric_init(self):
334334
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["cikey"], ikey)
335335
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["attach"], _AttachTypes.MANUAL)
336336
self.assertEqual(_StatsbeatMetrics._NETWORK_ATTRIBUTES["host"], "westus-1")
337-
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_NAMES[3])
337+
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_Names.UNKNOWN.value)
338338
self.assertEqual(_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"], 1)
339339
self.assertEqual(_StatsbeatMetrics._FEATURE_ATTRIBUTES["type"], _FEATURE_TYPES.FEATURE)
340340
self.assertEqual(metric._meter_provider, mp)
@@ -368,7 +368,7 @@ def test_statsbeat_metric_init_attach_enabled(self, attach_mock):
368368
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["cikey"], ikey)
369369
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["attach"], _AttachTypes.INTEGRATED)
370370
self.assertEqual(_StatsbeatMetrics._NETWORK_ATTRIBUTES["host"], "westus-1")
371-
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_NAMES[3])
371+
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_Names.UNKNOWN.value)
372372
self.assertEqual(_StatsbeatMetrics._FEATURE_ATTRIBUTES["feature"], 1)
373373
self.assertEqual(_StatsbeatMetrics._FEATURE_ATTRIBUTES["type"], _FEATURE_TYPES.FEATURE)
374374
self.assertEqual(metric._meter_provider, mp)
@@ -430,16 +430,17 @@ def test_get_attach_metric_does_not_meet_threshold(self):
430430
"WEBSITE_HOME_STAMPNAME": "stamp_name",
431431
}
432432
)
433-
def test_get_attach_metric_appsvc(self):
433+
@mock.patch("azure.monitor.opentelemetry.exporter.statsbeat._statsbeat_metrics._StatsbeatMetrics._get_azure_compute_metadata", return_value=False)
434+
def test_get_attach_metric_appsvc(self, metadata_mock):
434435
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
435-
self.assertEqual(attributes["rp"], _RP_NAMES[3])
436-
attributes["rp"] = _RP_NAMES[0]
436+
self.assertEqual(attributes["rp"], _RP_Names.UNKNOWN.value)
437+
attributes["rp"] = _RP_Names.APP_SERVICE.value
437438
attributes["rpId"] = "site_name/stamp_name"
438439
observations = self._metric._get_attach_metric(options=None)
439440
for obs in observations:
440441
self.assertEqual(obs.value, 1)
441442
self.assertEqual(obs.attributes, attributes)
442-
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_NAMES[0])
443+
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_Names.APP_SERVICE.value)
443444

444445
# pylint: disable=protected-access
445446
@mock.patch.dict(
@@ -449,18 +450,38 @@ def test_get_attach_metric_appsvc(self):
449450
"WEBSITE_HOSTNAME": "host_name",
450451
}
451452
)
452-
def test_get_attach_metric_functions(self):
453+
@mock.patch("azure.monitor.opentelemetry.exporter.statsbeat._statsbeat_metrics._StatsbeatMetrics._get_azure_compute_metadata", return_value=False)
454+
def test_get_attach_metric_functions(self, metadata_mock):
453455
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
454-
self.assertEqual(attributes["rp"], _RP_NAMES[3])
455-
attributes["rp"] = _RP_NAMES[1]
456+
self.assertEqual(attributes["rp"], _RP_Names.UNKNOWN.value)
457+
attributes["rp"] = _RP_Names.FUNCTIONS.value
456458
attributes["rpId"] = "host_name"
457459
observations = self._metric._get_attach_metric(options=None)
458460
for obs in observations:
459461
self.assertEqual(obs.value, 1)
460462
self.assertEqual(obs.attributes, attributes)
461-
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_NAMES[1])
463+
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_Names.FUNCTIONS.value)
462464

463-
def test_get_attach_metric_vm(self):
465+
# pylint: disable=protected-access
466+
@mock.patch.dict(
467+
os.environ,
468+
{
469+
"AKS_ARM_NAMESPACE_ID": "namespace_id",
470+
}
471+
)
472+
def test_get_attach_metric_aks(self):
473+
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
474+
self.assertEqual(attributes["rp"], _RP_Names.UNKNOWN.value)
475+
attributes["rp"] = _RP_Names.AKS.value
476+
attributes["rpId"] = "namespace_id"
477+
observations = self._metric._get_attach_metric(options=None)
478+
for obs in observations:
479+
self.assertEqual(obs.value, 1)
480+
self.assertEqual(obs.attributes, attributes)
481+
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_Names.AKS.value)
482+
483+
@mock.patch("azure.monitor.opentelemetry.exporter.statsbeat._statsbeat_metrics._StatsbeatMetrics._get_azure_compute_metadata")
484+
def test_get_attach_metric_vm(self, metadata_mock):
464485
mp = MeterProvider()
465486
ikey = "1aa11111-bbbb-1ccc-8ddd-eeeeffff3334"
466487
endpoint = "https://westus-1.in.applicationinsights.azure.com/"
@@ -478,23 +499,22 @@ def test_get_attach_metric_vm(self):
478499
_vm_data["osType"] = "test_os"
479500
metric._vm_data = _vm_data
480501
metric._vm_retry = True
481-
metadata_mock = mock.Mock()
482502
metadata_mock.return_value = True
483-
metric._get_azure_compute_metadata = metadata_mock
484503
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
485-
self.assertEqual(attributes["rp"], _RP_NAMES[3])
504+
self.assertEqual(attributes["rp"], _RP_Names.UNKNOWN.value)
486505
self.assertEqual(attributes["os"], platform.system())
487-
attributes["rp"] = _RP_NAMES[2]
506+
attributes["rp"] = _RP_Names.VM.value
488507
attributes["rpId"] = "123/sub123"
489508
attributes["os"] = "test_os"
490509
observations = metric._get_attach_metric(options=None)
491510
for obs in observations:
492511
self.assertEqual(obs.value, 1)
493512
self.assertEqual(obs.attributes, attributes)
494-
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_NAMES[2])
513+
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["rp"], _RP_Names.VM.value)
495514
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["os"], "test_os")
496515

497-
def test_get_attach_metric_vm_no_os(self):
516+
@mock.patch("azure.monitor.opentelemetry.exporter.statsbeat._statsbeat_metrics._StatsbeatMetrics._get_azure_compute_metadata", return_value=False)
517+
def test_get_attach_metric_vm_no_os(self, metadata_mock):
498518
mp = MeterProvider()
499519
ikey = "1aa11111-bbbb-1ccc-8ddd-eeeeffff3334"
500520
endpoint = "https://westus-1.in.applicationinsights.azure.com/"
@@ -512,10 +532,8 @@ def test_get_attach_metric_vm_no_os(self):
512532
_vm_data["osType"] = None
513533
metric._vm_data = _vm_data
514534
metric._vm_retry = True
515-
metadata_mock = mock.Mock()
516535
metadata_mock.return_value = True
517536
self.assertEqual(_StatsbeatMetrics._COMMON_ATTRIBUTES["os"], platform.system())
518-
metric._get_azure_compute_metadata = metadata_mock
519537
observations = metric._get_attach_metric(options=None)
520538
for obs in observations:
521539
self.assertEqual(obs.value, 1)
@@ -536,11 +554,11 @@ def test_get_attach_metric_unknown(self):
536554
)
537555
metric._vm_retry = False
538556
attributes = dict(_StatsbeatMetrics._COMMON_ATTRIBUTES)
539-
self.assertEqual(attributes["rp"], _RP_NAMES[3])
557+
self.assertEqual(attributes["rp"], _RP_Names.UNKNOWN.value)
540558
observations = metric._get_attach_metric(options=None)
541559
for obs in observations:
542560
self.assertEqual(obs.value, 1)
543-
self.assertEqual(obs.attributes["rp"], _RP_NAMES[3])
561+
self.assertEqual(obs.attributes["rp"], _RP_Names.UNKNOWN.value)
544562

545563
def test_get_azure_compute_metadata(self):
546564
mp = MeterProvider()

0 commit comments

Comments
 (0)