Skip to content
This repository was archived by the owner on Sep 17, 2025. It is now read-only.

Commit 58a08a1

Browse files
authored
Support statsbeat in EU regions (#1105)
1 parent d63d295 commit 58a08a1

File tree

5 files changed

+157
-13
lines changed

5 files changed

+157
-13
lines changed

contrib/opencensus-ext-azure/CHANGELOG.md

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

55
- Statsbeat bug fixes, shorten host in network stats
66
([#1100](https://github.com/census-instrumentation/opencensus-python/pull/1100))
7+
- Support statsbeat in EU regions
8+
([#1105](https://github.com/census-instrumentation/opencensus-python/pull/1105))
79

810
## 1.1.1
911
Released 2022-01-19

contrib/opencensus-ext-azure/opencensus/ext/azure/metrics_exporter/statsbeat_metrics/__init__.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,29 @@
1616

1717
from opencensus.ext.azure.metrics_exporter import MetricsExporter
1818
from opencensus.ext.azure.metrics_exporter.statsbeat_metrics.statsbeat import (
19-
_STATS_CONNECTION_STRING,
2019
_STATS_SHORT_EXPORT_INTERVAL,
20+
_get_stats_connection_string,
2121
_StatsbeatMetrics,
2222
)
2323
from opencensus.metrics import transport
2424
from opencensus.metrics.export.metric_producer import MetricProducer
2525

2626
_STATSBEAT_METRICS = None
27+
_STATSBEAT_EXPORTER = None
2728
_STATSBEAT_LOCK = threading.Lock()
2829

2930

3031
def collect_statsbeat_metrics(options):
31-
with _STATSBEAT_LOCK:
32-
# Only start statsbeat if did not exist before
33-
global _STATSBEAT_METRICS # pylint: disable=global-statement
34-
if _STATSBEAT_METRICS is None:
32+
# pylint: disable=global-statement
33+
global _STATSBEAT_METRICS
34+
global _STATSBEAT_EXPORTER
35+
# Only start statsbeat if did not exist before
36+
if _STATSBEAT_METRICS is None and _STATSBEAT_EXPORTER is None:
37+
with _STATSBEAT_LOCK:
38+
# Only start statsbeat if did not exist before
3539
exporter = MetricsExporter(
3640
is_stats=True,
37-
connection_string=_STATS_CONNECTION_STRING,
41+
connection_string=_get_stats_connection_string(options.endpoint), # noqa: E501
3842
enable_standard_metrics=False,
3943
export_interval=_STATS_SHORT_EXPORT_INTERVAL, # 15m by default
4044
)
@@ -47,6 +51,7 @@ def collect_statsbeat_metrics(options):
4751
transport.get_exporter_thread([_STATSBEAT_METRICS],
4852
exporter,
4953
exporter.options.export_interval)
54+
_STATSBEAT_EXPORTER = exporter
5055

5156

5257
class _AzureStatsbeatMetricsProducer(MetricProducer):

contrib/opencensus-ext-azure/opencensus/ext/azure/metrics_exporter/statsbeat_metrics/statsbeat.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,22 @@
3737
_AIMS_API_VERSION = "api-version=2017-12-01"
3838
_AIMS_FORMAT = "format=json"
3939

40-
_DEFAULT_STATS_CONNECTION_STRING = "InstrumentationKey=c4a29126-a7cb-47e5-b348-11414998b11e;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/" # noqa: E501
40+
_DEFAULT_NON_EU_STATS_CONNECTION_STRING = "InstrumentationKey=c4a29126-a7cb-47e5-b348-11414998b11e;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/" # noqa: E501
41+
_DEFAULT_EU_STATS_CONNECTION_STRING = "InstrumentationKey=7dc56bab-3c0c-4e9f-9ebb-d1acadee8d0f;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/" # noqa: E501
4142
_DEFAULT_STATS_SHORT_EXPORT_INTERVAL = 900 # 15 minutes
4243
_DEFAULT_STATS_LONG_EXPORT_INTERVAL = 86400 # 24 hours
44+
_EU_ENDPOINTS = [
45+
"westeurope",
46+
"northeurope",
47+
"francecentral",
48+
"francesouth",
49+
"germanywestcentral",
50+
"norwayeast",
51+
"norwaywest",
52+
"swedencentral",
53+
"switzerlandnorth",
54+
"switzerlandwest",
55+
]
4356

4457
_ATTACH_METRIC_NAME = "Attach"
4558
_FEATURE_METRIC_NAME = "Feature"
@@ -69,12 +82,16 @@ class _StatsbeatFeature:
6982
AAD = 2
7083

7184

72-
def _get_stats_connection_string():
85+
def _get_stats_connection_string(endpoint):
7386
cs_env = os.environ.get("APPLICATION_INSIGHTS_STATS_CONNECTION_STRING")
7487
if cs_env:
7588
return cs_env
7689
else:
77-
return _DEFAULT_STATS_CONNECTION_STRING
90+
for ep in _EU_ENDPOINTS:
91+
if ep in endpoint:
92+
# Use statsbeat EU endpoint if user is in EU region
93+
return _DEFAULT_EU_STATS_CONNECTION_STRING
94+
return _DEFAULT_NON_EU_STATS_CONNECTION_STRING
7895

7996

8097
def _get_stats_short_export_interval():
@@ -93,7 +110,6 @@ def _get_stats_long_export_interval():
93110
return _DEFAULT_STATS_LONG_EXPORT_INTERVAL
94111

95112

96-
_STATS_CONNECTION_STRING = _get_stats_connection_string()
97113
_STATS_SHORT_EXPORT_INTERVAL = _get_stats_short_export_interval()
98114
_STATS_LONG_EXPORT_INTERVAL = _get_stats_long_export_interval()
99115
_STATS_LONG_INTERVAL_THRESHOLD = _STATS_LONG_EXPORT_INTERVAL / _STATS_SHORT_EXPORT_INTERVAL # noqa: E501

contrib/opencensus-ext-azure/tests/test_azure_statsbeat_metrics.py

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,13 @@
2323
from opencensus.ext.azure.common import Options
2424
from opencensus.ext.azure.common.transport import _requests_map
2525
from opencensus.ext.azure.common.version import __version__ as ext_version
26-
from opencensus.ext.azure.metrics_exporter import statsbeat_metrics
26+
from opencensus.ext.azure.metrics_exporter import (
27+
MetricsExporter,
28+
statsbeat_metrics,
29+
)
2730
from opencensus.ext.azure.metrics_exporter.statsbeat_metrics.statsbeat import (
31+
_DEFAULT_EU_STATS_CONNECTION_STRING,
32+
_DEFAULT_NON_EU_STATS_CONNECTION_STRING,
2833
_ENDPOINT_TYPES,
2934
_FEATURE_TYPES,
3035
_RP_NAMES,
@@ -37,6 +42,7 @@
3742
_get_feature_properties,
3843
_get_network_properties,
3944
_get_retry_count_value,
45+
_get_stats_connection_string,
4046
_get_success_count_value,
4147
_get_throttle_count_value,
4248
_shorten_host,
@@ -78,6 +84,7 @@ class TestStatsbeatMetrics(unittest.TestCase):
7884
def setUp(self):
7985
# pylint: disable=protected-access
8086
statsbeat_metrics._STATSBEAT_METRICS = None
87+
statsbeat_metrics._STATSBEAT_EXPORTER = None
8188

8289
def test_producer_ctor(self):
8390
# pylint: disable=protected-access
@@ -121,6 +128,12 @@ def test_collect_statsbeat_metrics(self, thread_mock, stats_mock):
121128
statsbeat_metrics._AzureStatsbeatMetricsProducer
122129
)
123130
)
131+
self.assertTrue(
132+
isinstance(
133+
statsbeat_metrics._STATSBEAT_EXPORTER,
134+
MetricsExporter,
135+
)
136+
)
124137
self.assertEqual(
125138
statsbeat_metrics._STATSBEAT_METRICS._statsbeat._instrumentation_key, "ikey") # noqa: E501
126139
thread_mock.assert_called_once()
@@ -137,6 +150,74 @@ def test_collect_statsbeat_metrics_exists(self, thread_mock, stats_mock):
137150
thread_mock.assert_not_called()
138151
stats_mock.assert_not_called()
139152

153+
@mock.patch.object(_StatsbeatMetrics, 'get_initial_metrics')
154+
@mock.patch('opencensus.metrics.transport.get_exporter_thread')
155+
def test_collect_statsbeat_metrics_non_eu(self, thread_mock, stats_mock):
156+
# pylint: disable=protected-access
157+
cs = "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/" # noqa: E501
158+
non_eu = Options(
159+
connection_string=cs
160+
)
161+
with mock.patch.dict(
162+
os.environ, {
163+
"APPLICATION_INSIGHTS_STATS_CONNECTION_STRING": "",
164+
}):
165+
statsbeat_metrics.collect_statsbeat_metrics(non_eu)
166+
self.assertTrue(
167+
isinstance(
168+
statsbeat_metrics._STATSBEAT_METRICS,
169+
statsbeat_metrics._AzureStatsbeatMetricsProducer
170+
)
171+
)
172+
self.assertTrue(
173+
isinstance(
174+
statsbeat_metrics._STATSBEAT_EXPORTER,
175+
MetricsExporter,
176+
)
177+
)
178+
self.assertEqual(
179+
statsbeat_metrics._STATSBEAT_EXPORTER.options.instrumentation_key, # noqa: E501
180+
_DEFAULT_NON_EU_STATS_CONNECTION_STRING.split(";")[0].split("=")[1] # noqa: E501
181+
)
182+
self.assertEqual(
183+
statsbeat_metrics._STATSBEAT_EXPORTER.options.endpoint,
184+
_DEFAULT_NON_EU_STATS_CONNECTION_STRING.split(";")[1].split("=")[1] # noqa: E501
185+
)
186+
187+
@mock.patch.object(_StatsbeatMetrics, 'get_initial_metrics')
188+
@mock.patch('opencensus.metrics.transport.get_exporter_thread')
189+
def test_collect_statsbeat_metrics_eu(self, thread_mock, stats_mock):
190+
# pylint: disable=protected-access
191+
cs = "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;IngestionEndpoint=https://northeurope-0.in.applicationinsights.azure.com/" # noqa: E501
192+
eu = Options(
193+
connection_string=cs
194+
)
195+
with mock.patch.dict(
196+
os.environ, {
197+
"APPLICATION_INSIGHTS_STATS_CONNECTION_STRING": "",
198+
}):
199+
statsbeat_metrics.collect_statsbeat_metrics(eu)
200+
self.assertTrue(
201+
isinstance(
202+
statsbeat_metrics._STATSBEAT_METRICS,
203+
statsbeat_metrics._AzureStatsbeatMetricsProducer
204+
)
205+
)
206+
self.assertTrue(
207+
isinstance(
208+
statsbeat_metrics._STATSBEAT_EXPORTER,
209+
MetricsExporter,
210+
)
211+
)
212+
self.assertEqual(
213+
statsbeat_metrics._STATSBEAT_EXPORTER.options.instrumentation_key, # noqa: E501
214+
_DEFAULT_EU_STATS_CONNECTION_STRING.split(";")[0].split("=")[1] # noqa: E501
215+
)
216+
self.assertEqual(
217+
statsbeat_metrics._STATSBEAT_EXPORTER.options.endpoint,
218+
_DEFAULT_EU_STATS_CONNECTION_STRING.split(";")[1].split("=")[1] # noqa: E501
219+
)
220+
140221
@mock.patch(
141222
'opencensus.ext.azure.metrics_exporter.statsbeat_metrics.statsbeat._get_feature_properties') # noqa: E501
142223
@mock.patch(
@@ -149,6 +230,7 @@ def test_statsbeat_metric_init(self, attach_mock, network_mock, feature_mock):
149230
self.assertEqual(len(metric._vm_data), 0)
150231
self.assertTrue(metric._vm_retry)
151232
self.assertEqual(metric._instrumentation_key, "ikey")
233+
self.assertEqual(metric._feature, 1)
152234
self.assertTrue(
153235
isinstance(
154236
metric._attach_metric,
@@ -327,7 +409,7 @@ def test_get_feature_metric(self):
327409
self.assertEqual(
328410
properties[8].value, ext_version) # noqa: E501
329411

330-
def test_get_feature_metric_wtih_aad(self):
412+
def test_get_feature_metric_with_aad(self):
331413
aad_options = Options(
332414
instrumentation_key="ikey",
333415
enable_local_storage=True,
@@ -584,7 +666,7 @@ def test_get_azure_compute_metadata_not_vm_timeout(self):
584666
self.assertEqual(len(stats._vm_data), 0)
585667
self.assertFalse(stats._vm_retry)
586668

587-
def test_get_azure_compute_metadata__vm_retry(self):
669+
def test_get_azure_compute_metadata_vm_retry(self):
588670
with mock.patch(
589671
'requests.get',
590672
throw(requests.exceptions.RequestException)
@@ -612,3 +694,39 @@ def test_shorten_host(self):
612694
self.assertEqual(_shorten_host(url), "fakehost")
613695
url = "http://fakehost-5/"
614696
self.assertEqual(_shorten_host(url), "fakehost-5")
697+
698+
def test_get_stats_connection_string_env(self):
699+
cs = "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/" # noqa: E501
700+
with mock.patch.dict(
701+
os.environ, {
702+
"APPLICATION_INSIGHTS_STATS_CONNECTION_STRING": cs
703+
}
704+
):
705+
stats_cs = _get_stats_connection_string(_OPTIONS.endpoint)
706+
self.assertEqual(stats_cs, cs)
707+
708+
def test_get_stats_connection_string_non_eu(self):
709+
with mock.patch.dict(
710+
os.environ, {
711+
"APPLICATION_INSIGHTS_STATS_CONNECTION_STRING": ""
712+
}
713+
):
714+
cs = "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/" # noqa: E501
715+
non_eu = Options(
716+
connection_string=cs,
717+
)
718+
stats_cs = _get_stats_connection_string(non_eu.endpoint)
719+
self.assertEqual(stats_cs, _DEFAULT_NON_EU_STATS_CONNECTION_STRING)
720+
721+
def test_get_stats_connection_string_eu(self):
722+
with mock.patch.dict(
723+
os.environ, {
724+
"APPLICATION_INSIGHTS_STATS_CONNECTION_STRING": ""
725+
}
726+
):
727+
cs = "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;IngestionEndpoint=https://northeurope-0.in.applicationinsights.azure.com/" # noqa: E501
728+
eu = Options(
729+
connection_string=cs,
730+
)
731+
stats_cs = _get_stats_connection_string(eu.endpoint)
732+
self.assertEqual(stats_cs, _DEFAULT_EU_STATS_CONNECTION_STRING)

tox.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ deps =
1818
unit,lint: pytest-cov
1919
unit,lint: retrying
2020
unit,lint: unittest2
21+
py27-unit: markupsafe==1.1.1
22+
py35-unit: markupsafe==1.1.1
23+
py3{6,7,8,9}-unit: markupsafe==2.0.1 # https://github.com/pallets/markupsafe/issues/282
2124
bandit: bandit
2225
unit,lint,setup,docs,bandit: -e context/opencensus-context
2326
unit,lint,docs,bandit: -e contrib/opencensus-correlation

0 commit comments

Comments
 (0)