1
1
// Copyright (c) Microsoft Corporation. All rights reserved.
2
2
// Licensed under the MIT License.
3
3
4
- #nullable disable // TODO: remove and fix errors
5
-
6
4
using System ;
7
5
using System . Collections . Generic ;
8
6
using System . Diagnostics . Metrics ;
17
15
18
16
namespace Azure . Monitor . OpenTelemetry . Exporter . Internals
19
17
{
20
- internal static class Statsbeat
18
+ internal sealed class Statsbeat : IDisposable
21
19
{
22
- internal const string StatsBeat_ConnectionString_NonEU = "<Non-EU-ConnectionString> " ;
20
+ internal const string Statsbeat_ConnectionString_NonEU = "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://NonEU.in.applicationinsights.azure.com/ " ;
23
21
24
- internal const string StatsBeat_ConnectionString_EU = "EU-ConnectionString " ;
22
+ internal const string Statsbeat_ConnectionString_EU = "InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://EU.in.applicationinsights.azure.com/ " ;
25
23
26
24
private const string AMS_Url = "http://169.254.169.254/metadata/instance/compute?api-version=2017-08-01&format=json" ;
27
25
28
- internal const int AttachStatsBeatInterval = 86400000 ;
29
-
30
- private static readonly Meter s_myMeter = new ( "AttachStatsBeatMeter" , "1.0" ) ;
26
+ internal const int AttachStatsbeatInterval = 86400000 ;
31
27
32
- private static bool s_isEnabled = true ;
28
+ private static readonly Meter s_myMeter = new ( "AttachStatsbeatMeter" , "1.0" ) ;
33
29
34
- internal static string s_statsBeat_ConnectionString ;
30
+ internal string ? _statsbeat_ConnectionString ;
35
31
36
- private static string s_resourceProviderId ;
32
+ private string ? _resourceProviderId ;
37
33
38
- private static string s_resourceProvider ;
34
+ private string ? _resourceProvider ;
39
35
40
- private static string s_runtimeVersion => SdkVersionUtils . GetVersion ( typeof ( object ) ) ;
36
+ private static string ? s_runtimeVersion => SdkVersionUtils . GetVersion ( typeof ( object ) ) ;
41
37
42
- private static string s_sdkVersion => SdkVersionUtils . GetVersion ( typeof ( AzureMonitorTraceExporter ) ) ;
38
+ private static string ? s_sdkVersion => SdkVersionUtils . GetVersion ( typeof ( AzureMonitorTraceExporter ) ) ;
43
39
44
40
private static string s_operatingSystem = GetOS ( ) ;
45
41
46
- private static string s_customer_Ikey ;
42
+ private readonly string ? _customer_Ikey ;
47
43
48
- internal static MeterProvider s_attachStatsBeatMeterProvider ;
44
+ internal MeterProvider ? _attachStatsbeatMeterProvider ;
49
45
50
- internal static Regex s_endpoint_pattern = new ( "^https?://(?:www\\ .)?([^/.-]+)" ) ;
46
+ internal static Regex s_endpoint_pattern => new ( "^https?://(?:www\\ .)?([^/.-]+)" ) ;
51
47
52
- internal static readonly HashSet < string > EU_Endpoints = new ( )
48
+ internal static readonly HashSet < string > s_EU_Endpoints = new ( )
53
49
{
54
50
"francecentral" ,
55
51
"francesouth" ,
@@ -64,7 +60,7 @@ internal static class Statsbeat
64
60
"westeurope" ,
65
61
} ;
66
62
67
- internal static readonly HashSet < string > Non_EU_Endpoints = new ( )
63
+ internal static readonly HashSet < string > s_non_EU_Endpoints = new ( )
68
64
{
69
65
"australiacentral" ,
70
66
"australiacentral2" ,
@@ -101,6 +97,35 @@ internal static class Statsbeat
101
97
"westus3" ,
102
98
} ;
103
99
100
+ internal Statsbeat ( ConnectionVars connectionStringVars )
101
+ {
102
+ _statsbeat_ConnectionString = GetStatsbeatConnectionString ( connectionStringVars ? . IngestionEndpoint ) ;
103
+
104
+ // Initialize only if we are able to determine the correct region to send the data to.
105
+ if ( _statsbeat_ConnectionString == null )
106
+ {
107
+ throw new InvalidOperationException ( "Cannot initialize statsbeat" ) ;
108
+ }
109
+
110
+ _customer_Ikey = connectionStringVars ? . InstrumentationKey ;
111
+
112
+ s_myMeter . CreateObservableGauge ( "AttachStatsbeat" , ( ) => GetAttachStatsbeat ( ) ) ;
113
+
114
+ // Configure for attach statsbeat which has collection
115
+ // schedule of 24 hrs == 86400000 milliseconds.
116
+ // TODO: Follow up in spec to confirm the behavior
117
+ // in case if the app exits before 24hrs duration.
118
+ var exporterOptions = new AzureMonitorExporterOptions ( ) ;
119
+ exporterOptions . DisableOfflineStorage = true ;
120
+ exporterOptions . ConnectionString = _statsbeat_ConnectionString ;
121
+
122
+ _attachStatsbeatMeterProvider = Sdk . CreateMeterProviderBuilder ( )
123
+ . AddMeter ( "AttachStatsbeatMeter" )
124
+ . AddReader ( new PeriodicExportingMetricReader ( new AzureMonitorMetricExporter ( exporterOptions ) , AttachStatsbeatInterval )
125
+ { TemporalityPreference = MetricReaderTemporalityPreference . Delta } )
126
+ . Build ( ) ;
127
+ }
128
+
104
129
private static string GetOS ( )
105
130
{
106
131
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
@@ -119,90 +144,54 @@ private static string GetOS()
119
144
return "unknown" ;
120
145
}
121
146
122
- internal static void InitializeAttachStatsbeat ( string connectionString )
147
+ internal static string ? GetStatsbeatConnectionString ( string ? ingestionEndpoint )
123
148
{
124
- // check whether it is disabled or already initialized.
125
- if ( s_isEnabled && s_attachStatsBeatMeterProvider == null )
149
+ var patternMatch = s_endpoint_pattern . Match ( ingestionEndpoint ) ;
150
+ string ? statsbeatConnectionString = null ;
151
+ if ( patternMatch . Success )
126
152
{
127
- if ( s_statsBeat_ConnectionString == null )
153
+ var endpoint = patternMatch . Groups [ 1 ] . Value ;
154
+ if ( s_EU_Endpoints . Contains ( endpoint ) )
128
155
{
129
- var parsedConectionString = ConnectionStringParser . GetValues ( connectionString ) ;
130
- SetCustomerIkey ( parsedConectionString . InstrumentationKey ) ;
131
- SetStatsbeatConnectionString ( parsedConectionString . IngestionEndpoint ) ;
156
+ statsbeatConnectionString = Statsbeat_ConnectionString_EU ;
132
157
}
133
-
134
- if ( ! s_isEnabled )
158
+ else if ( s_non_EU_Endpoints . Contains ( endpoint ) )
135
159
{
136
- // TODO: log
137
- return ;
160
+ statsbeatConnectionString = Statsbeat_ConnectionString_NonEU ;
138
161
}
139
-
140
- s_myMeter . CreateObservableGauge ( "AttachStatsBeat" , ( ) => GetAttachStatsBeat ( ) ) ;
141
-
142
- // Configure for attach statsbeat which has collection
143
- // schedule of 24 hrs == 86400000 milliseconds.
144
- // TODO: Follow up in spec to confirm the behavior
145
- // in case if the app exits before 24hrs duration.
146
- var exporterOptions = new AzureMonitorExporterOptions ( ) ;
147
- exporterOptions . DisableOfflineStorage = true ;
148
- exporterOptions . ConnectionString = s_statsBeat_ConnectionString ;
149
-
150
- s_attachStatsBeatMeterProvider = Sdk . CreateMeterProviderBuilder ( )
151
- . AddMeter ( "AttachStatsBeatMeter" )
152
- . AddReader ( new PeriodicExportingMetricReader ( new AzureMonitorMetricExporter ( exporterOptions ) , AttachStatsBeatInterval )
153
- { TemporalityPreference = MetricReaderTemporalityPreference . Delta } )
154
- . Build ( ) ;
155
162
}
156
- }
157
163
158
- internal static void SetCustomerIkey ( string instrumentationKey )
159
- {
160
- s_customer_Ikey = instrumentationKey ;
164
+ return statsbeatConnectionString ;
161
165
}
162
166
163
- internal static void SetStatsbeatConnectionString ( string ingestionEndpoint )
167
+ private Measurement < int > GetAttachStatsbeat ( )
164
168
{
165
- var patternMatch = s_endpoint_pattern . Match ( ingestionEndpoint ) ;
166
- if ( patternMatch . Success )
169
+ try
167
170
{
168
- var endpoint = patternMatch . Groups [ 1 ] . Value ;
169
- if ( EU_Endpoints . Contains ( endpoint ) )
170
- {
171
- s_statsBeat_ConnectionString = StatsBeat_ConnectionString_EU ;
172
- }
173
- else if ( Non_EU_Endpoints . Contains ( endpoint ) )
174
- {
175
- s_statsBeat_ConnectionString = StatsBeat_ConnectionString_NonEU ;
176
- }
177
- else
171
+ if ( _resourceProvider == null )
178
172
{
179
- // disable statsbeat
180
- s_isEnabled = false ;
173
+ SetResourceProviderDetails ( ) ;
181
174
}
182
- }
183
- }
184
175
185
- private static Measurement < int > GetAttachStatsBeat ( )
186
- {
187
- if ( s_resourceProvider == null )
176
+ return
177
+ new Measurement < int > ( 1 ,
178
+ new ( "rp" , _resourceProvider ) ,
179
+ new ( "rpId" , _resourceProviderId ) ,
180
+ new ( "attach" , "sdk" ) ,
181
+ new ( "cikey" , _customer_Ikey ) ,
182
+ new ( "runtimeVersion" , s_runtimeVersion ) ,
183
+ new ( "language" , "dotnet" ) ,
184
+ new ( "version" , s_sdkVersion ) ,
185
+ new ( "os" , s_operatingSystem ) ) ;
186
+ }
187
+ catch ( Exception ex )
188
188
{
189
- SetResourceProviderDetails ( ) ;
189
+ AzureMonitorExporterEventSource . Log . WriteWarning ( "ErrorGettingStatsbeatData" , ex ) ;
190
+ return new Measurement < int > ( ) ;
190
191
}
191
-
192
- // TODO: Add os to the list
193
- return
194
- new Measurement < int > ( 1 ,
195
- new ( "rp" , s_resourceProvider ) ,
196
- new ( "rpId" , s_resourceProviderId ) ,
197
- new ( "attach" , "sdk" ) ,
198
- new ( "cikey" , s_customer_Ikey ) ,
199
- new ( "runtimeVersion" , s_runtimeVersion ) ,
200
- new ( "language" , "dotnet" ) ,
201
- new ( "version" , s_sdkVersion ) ,
202
- new ( "os" , s_operatingSystem ) ) ;
203
192
}
204
193
205
- private static VmMetadataResponse GetVmMetadataResponse ( )
194
+ private static VmMetadataResponse ? GetVmMetadataResponse ( )
206
195
{
207
196
try
208
197
{
@@ -222,17 +211,17 @@ private static VmMetadataResponse GetVmMetadataResponse()
222
211
}
223
212
}
224
213
225
- private static void SetResourceProviderDetails ( )
214
+ private void SetResourceProviderDetails ( )
226
215
{
227
216
var appSvcWebsiteName = Environment . GetEnvironmentVariable ( "WEBSITE_SITE_NAME" ) ;
228
217
if ( appSvcWebsiteName != null )
229
218
{
230
- s_resourceProvider = "appsvc" ;
231
- s_resourceProviderId = appSvcWebsiteName ;
219
+ _resourceProvider = "appsvc" ;
220
+ _resourceProviderId = appSvcWebsiteName ;
232
221
var appSvcWebsiteHostName = Environment . GetEnvironmentVariable ( "WEBSITE_HOME_STAMPNAME" ) ;
233
222
if ( ! string . IsNullOrEmpty ( appSvcWebsiteHostName ) )
234
223
{
235
- s_resourceProviderId += "/" + appSvcWebsiteHostName ;
224
+ _resourceProviderId += "/" + appSvcWebsiteHostName ;
236
225
}
237
226
238
227
return ;
@@ -241,8 +230,8 @@ private static void SetResourceProviderDetails()
241
230
var functionsWorkerRuntime = Environment . GetEnvironmentVariable ( "FUNCTIONS_WORKER_RUNTIME" ) ;
242
231
if ( functionsWorkerRuntime != null )
243
232
{
244
- s_resourceProvider = "functions" ;
245
- s_resourceProviderId = Environment . GetEnvironmentVariable ( "WEBSITE_HOSTNAME" ) ;
233
+ _resourceProvider = "functions" ;
234
+ _resourceProviderId = Environment . GetEnvironmentVariable ( "WEBSITE_HOSTNAME" ) ;
246
235
247
236
return ;
248
237
}
@@ -251,17 +240,22 @@ private static void SetResourceProviderDetails()
251
240
252
241
if ( vmMetadata != null )
253
242
{
254
- s_resourceProvider = "vm" ;
255
- s_resourceProviderId = s_resourceProviderId = vmMetadata . vmId + "/" + vmMetadata . subscriptionId ;
243
+ _resourceProvider = "vm" ;
244
+ _resourceProviderId = _resourceProviderId = vmMetadata . vmId + "/" + vmMetadata . subscriptionId ;
256
245
257
246
// osType takes precedence.
258
247
s_operatingSystem = vmMetadata . osType . ToLower ( CultureInfo . InvariantCulture ) ;
259
248
260
249
return ;
261
250
}
262
251
263
- s_resourceProvider = "unknown" ;
264
- s_resourceProviderId = "unknown" ;
252
+ _resourceProvider = "unknown" ;
253
+ _resourceProviderId = "unknown" ;
254
+ }
255
+
256
+ public void Dispose ( )
257
+ {
258
+ _attachStatsbeatMeterProvider ? . Dispose ( ) ;
265
259
}
266
260
}
267
261
}
0 commit comments