@azure/monitor-opentelemetry-exporter 1.0.0-beta.16 → 1.0.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -11
- package/dist/index.js +444 -377
- package/dist-esm/src/Declarations/Contracts/Constants.js.map +1 -1
- package/dist-esm/src/export/base.js +10 -4
- package/dist-esm/src/export/base.js.map +1 -1
- package/dist-esm/src/export/log.js +10 -4
- package/dist-esm/src/export/log.js.map +1 -1
- package/dist-esm/src/export/metric.js +11 -5
- package/dist-esm/src/export/metric.js.map +1 -1
- package/dist-esm/src/export/statsbeat/longIntervalStatsbeatMetrics.js +53 -54
- package/dist-esm/src/export/statsbeat/longIntervalStatsbeatMetrics.js.map +1 -1
- package/dist-esm/src/export/statsbeat/networkStatsbeatMetrics.js +101 -104
- package/dist-esm/src/export/statsbeat/networkStatsbeatMetrics.js.map +1 -1
- package/dist-esm/src/export/statsbeat/statsbeatExporter.js +7 -2
- package/dist-esm/src/export/statsbeat/statsbeatExporter.js.map +1 -1
- package/dist-esm/src/export/statsbeat/statsbeatMetrics.js +33 -21
- package/dist-esm/src/export/statsbeat/statsbeatMetrics.js.map +1 -1
- package/dist-esm/src/export/statsbeat/types.js +11 -8
- package/dist-esm/src/export/statsbeat/types.js.map +1 -1
- package/dist-esm/src/export/trace.js +14 -8
- package/dist-esm/src/export/trace.js.map +1 -1
- package/dist-esm/src/generated/applicationInsightsClient.js +1 -1
- package/dist-esm/src/generated/applicationInsightsClient.js.map +1 -1
- package/dist-esm/src/platform/nodejs/baseSender.js +52 -52
- package/dist-esm/src/platform/nodejs/baseSender.js.map +1 -1
- package/dist-esm/src/platform/nodejs/context/context.js +4 -5
- package/dist-esm/src/platform/nodejs/context/context.js.map +1 -1
- package/dist-esm/src/platform/nodejs/httpSender.js +22 -21
- package/dist-esm/src/platform/nodejs/httpSender.js.map +1 -1
- package/dist-esm/src/platform/nodejs/persist/fileAccessControl.js +6 -7
- package/dist-esm/src/platform/nodejs/persist/fileAccessControl.js.map +1 -1
- package/dist-esm/src/platform/nodejs/persist/fileSystemPersist.js +1 -2
- package/dist-esm/src/platform/nodejs/persist/fileSystemPersist.js.map +1 -1
- package/dist-esm/src/sampling.js +17 -17
- package/dist-esm/src/sampling.js.map +1 -1
- package/dist-esm/src/utils/common.js +5 -5
- package/dist-esm/src/utils/common.js.map +1 -1
- package/dist-esm/src/utils/connectionStringParser.js +12 -3
- package/dist-esm/src/utils/connectionStringParser.js.map +1 -1
- package/dist-esm/src/utils/constants/applicationinsights.js +1 -1
- package/dist-esm/src/utils/constants/applicationinsights.js.map +1 -1
- package/dist-esm/src/utils/logUtils.js +8 -8
- package/dist-esm/src/utils/logUtils.js.map +1 -1
- package/dist-esm/src/utils/metricUtils.js +6 -6
- package/dist-esm/src/utils/metricUtils.js.map +1 -1
- package/dist-esm/src/utils/spanUtils.js +22 -21
- package/dist-esm/src/utils/spanUtils.js.map +1 -1
- package/package.json +24 -23
- package/types/monitor-opentelemetry-exporter.d.ts +16 -12
package/dist/index.js
CHANGED
|
@@ -16,10 +16,7 @@ var child_process = require('child_process');
|
|
|
16
16
|
var util = require('util');
|
|
17
17
|
var coreClient = require('@azure/core-client');
|
|
18
18
|
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
function _interopNamespace(e) {
|
|
22
|
-
if (e && e.__esModule) return e;
|
|
19
|
+
function _interopNamespaceDefault(e) {
|
|
23
20
|
var n = Object.create(null);
|
|
24
21
|
if (e) {
|
|
25
22
|
Object.keys(e).forEach(function (k) {
|
|
@@ -32,18 +29,16 @@ function _interopNamespace(e) {
|
|
|
32
29
|
}
|
|
33
30
|
});
|
|
34
31
|
}
|
|
35
|
-
n
|
|
32
|
+
n.default = e;
|
|
36
33
|
return Object.freeze(n);
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
var
|
|
44
|
-
var
|
|
45
|
-
var child_process__namespace = /*#__PURE__*/_interopNamespace(child_process);
|
|
46
|
-
var coreClient__namespace = /*#__PURE__*/_interopNamespace(coreClient);
|
|
36
|
+
var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os$1);
|
|
37
|
+
var coreRestPipeline__namespace = /*#__PURE__*/_interopNamespaceDefault(coreRestPipeline);
|
|
38
|
+
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
39
|
+
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
40
|
+
var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_process);
|
|
41
|
+
var coreClient__namespace = /*#__PURE__*/_interopNamespaceDefault(coreClient);
|
|
47
42
|
|
|
48
43
|
// Copyright (c) Microsoft Corporation.
|
|
49
44
|
// Licensed under the MIT license.
|
|
@@ -66,7 +61,7 @@ const TIME_SINCE_ENQUEUED = "timeSinceEnqueued";
|
|
|
66
61
|
* AzureMonitorTraceExporter version.
|
|
67
62
|
* @internal
|
|
68
63
|
*/
|
|
69
|
-
const packageVersion = "1.0.0-beta.
|
|
64
|
+
const packageVersion = "1.0.0-beta.18";
|
|
70
65
|
var DependencyTypes;
|
|
71
66
|
(function (DependencyTypes) {
|
|
72
67
|
DependencyTypes["InProc"] = "InProc";
|
|
@@ -97,26 +92,26 @@ const ApplicationInsightsEventBaseType = "EventData";
|
|
|
97
92
|
class ApplicationInsightsSampler {
|
|
98
93
|
/**
|
|
99
94
|
* Initializes a new instance of the ApplicationInsightsSampler class.
|
|
100
|
-
* @param samplingRatio Value in the range [0,1], 1 meaning all data will sampled and 0 all Tracing data will be sampled out.
|
|
95
|
+
* @param samplingRatio - Value in the range [0,1], 1 meaning all data will sampled and 0 all Tracing data will be sampled out.
|
|
101
96
|
*/
|
|
102
97
|
constructor(samplingRatio = 1) {
|
|
103
|
-
this.
|
|
104
|
-
if (this.
|
|
98
|
+
this.samplingRatio = samplingRatio;
|
|
99
|
+
if (this.samplingRatio > 1) {
|
|
105
100
|
throw new Error("Wrong sampling rate, data will not be sampled out");
|
|
106
101
|
}
|
|
107
|
-
this._sampleRate = Math.round(this.
|
|
102
|
+
this._sampleRate = Math.round(this.samplingRatio * 100);
|
|
108
103
|
}
|
|
109
104
|
/**
|
|
110
105
|
* Checks whether span needs to be created and tracked.
|
|
111
106
|
*
|
|
112
|
-
* @param context Parent Context which may contain a span.
|
|
113
|
-
* @param traceId of the span to be created. It can be different from the
|
|
107
|
+
* @param context - Parent Context which may contain a span.
|
|
108
|
+
* @param traceId - traceif of the span to be created. It can be different from the
|
|
114
109
|
* traceId in the {@link SpanContext}. Typically in situations when the
|
|
115
110
|
* span to be created starts a new trace.
|
|
116
|
-
* @param spanName of the span to be created.
|
|
117
|
-
* @param spanKind of the span to be created.
|
|
118
|
-
* @param attributes Initial set of SpanAttributes for the Span being constructed.
|
|
119
|
-
* @param links Collection of links that will be associated with the Span to
|
|
111
|
+
* @param spanName - Name of the span to be created.
|
|
112
|
+
* @param spanKind - Kind of the span to be created.
|
|
113
|
+
* @param attributes - Initial set of SpanAttributes for the Span being constructed.
|
|
114
|
+
* @param links - Collection of links that will be associated with the Span to
|
|
120
115
|
* be created. Typically useful for batch operations.
|
|
121
116
|
* @returns a {@link SamplingResult}.
|
|
122
117
|
*/
|
|
@@ -130,10 +125,10 @@ class ApplicationInsightsSampler {
|
|
|
130
125
|
// @ts-ignore
|
|
131
126
|
links) {
|
|
132
127
|
let isSampledIn = false;
|
|
133
|
-
if (this._sampleRate
|
|
128
|
+
if (this._sampleRate === 100) {
|
|
134
129
|
isSampledIn = true;
|
|
135
130
|
}
|
|
136
|
-
else if (this._sampleRate
|
|
131
|
+
else if (this._sampleRate === 0) {
|
|
137
132
|
isSampledIn = false;
|
|
138
133
|
}
|
|
139
134
|
else {
|
|
@@ -150,19 +145,19 @@ class ApplicationInsightsSampler {
|
|
|
150
145
|
* Return Sampler description
|
|
151
146
|
*/
|
|
152
147
|
toString() {
|
|
153
|
-
return `ApplicationInsightsSampler{${this.
|
|
148
|
+
return `ApplicationInsightsSampler{${this.samplingRatio}}`;
|
|
154
149
|
}
|
|
155
150
|
_getSamplingHashCode(input) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
151
|
+
const csharpMin = -2147483648;
|
|
152
|
+
const csharpMax = 2147483647;
|
|
153
|
+
let hash = 5381;
|
|
159
154
|
if (!input) {
|
|
160
155
|
return 0;
|
|
161
156
|
}
|
|
162
157
|
while (input.length < 8) {
|
|
163
158
|
input = input + input;
|
|
164
159
|
}
|
|
165
|
-
for (
|
|
160
|
+
for (let i = 0; i < input.length; i++) {
|
|
166
161
|
// JS doesn't respond to integer overflow by wrapping around. Simulate it with bitwise operators ( | 0)
|
|
167
162
|
hash = ((((hash << 5) + hash) | 0) + input.charCodeAt(i)) | 0;
|
|
168
163
|
}
|
|
@@ -263,6 +258,7 @@ var PerformanceCounter;
|
|
|
263
258
|
});
|
|
264
259
|
|
|
265
260
|
// Copyright (c) Microsoft Corporation.
|
|
261
|
+
// Licensed under the MIT license.
|
|
266
262
|
/**
|
|
267
263
|
* ConnectionString parser.
|
|
268
264
|
* @internal
|
|
@@ -318,16 +314,27 @@ class ConnectionStringParser {
|
|
|
318
314
|
newUrl = newUrl.replace("http://", "https://");
|
|
319
315
|
}
|
|
320
316
|
// Remove final slash if present
|
|
321
|
-
if (newUrl[newUrl.length - 1]
|
|
317
|
+
if (newUrl[newUrl.length - 1] === "/") {
|
|
322
318
|
newUrl = newUrl.slice(0, -1);
|
|
323
319
|
}
|
|
324
320
|
return newUrl;
|
|
325
321
|
}
|
|
322
|
+
static validateInstrumentationKey(iKey) {
|
|
323
|
+
if (iKey.startsWith("InstrumentationKey=")) {
|
|
324
|
+
const startIndex = iKey.indexOf("InstrumentationKey=") + "InstrumentationKey=".length;
|
|
325
|
+
const endIndex = iKey.indexOf(";", startIndex);
|
|
326
|
+
iKey = iKey.substring(startIndex, endIndex);
|
|
327
|
+
}
|
|
328
|
+
const UUID_Regex = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
|
|
329
|
+
const regexp = new RegExp(UUID_Regex);
|
|
330
|
+
return regexp.test(iKey);
|
|
331
|
+
}
|
|
326
332
|
}
|
|
327
333
|
ConnectionStringParser.FIELDS_SEPARATOR = ";";
|
|
328
334
|
ConnectionStringParser.FIELD_KEY_VALUE_SEPARATOR = "=";
|
|
329
335
|
|
|
330
336
|
// Copyright (c) Microsoft Corporation.
|
|
337
|
+
// Licensed under the MIT license.
|
|
331
338
|
/**
|
|
332
339
|
* Azure Monitor OpenTelemetry Trace Exporter.
|
|
333
340
|
*/
|
|
@@ -350,16 +357,17 @@ class AzureMonitorBaseExporter {
|
|
|
350
357
|
*Flag to determine if exporter will generate Statsbeat data
|
|
351
358
|
*/
|
|
352
359
|
this.trackStatsbeat = false;
|
|
353
|
-
this.
|
|
360
|
+
this.options = options;
|
|
354
361
|
this.instrumentationKey = "";
|
|
355
362
|
this.endpointUrl = DEFAULT_BREEZE_ENDPOINT;
|
|
356
|
-
const connectionString = this.
|
|
357
|
-
this.
|
|
363
|
+
const connectionString = this.options.connectionString || process.env[ENV_CONNECTION_STRING];
|
|
364
|
+
this.isStatsbeatExporter = isStatsbeatExporter ? isStatsbeatExporter : false;
|
|
358
365
|
if (connectionString) {
|
|
359
366
|
const parsedConnectionString = ConnectionStringParser.parse(connectionString);
|
|
360
367
|
this.instrumentationKey =
|
|
361
368
|
parsedConnectionString.instrumentationkey || this.instrumentationKey;
|
|
362
369
|
this.endpointUrl = ((_a = parsedConnectionString.ingestionendpoint) === null || _a === void 0 ? void 0 : _a.trim()) || this.endpointUrl;
|
|
370
|
+
this.aadAudience = parsedConnectionString.aadaudience;
|
|
363
371
|
}
|
|
364
372
|
// Instrumentation key is required
|
|
365
373
|
if (!this.instrumentationKey) {
|
|
@@ -367,12 +375,18 @@ class AzureMonitorBaseExporter {
|
|
|
367
375
|
api.diag.error(message);
|
|
368
376
|
throw new Error(message);
|
|
369
377
|
}
|
|
370
|
-
|
|
378
|
+
if (!ConnectionStringParser.validateInstrumentationKey(this.instrumentationKey)) {
|
|
379
|
+
const message = "Invalid instrumentation key was provided to the Azure Monitor Exporter";
|
|
380
|
+
api.diag.error(message);
|
|
381
|
+
throw new Error(message);
|
|
382
|
+
}
|
|
383
|
+
this.trackStatsbeat = !this.isStatsbeatExporter && !process.env[ENV_DISABLE_STATSBEAT];
|
|
371
384
|
api.diag.debug("AzureMonitorExporter was successfully setup");
|
|
372
385
|
}
|
|
373
386
|
}
|
|
374
387
|
|
|
375
388
|
// Copyright (c) Microsoft Corporation.
|
|
389
|
+
// Licensed under the MIT license.
|
|
376
390
|
class FileAccessControl {
|
|
377
391
|
// Check if file access control could be enabled
|
|
378
392
|
static checkFileProtection() {
|
|
@@ -410,7 +424,7 @@ class FileAccessControl {
|
|
|
410
424
|
FileAccessControl.ACLED_DIRECTORIES[directory] = false;
|
|
411
425
|
try {
|
|
412
426
|
// Restrict this directory to only current user and administrator access
|
|
413
|
-
|
|
427
|
+
const identity = await this._getACLIdentity();
|
|
414
428
|
await this._runICACLS(this._getACLArguments(directory, identity));
|
|
415
429
|
FileAccessControl.ACLED_DIRECTORIES[directory] = true;
|
|
416
430
|
}
|
|
@@ -442,7 +456,7 @@ class FileAccessControl {
|
|
|
442
456
|
}
|
|
443
457
|
static _runICACLS(args) {
|
|
444
458
|
return new Promise((resolve, reject) => {
|
|
445
|
-
|
|
459
|
+
const aclProc = child_process__namespace.spawn(FileAccessControl.ICACLS_PATH, args, {
|
|
446
460
|
windowsHide: true,
|
|
447
461
|
});
|
|
448
462
|
aclProc.on("error", (e) => reject(e));
|
|
@@ -459,7 +473,7 @@ class FileAccessControl {
|
|
|
459
473
|
static _runICACLSSync(args) {
|
|
460
474
|
// Some very old versions of Node (< 0.11) don't have this
|
|
461
475
|
if (child_process__namespace.spawnSync) {
|
|
462
|
-
|
|
476
|
+
const aclProc = child_process__namespace.spawnSync(FileAccessControl.ICACLS_PATH, args, {
|
|
463
477
|
windowsHide: true,
|
|
464
478
|
});
|
|
465
479
|
if (aclProc.error) {
|
|
@@ -478,7 +492,7 @@ class FileAccessControl {
|
|
|
478
492
|
if (FileAccessControl.ACL_IDENTITY) {
|
|
479
493
|
resolve(FileAccessControl.ACL_IDENTITY);
|
|
480
494
|
}
|
|
481
|
-
|
|
495
|
+
const psProc = child_process__namespace.spawn(FileAccessControl.POWERSHELL_PATH, ["-Command", "[System.Security.Principal.WindowsIdentity]::GetCurrent().Name"], {
|
|
482
496
|
windowsHide: true,
|
|
483
497
|
stdio: ["ignore", "pipe", "pipe"], // Needed to prevent hanging on Win 7
|
|
484
498
|
});
|
|
@@ -502,7 +516,7 @@ class FileAccessControl {
|
|
|
502
516
|
}
|
|
503
517
|
// Some very old versions of Node (< 0.11) don't have this
|
|
504
518
|
if (child_process__namespace.spawnSync) {
|
|
505
|
-
|
|
519
|
+
const psProc = child_process__namespace.spawnSync(FileAccessControl.POWERSHELL_PATH, ["-Command", "[System.Security.Principal.WindowsIdentity]::GetCurrent().Name"], {
|
|
506
520
|
windowsHide: true,
|
|
507
521
|
stdio: ["ignore", "pipe", "pipe"], // Needed to prevent hanging on Win 7
|
|
508
522
|
});
|
|
@@ -539,6 +553,7 @@ FileAccessControl.OS_PROVIDES_FILE_PROTECTION = false;
|
|
|
539
553
|
FileAccessControl.USE_ICACLS = os__namespace.type() === "Windows_NT";
|
|
540
554
|
|
|
541
555
|
// Copyright (c) Microsoft Corporation.
|
|
556
|
+
// Licensed under the MIT license.
|
|
542
557
|
const readdirAsync$1 = util.promisify(fs__namespace.readdir);
|
|
543
558
|
const statAsync$1 = util.promisify(fs__namespace.stat);
|
|
544
559
|
const lstatAsync = util.promisify(fs__namespace.lstat);
|
|
@@ -588,6 +603,7 @@ const confirmDirExists = async (directory) => {
|
|
|
588
603
|
};
|
|
589
604
|
|
|
590
605
|
// Copyright (c) Microsoft Corporation.
|
|
606
|
+
// Licensed under the MIT license.
|
|
591
607
|
const statAsync = util.promisify(fs__namespace.stat);
|
|
592
608
|
const readdirAsync = util.promisify(fs__namespace.readdir);
|
|
593
609
|
const readFileAsync = util.promisify(fs__namespace.readFile);
|
|
@@ -1752,23 +1768,23 @@ const RequestData = {
|
|
|
1752
1768
|
|
|
1753
1769
|
var Mappers = /*#__PURE__*/Object.freeze({
|
|
1754
1770
|
__proto__: null,
|
|
1755
|
-
TelemetryItem: TelemetryItem,
|
|
1756
|
-
MonitorBase: MonitorBase,
|
|
1757
|
-
MonitorDomain: MonitorDomain,
|
|
1758
|
-
TrackResponse: TrackResponse,
|
|
1759
|
-
TelemetryErrorDetails: TelemetryErrorDetails,
|
|
1760
|
-
MetricDataPoint: MetricDataPoint,
|
|
1761
|
-
TelemetryExceptionDetails: TelemetryExceptionDetails,
|
|
1762
|
-
StackFrame: StackFrame,
|
|
1763
1771
|
AvailabilityData: AvailabilityData,
|
|
1764
|
-
TelemetryEventData: TelemetryEventData,
|
|
1765
|
-
TelemetryExceptionData: TelemetryExceptionData,
|
|
1766
1772
|
MessageData: MessageData,
|
|
1773
|
+
MetricDataPoint: MetricDataPoint,
|
|
1767
1774
|
MetricsData: MetricsData,
|
|
1775
|
+
MonitorBase: MonitorBase,
|
|
1776
|
+
MonitorDomain: MonitorDomain,
|
|
1768
1777
|
PageViewData: PageViewData,
|
|
1769
1778
|
PageViewPerfData: PageViewPerfData,
|
|
1770
1779
|
RemoteDependencyData: RemoteDependencyData,
|
|
1771
|
-
RequestData: RequestData
|
|
1780
|
+
RequestData: RequestData,
|
|
1781
|
+
StackFrame: StackFrame,
|
|
1782
|
+
TelemetryErrorDetails: TelemetryErrorDetails,
|
|
1783
|
+
TelemetryEventData: TelemetryEventData,
|
|
1784
|
+
TelemetryExceptionData: TelemetryExceptionData,
|
|
1785
|
+
TelemetryExceptionDetails: TelemetryExceptionDetails,
|
|
1786
|
+
TelemetryItem: TelemetryItem,
|
|
1787
|
+
TrackResponse: TrackResponse
|
|
1772
1788
|
});
|
|
1773
1789
|
|
|
1774
1790
|
/*
|
|
@@ -1792,7 +1808,7 @@ class ApplicationInsightsClient extends coreClient__namespace.ServiceClient {
|
|
|
1792
1808
|
const defaults = {
|
|
1793
1809
|
requestContentType: "application/json; charset=utf-8"
|
|
1794
1810
|
};
|
|
1795
|
-
const packageDetails = `azsdk-js-monitor-opentelemetry-exporter/1.0.0-beta.
|
|
1811
|
+
const packageDetails = `azsdk-js-monitor-opentelemetry-exporter/1.0.0-beta.18`;
|
|
1796
1812
|
const userAgentPrefix = options.userAgentOptions && options.userAgentOptions.userAgentPrefix
|
|
1797
1813
|
? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}`
|
|
1798
1814
|
: `${packageDetails}`;
|
|
@@ -1868,6 +1884,8 @@ const trackOperationSpec = {
|
|
|
1868
1884
|
serializer
|
|
1869
1885
|
};
|
|
1870
1886
|
|
|
1887
|
+
// Copyright (c) Microsoft Corporation.
|
|
1888
|
+
// Licensed under the MIT license.
|
|
1871
1889
|
class NetworkStatsbeat {
|
|
1872
1890
|
constructor(endpoint, host) {
|
|
1873
1891
|
this.endpoint = endpoint;
|
|
@@ -1889,18 +1907,19 @@ const STATSBEAT_LANGUAGE = "node";
|
|
|
1889
1907
|
const MAX_STATSBEAT_FAILURES = 3;
|
|
1890
1908
|
const StatsbeatResourceProvider = {
|
|
1891
1909
|
appsvc: "appsvc",
|
|
1910
|
+
aks: "aks",
|
|
1892
1911
|
functions: "functions",
|
|
1893
1912
|
vm: "vm",
|
|
1894
1913
|
unknown: "unknown",
|
|
1895
1914
|
};
|
|
1896
1915
|
var StatsbeatCounter;
|
|
1897
1916
|
(function (StatsbeatCounter) {
|
|
1898
|
-
StatsbeatCounter["SUCCESS_COUNT"] = "
|
|
1899
|
-
StatsbeatCounter["FAILURE_COUNT"] = "
|
|
1900
|
-
StatsbeatCounter["RETRY_COUNT"] = "
|
|
1901
|
-
StatsbeatCounter["THROTTLE_COUNT"] = "
|
|
1902
|
-
StatsbeatCounter["EXCEPTION_COUNT"] = "
|
|
1903
|
-
StatsbeatCounter["AVERAGE_DURATION"] = "
|
|
1917
|
+
StatsbeatCounter["SUCCESS_COUNT"] = "Request_Success_Count";
|
|
1918
|
+
StatsbeatCounter["FAILURE_COUNT"] = "Request_Failure_Count";
|
|
1919
|
+
StatsbeatCounter["RETRY_COUNT"] = "Retry_Count";
|
|
1920
|
+
StatsbeatCounter["THROTTLE_COUNT"] = "Throttle_Count";
|
|
1921
|
+
StatsbeatCounter["EXCEPTION_COUNT"] = "Exception_Count";
|
|
1922
|
+
StatsbeatCounter["AVERAGE_DURATION"] = "Request_Duration";
|
|
1904
1923
|
StatsbeatCounter["ATTACH"] = "Attach";
|
|
1905
1924
|
StatsbeatCounter["FEATURE"] = "Feature";
|
|
1906
1925
|
})(StatsbeatCounter || (StatsbeatCounter = {}));
|
|
@@ -1925,40 +1944,53 @@ const EU_ENDPOINTS = [
|
|
|
1925
1944
|
];
|
|
1926
1945
|
var StatsbeatFeatureType;
|
|
1927
1946
|
(function (StatsbeatFeatureType) {
|
|
1928
|
-
StatsbeatFeatureType["FEATURE"] = "
|
|
1929
|
-
StatsbeatFeatureType["INSTRUMENTATION"] = "
|
|
1947
|
+
StatsbeatFeatureType[StatsbeatFeatureType["FEATURE"] = 0] = "FEATURE";
|
|
1948
|
+
StatsbeatFeatureType[StatsbeatFeatureType["INSTRUMENTATION"] = 1] = "INSTRUMENTATION";
|
|
1930
1949
|
})(StatsbeatFeatureType || (StatsbeatFeatureType = {}));
|
|
1931
1950
|
|
|
1932
1951
|
// Copyright (c) Microsoft Corporation.
|
|
1952
|
+
// Licensed under the MIT license.
|
|
1933
1953
|
const os = require("os");
|
|
1934
1954
|
class StatsbeatMetrics {
|
|
1935
1955
|
constructor() {
|
|
1936
|
-
this.
|
|
1937
|
-
this.
|
|
1938
|
-
this.
|
|
1939
|
-
this.
|
|
1956
|
+
this.resourceProvider = StatsbeatResourceProvider.unknown;
|
|
1957
|
+
this.vmInfo = {};
|
|
1958
|
+
this.os = os.type();
|
|
1959
|
+
this.resourceIdentifier = "";
|
|
1940
1960
|
}
|
|
1941
|
-
async
|
|
1961
|
+
async getResourceProvider() {
|
|
1942
1962
|
// Check resource provider
|
|
1943
|
-
this.
|
|
1944
|
-
if (process.env.
|
|
1963
|
+
this.resourceProvider = StatsbeatResourceProvider.unknown;
|
|
1964
|
+
if (process.env.AKS_ARM_NAMESPACE_ID) {
|
|
1965
|
+
// AKS
|
|
1966
|
+
this.resourceProvider = StatsbeatResourceProvider.aks;
|
|
1967
|
+
this.resourceIdentifier = process.env.AKS_ARM_NAMESPACE_ID;
|
|
1968
|
+
}
|
|
1969
|
+
else if (process.env.WEBSITE_SITE_NAME) {
|
|
1945
1970
|
// Web apps
|
|
1946
|
-
this.
|
|
1971
|
+
this.resourceProvider = StatsbeatResourceProvider.appsvc;
|
|
1972
|
+
this.resourceIdentifier = process.env.WEBSITE_SITE_NAME;
|
|
1973
|
+
if (process.env.WEBSITE_HOME_STAMPNAME) {
|
|
1974
|
+
this.resourceIdentifier += "/" + process.env.WEBSITE_HOME_STAMPNAME;
|
|
1975
|
+
}
|
|
1947
1976
|
}
|
|
1948
1977
|
else if (process.env.FUNCTIONS_WORKER_RUNTIME) {
|
|
1949
1978
|
// Function apps
|
|
1950
|
-
this.
|
|
1979
|
+
this.resourceProvider = StatsbeatResourceProvider.functions;
|
|
1980
|
+
if (process.env.WEBSITE_HOSTNAME) {
|
|
1981
|
+
this.resourceIdentifier = process.env.WEBSITE_HOSTNAME;
|
|
1982
|
+
}
|
|
1951
1983
|
}
|
|
1952
1984
|
else if (await this.getAzureComputeMetadata()) {
|
|
1953
|
-
this.
|
|
1954
|
-
this.
|
|
1985
|
+
this.resourceProvider = StatsbeatResourceProvider.vm;
|
|
1986
|
+
this.resourceIdentifier = this.vmInfo.id + "/" + this.vmInfo.subscriptionId;
|
|
1955
1987
|
// Overrride OS as VM info have higher precedence
|
|
1956
|
-
if (this.
|
|
1957
|
-
this.
|
|
1988
|
+
if (this.vmInfo.osType) {
|
|
1989
|
+
this.os = this.vmInfo.osType;
|
|
1958
1990
|
}
|
|
1959
1991
|
}
|
|
1960
1992
|
else {
|
|
1961
|
-
this.
|
|
1993
|
+
this.resourceProvider = StatsbeatResourceProvider.unknown;
|
|
1962
1994
|
}
|
|
1963
1995
|
}
|
|
1964
1996
|
async getAzureComputeMetadata() {
|
|
@@ -1976,17 +2008,17 @@ class StatsbeatMetrics {
|
|
|
1976
2008
|
.then((res) => {
|
|
1977
2009
|
if (res.status === 200) {
|
|
1978
2010
|
// Success; VM
|
|
1979
|
-
this.
|
|
2011
|
+
this.vmInfo.isVM = true;
|
|
1980
2012
|
let virtualMachineData = "";
|
|
1981
2013
|
res.on("data", (data) => {
|
|
1982
2014
|
virtualMachineData += data;
|
|
1983
2015
|
});
|
|
1984
2016
|
res.on("end", () => {
|
|
1985
2017
|
try {
|
|
1986
|
-
|
|
1987
|
-
this.
|
|
1988
|
-
this.
|
|
1989
|
-
this.
|
|
2018
|
+
const data = JSON.parse(virtualMachineData);
|
|
2019
|
+
this.vmInfo.id = data["vmId"] || "";
|
|
2020
|
+
this.vmInfo.subscriptionId = data["subscriptionId"] || "";
|
|
2021
|
+
this.vmInfo.osType = data["osType"] || "";
|
|
1990
2022
|
}
|
|
1991
2023
|
catch (error) {
|
|
1992
2024
|
api.diag.debug("Failed to parse JSON: ", error);
|
|
@@ -2003,8 +2035,8 @@ class StatsbeatMetrics {
|
|
|
2003
2035
|
});
|
|
2004
2036
|
return false;
|
|
2005
2037
|
}
|
|
2006
|
-
|
|
2007
|
-
|
|
2038
|
+
getConnectionString(endpointUrl) {
|
|
2039
|
+
const currentEndpoint = endpointUrl;
|
|
2008
2040
|
for (let i = 0; i < EU_ENDPOINTS.length; i++) {
|
|
2009
2041
|
if (currentEndpoint.includes(EU_ENDPOINTS[i])) {
|
|
2010
2042
|
return EU_CONNECTION_STRING;
|
|
@@ -2015,6 +2047,7 @@ class StatsbeatMetrics {
|
|
|
2015
2047
|
}
|
|
2016
2048
|
|
|
2017
2049
|
// Copyright (c) Microsoft Corporation.
|
|
2050
|
+
// Licensed under the MIT license.
|
|
2018
2051
|
function createPropertiesFromMetricAttributes(attributes) {
|
|
2019
2052
|
const properties = {};
|
|
2020
2053
|
if (attributes) {
|
|
@@ -2029,7 +2062,7 @@ function createPropertiesFromMetricAttributes(attributes) {
|
|
|
2029
2062
|
* @internal
|
|
2030
2063
|
*/
|
|
2031
2064
|
function resourceMetricsToEnvelope(metrics, ikey, isStatsbeat) {
|
|
2032
|
-
|
|
2065
|
+
const envelopes = [];
|
|
2033
2066
|
const time = new Date();
|
|
2034
2067
|
const instrumentationKey = ikey;
|
|
2035
2068
|
const tags = createTagsFromResource(metrics.resource);
|
|
@@ -2043,19 +2076,19 @@ function resourceMetricsToEnvelope(metrics, ikey, isStatsbeat) {
|
|
|
2043
2076
|
metrics.scopeMetrics.forEach((scopeMetric) => {
|
|
2044
2077
|
scopeMetric.metrics.forEach((metric) => {
|
|
2045
2078
|
metric.dataPoints.forEach((dataPoint) => {
|
|
2046
|
-
|
|
2079
|
+
const baseData = {
|
|
2047
2080
|
metrics: [],
|
|
2048
2081
|
version: 2,
|
|
2049
2082
|
properties: {},
|
|
2050
2083
|
};
|
|
2051
2084
|
baseData.properties = createPropertiesFromMetricAttributes(dataPoint.attributes);
|
|
2052
|
-
|
|
2085
|
+
const metricDataPoint = {
|
|
2053
2086
|
name: metric.descriptor.name,
|
|
2054
2087
|
value: 0,
|
|
2055
2088
|
dataPointType: "Aggregation",
|
|
2056
2089
|
};
|
|
2057
|
-
if (metric.dataPointType
|
|
2058
|
-
metric.dataPointType
|
|
2090
|
+
if (metric.dataPointType === sdkMetrics.DataPointType.SUM ||
|
|
2091
|
+
metric.dataPointType === sdkMetrics.DataPointType.GAUGE) {
|
|
2059
2092
|
metricDataPoint.value = dataPoint.value;
|
|
2060
2093
|
metricDataPoint.count = 1;
|
|
2061
2094
|
}
|
|
@@ -2066,7 +2099,7 @@ function resourceMetricsToEnvelope(metrics, ikey, isStatsbeat) {
|
|
|
2066
2099
|
metricDataPoint.min = dataPoint.value.min;
|
|
2067
2100
|
}
|
|
2068
2101
|
baseData.metrics.push(metricDataPoint);
|
|
2069
|
-
|
|
2102
|
+
const envelope = {
|
|
2070
2103
|
name: envelopeName,
|
|
2071
2104
|
time: time,
|
|
2072
2105
|
sampleRate: 100,
|
|
@@ -2086,6 +2119,7 @@ function resourceMetricsToEnvelope(metrics, ikey, isStatsbeat) {
|
|
|
2086
2119
|
}
|
|
2087
2120
|
|
|
2088
2121
|
// Copyright (c) Microsoft Corporation.
|
|
2122
|
+
// Licensed under the MIT license.
|
|
2089
2123
|
/**
|
|
2090
2124
|
* Azure Monitor Statsbeat Exporter
|
|
2091
2125
|
*/
|
|
@@ -2100,7 +2134,12 @@ class AzureMonitorStatsbeatExporter extends AzureMonitorBaseExporter {
|
|
|
2100
2134
|
* Flag to determine if the Exporter is shutdown.
|
|
2101
2135
|
*/
|
|
2102
2136
|
this._isShutdown = false;
|
|
2103
|
-
this._sender = new HttpSender(
|
|
2137
|
+
this._sender = new HttpSender({
|
|
2138
|
+
endpointUrl: this.endpointUrl,
|
|
2139
|
+
instrumentationKey: this.instrumentationKey,
|
|
2140
|
+
trackStatsbeat: this.trackStatsbeat,
|
|
2141
|
+
exporterOptions: options,
|
|
2142
|
+
});
|
|
2104
2143
|
}
|
|
2105
2144
|
/**
|
|
2106
2145
|
* Export Statsbeat metrics.
|
|
@@ -2110,7 +2149,7 @@ class AzureMonitorStatsbeatExporter extends AzureMonitorBaseExporter {
|
|
|
2110
2149
|
setTimeout(() => resultCallback({ code: core.ExportResultCode.FAILED }), 0);
|
|
2111
2150
|
return;
|
|
2112
2151
|
}
|
|
2113
|
-
|
|
2152
|
+
const envelopes = resourceMetricsToEnvelope(metrics, this.instrumentationKey, true // isStatsbeat flag passed to create a Statsbeat envelope.
|
|
2114
2153
|
);
|
|
2115
2154
|
// Supress tracing until OpenTelemetry Metrics SDK support it
|
|
2116
2155
|
api.context.with(core.suppressTracing(api.context.active()), async () => {
|
|
@@ -2133,140 +2172,138 @@ class AzureMonitorStatsbeatExporter extends AzureMonitorBaseExporter {
|
|
|
2133
2172
|
}
|
|
2134
2173
|
|
|
2135
2174
|
// Copyright (c) Microsoft Corporation.
|
|
2175
|
+
// Licensed under the MIT license.
|
|
2136
2176
|
class NetworkStatsbeatMetrics extends StatsbeatMetrics {
|
|
2137
2177
|
constructor(options) {
|
|
2138
2178
|
super();
|
|
2139
|
-
this.
|
|
2140
|
-
this.
|
|
2141
|
-
this.
|
|
2142
|
-
this.
|
|
2143
|
-
this.
|
|
2144
|
-
this.
|
|
2179
|
+
this.isInitialized = false;
|
|
2180
|
+
this.statsCollectionShortInterval = 900000; // 15 minutes
|
|
2181
|
+
this.networkStatsbeatCollection = [];
|
|
2182
|
+
this.attach = "sdk";
|
|
2183
|
+
this.connectionString = super.getConnectionString(options.endpointUrl);
|
|
2184
|
+
this.networkStatsbeatMeterProvider = new sdkMetrics.MeterProvider();
|
|
2145
2185
|
const exporterConfig = {
|
|
2146
|
-
connectionString: this.
|
|
2186
|
+
connectionString: this.connectionString,
|
|
2147
2187
|
};
|
|
2148
|
-
this.
|
|
2188
|
+
this.networkAzureExporter = new AzureMonitorStatsbeatExporter(exporterConfig);
|
|
2149
2189
|
// Exports Network Statsbeat every 15 minutes
|
|
2150
2190
|
const networkMetricReaderOptions = {
|
|
2151
|
-
exporter: this.
|
|
2152
|
-
exportIntervalMillis: options.networkCollectionInterval || this.
|
|
2191
|
+
exporter: this.networkAzureExporter,
|
|
2192
|
+
exportIntervalMillis: options.networkCollectionInterval || this.statsCollectionShortInterval, // 15 minutes
|
|
2153
2193
|
};
|
|
2154
|
-
this.
|
|
2155
|
-
this.
|
|
2156
|
-
this.
|
|
2157
|
-
this.
|
|
2158
|
-
this.
|
|
2159
|
-
this.
|
|
2160
|
-
this.
|
|
2161
|
-
this.
|
|
2162
|
-
this.
|
|
2163
|
-
this.
|
|
2164
|
-
this.
|
|
2165
|
-
this.
|
|
2166
|
-
this.
|
|
2167
|
-
this.
|
|
2168
|
-
this.
|
|
2169
|
-
this.
|
|
2170
|
-
os: super.
|
|
2171
|
-
rp: super.
|
|
2172
|
-
cikey: this.
|
|
2173
|
-
runtimeVersion: this.
|
|
2174
|
-
language: this.
|
|
2175
|
-
version: this.
|
|
2176
|
-
attach: this.
|
|
2194
|
+
this.networkMetricReader = new sdkMetrics.PeriodicExportingMetricReader(networkMetricReaderOptions);
|
|
2195
|
+
this.networkStatsbeatMeterProvider.addMetricReader(this.networkMetricReader);
|
|
2196
|
+
this.networkStatsbeatMeter = this.networkStatsbeatMeterProvider.getMeter("Azure Monitor Network Statsbeat");
|
|
2197
|
+
this.endpointUrl = options.endpointUrl;
|
|
2198
|
+
this.runtimeVersion = process.version;
|
|
2199
|
+
this.language = STATSBEAT_LANGUAGE;
|
|
2200
|
+
this.version = packageVersion;
|
|
2201
|
+
this.host = this.getShortHost(options.endpointUrl);
|
|
2202
|
+
this.cikey = options.instrumentationKey;
|
|
2203
|
+
this.successCountGauge = this.networkStatsbeatMeter.createObservableGauge(StatsbeatCounter.SUCCESS_COUNT);
|
|
2204
|
+
this.failureCountGauge = this.networkStatsbeatMeter.createObservableGauge(StatsbeatCounter.FAILURE_COUNT);
|
|
2205
|
+
this.retryCountGauge = this.networkStatsbeatMeter.createObservableGauge(StatsbeatCounter.RETRY_COUNT);
|
|
2206
|
+
this.throttleCountGauge = this.networkStatsbeatMeter.createObservableGauge(StatsbeatCounter.THROTTLE_COUNT);
|
|
2207
|
+
this.exceptionCountGauge = this.networkStatsbeatMeter.createObservableGauge(StatsbeatCounter.EXCEPTION_COUNT);
|
|
2208
|
+
this.averageDurationGauge = this.networkStatsbeatMeter.createObservableGauge(StatsbeatCounter.AVERAGE_DURATION);
|
|
2209
|
+
this.commonProperties = {
|
|
2210
|
+
os: super.os,
|
|
2211
|
+
rp: super.resourceProvider,
|
|
2212
|
+
cikey: this.cikey,
|
|
2213
|
+
runtimeVersion: this.runtimeVersion,
|
|
2214
|
+
language: this.language,
|
|
2215
|
+
version: this.version,
|
|
2216
|
+
attach: this.attach,
|
|
2177
2217
|
};
|
|
2178
|
-
this.
|
|
2179
|
-
endpoint: this.
|
|
2180
|
-
host: this.
|
|
2218
|
+
this.networkProperties = {
|
|
2219
|
+
endpoint: this.endpointUrl,
|
|
2220
|
+
host: this.host,
|
|
2181
2221
|
};
|
|
2182
|
-
this.
|
|
2183
|
-
this.
|
|
2184
|
-
}
|
|
2185
|
-
isInitialized() {
|
|
2186
|
-
return this._isInitialized;
|
|
2222
|
+
this.isInitialized = true;
|
|
2223
|
+
this.initialize();
|
|
2187
2224
|
}
|
|
2188
2225
|
shutdown() {
|
|
2189
|
-
this.
|
|
2226
|
+
return this.networkStatsbeatMeterProvider.shutdown();
|
|
2190
2227
|
}
|
|
2191
|
-
async
|
|
2228
|
+
async initialize() {
|
|
2192
2229
|
try {
|
|
2193
|
-
await super.
|
|
2230
|
+
await super.getResourceProvider();
|
|
2194
2231
|
// Add network observable callbacks
|
|
2195
|
-
this.
|
|
2196
|
-
this.
|
|
2197
|
-
this.
|
|
2232
|
+
this.successCountGauge.addCallback(this.successCallback.bind(this));
|
|
2233
|
+
this.networkStatsbeatMeter.addBatchObservableCallback(this.failureCallback.bind(this), [
|
|
2234
|
+
this.failureCountGauge,
|
|
2198
2235
|
]);
|
|
2199
|
-
this.
|
|
2200
|
-
this.
|
|
2236
|
+
this.networkStatsbeatMeter.addBatchObservableCallback(this.retryCallback.bind(this), [
|
|
2237
|
+
this.retryCountGauge,
|
|
2201
2238
|
]);
|
|
2202
|
-
this.
|
|
2203
|
-
this.
|
|
2239
|
+
this.networkStatsbeatMeter.addBatchObservableCallback(this.throttleCallback.bind(this), [
|
|
2240
|
+
this.throttleCountGauge,
|
|
2204
2241
|
]);
|
|
2205
|
-
this.
|
|
2206
|
-
this.
|
|
2242
|
+
this.networkStatsbeatMeter.addBatchObservableCallback(this.exceptionCallback.bind(this), [
|
|
2243
|
+
this.exceptionCountGauge,
|
|
2207
2244
|
]);
|
|
2208
|
-
this.
|
|
2245
|
+
this.averageDurationGauge.addCallback(this.durationCallback.bind(this));
|
|
2209
2246
|
}
|
|
2210
2247
|
catch (error) {
|
|
2211
2248
|
api.diag.debug("Call to get the resource provider failed.");
|
|
2212
2249
|
}
|
|
2213
2250
|
}
|
|
2214
2251
|
// Observable gauge callbacks
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2252
|
+
successCallback(observableResult) {
|
|
2253
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2254
|
+
const attributes = Object.assign(Object.assign({}, this.commonProperties), this.networkProperties);
|
|
2218
2255
|
observableResult.observe(counter.totalSuccesfulRequestCount, attributes);
|
|
2219
2256
|
counter.totalSuccesfulRequestCount = 0;
|
|
2220
2257
|
}
|
|
2221
|
-
|
|
2222
|
-
|
|
2258
|
+
failureCallback(observableResult) {
|
|
2259
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2223
2260
|
/*
|
|
2224
2261
|
Takes the failureCountGauge, value (of the counter), and attributes
|
|
2225
2262
|
create a unqiue counter based on statusCode as well
|
|
2226
2263
|
append statusCode to attributes so the newly created attributes are unique.
|
|
2227
2264
|
*/
|
|
2228
|
-
|
|
2265
|
+
const attributes = Object.assign(Object.assign(Object.assign({}, this.networkProperties), this.commonProperties), { statusCode: 0 });
|
|
2229
2266
|
// For each { statusCode -> count } mapping, call observe, passing the count and attributes that include the statusCode
|
|
2230
2267
|
for (let i = 0; i < counter.totalFailedRequestCount.length; i++) {
|
|
2231
2268
|
attributes.statusCode = counter.totalFailedRequestCount[i].statusCode;
|
|
2232
|
-
observableResult.observe(this.
|
|
2269
|
+
observableResult.observe(this.failureCountGauge, counter.totalFailedRequestCount[i].count, Object.assign({}, attributes));
|
|
2233
2270
|
counter.totalFailedRequestCount[i].count = 0;
|
|
2234
2271
|
}
|
|
2235
2272
|
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2273
|
+
retryCallback(observableResult) {
|
|
2274
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2275
|
+
const attributes = Object.assign(Object.assign(Object.assign({}, this.networkProperties), this.commonProperties), { statusCode: 0 });
|
|
2239
2276
|
for (let i = 0; i < counter.retryCount.length; i++) {
|
|
2240
2277
|
attributes.statusCode = counter.retryCount[i].statusCode;
|
|
2241
|
-
observableResult.observe(this.
|
|
2278
|
+
observableResult.observe(this.retryCountGauge, counter.retryCount[i].count, Object.assign({}, attributes));
|
|
2242
2279
|
counter.retryCount[i].count = 0;
|
|
2243
2280
|
}
|
|
2244
2281
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2282
|
+
throttleCallback(observableResult) {
|
|
2283
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2284
|
+
const attributes = Object.assign(Object.assign(Object.assign({}, this.networkProperties), this.commonProperties), { statusCode: 0 });
|
|
2248
2285
|
for (let i = 0; i < counter.throttleCount.length; i++) {
|
|
2249
2286
|
attributes.statusCode = counter.throttleCount[i].statusCode;
|
|
2250
|
-
observableResult.observe(this.
|
|
2287
|
+
observableResult.observe(this.throttleCountGauge, counter.throttleCount[i].count, Object.assign({}, attributes));
|
|
2251
2288
|
counter.throttleCount[i].count = 0;
|
|
2252
2289
|
}
|
|
2253
2290
|
}
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2291
|
+
exceptionCallback(observableResult) {
|
|
2292
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2293
|
+
const attributes = Object.assign(Object.assign(Object.assign({}, this.networkProperties), this.commonProperties), { exceptionType: "" });
|
|
2257
2294
|
for (let i = 0; i < counter.exceptionCount.length; i++) {
|
|
2258
2295
|
attributes.exceptionType = counter.exceptionCount[i].exceptionType;
|
|
2259
|
-
observableResult.observe(this.
|
|
2296
|
+
observableResult.observe(this.exceptionCountGauge, counter.exceptionCount[i].count, Object.assign({}, attributes));
|
|
2260
2297
|
counter.exceptionCount[i].count = 0;
|
|
2261
2298
|
}
|
|
2262
2299
|
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
for (let i = 0; i < this.
|
|
2267
|
-
|
|
2300
|
+
durationCallback(observableResult) {
|
|
2301
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2302
|
+
const attributes = Object.assign(Object.assign({}, this.networkProperties), this.commonProperties);
|
|
2303
|
+
for (let i = 0; i < this.networkStatsbeatCollection.length; i++) {
|
|
2304
|
+
const currentCounter = this.networkStatsbeatCollection[i];
|
|
2268
2305
|
currentCounter.time = Number(new Date());
|
|
2269
|
-
|
|
2306
|
+
const intervalRequests = currentCounter.totalRequestCount - currentCounter.lastRequestCount || 0;
|
|
2270
2307
|
currentCounter.averageRequestExecutionTime =
|
|
2271
2308
|
(currentCounter.intervalRequestExecutionTime -
|
|
2272
2309
|
currentCounter.lastIntervalRequestExecutionTime) /
|
|
@@ -2280,20 +2317,20 @@ class NetworkStatsbeatMetrics extends StatsbeatMetrics {
|
|
|
2280
2317
|
}
|
|
2281
2318
|
// Public methods to increase counters
|
|
2282
2319
|
countSuccess(duration) {
|
|
2283
|
-
if (!this.
|
|
2320
|
+
if (!this.isInitialized) {
|
|
2284
2321
|
return;
|
|
2285
2322
|
}
|
|
2286
|
-
|
|
2323
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2287
2324
|
counter.totalRequestCount++;
|
|
2288
2325
|
counter.totalSuccesfulRequestCount++;
|
|
2289
2326
|
counter.intervalRequestExecutionTime += duration;
|
|
2290
2327
|
}
|
|
2291
2328
|
countFailure(duration, statusCode) {
|
|
2292
|
-
if (!this.
|
|
2329
|
+
if (!this.isInitialized) {
|
|
2293
2330
|
return;
|
|
2294
2331
|
}
|
|
2295
|
-
|
|
2296
|
-
|
|
2332
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2333
|
+
const currentStatusCounter = counter.totalFailedRequestCount.find((statusCounter) => statusCode === statusCounter.statusCode);
|
|
2297
2334
|
if (currentStatusCounter) {
|
|
2298
2335
|
currentStatusCounter.count++;
|
|
2299
2336
|
}
|
|
@@ -2304,11 +2341,11 @@ class NetworkStatsbeatMetrics extends StatsbeatMetrics {
|
|
|
2304
2341
|
counter.intervalRequestExecutionTime += duration;
|
|
2305
2342
|
}
|
|
2306
2343
|
countRetry(statusCode) {
|
|
2307
|
-
if (!this.
|
|
2344
|
+
if (!this.isInitialized) {
|
|
2308
2345
|
return;
|
|
2309
2346
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2347
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2348
|
+
const currentStatusCounter = counter.retryCount.find((statusCounter) => statusCode === statusCounter.statusCode);
|
|
2312
2349
|
if (currentStatusCounter) {
|
|
2313
2350
|
currentStatusCounter.count++;
|
|
2314
2351
|
}
|
|
@@ -2317,11 +2354,11 @@ class NetworkStatsbeatMetrics extends StatsbeatMetrics {
|
|
|
2317
2354
|
}
|
|
2318
2355
|
}
|
|
2319
2356
|
countThrottle(statusCode) {
|
|
2320
|
-
if (!this.
|
|
2357
|
+
if (!this.isInitialized) {
|
|
2321
2358
|
return;
|
|
2322
2359
|
}
|
|
2323
|
-
|
|
2324
|
-
|
|
2360
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2361
|
+
const currentStatusCounter = counter.throttleCount.find((statusCounter) => statusCode === statusCounter.statusCode);
|
|
2325
2362
|
if (currentStatusCounter) {
|
|
2326
2363
|
currentStatusCounter.count++;
|
|
2327
2364
|
}
|
|
@@ -2330,11 +2367,11 @@ class NetworkStatsbeatMetrics extends StatsbeatMetrics {
|
|
|
2330
2367
|
}
|
|
2331
2368
|
}
|
|
2332
2369
|
countException(exceptionType) {
|
|
2333
|
-
if (!this.
|
|
2370
|
+
if (!this.isInitialized) {
|
|
2334
2371
|
return;
|
|
2335
2372
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2373
|
+
const counter = this.getNetworkStatsbeatCounter(this.endpointUrl, this.host);
|
|
2374
|
+
const currentErrorCounter = counter.exceptionCount.find((exceptionCounter) => exceptionType.name === exceptionCounter.exceptionType);
|
|
2338
2375
|
if (currentErrorCounter) {
|
|
2339
2376
|
currentErrorCounter.count++;
|
|
2340
2377
|
}
|
|
@@ -2343,26 +2380,26 @@ class NetworkStatsbeatMetrics extends StatsbeatMetrics {
|
|
|
2343
2380
|
}
|
|
2344
2381
|
}
|
|
2345
2382
|
// Gets a networkStatsbeat counter if one exists for the given endpoint
|
|
2346
|
-
|
|
2383
|
+
getNetworkStatsbeatCounter(endpoint, host) {
|
|
2347
2384
|
// Check if the counter is available
|
|
2348
|
-
for (let i = 0; i < this.
|
|
2385
|
+
for (let i = 0; i < this.networkStatsbeatCollection.length; i++) {
|
|
2349
2386
|
// Same object
|
|
2350
|
-
if (endpoint === this.
|
|
2351
|
-
host === this.
|
|
2352
|
-
return this.
|
|
2387
|
+
if (endpoint === this.networkStatsbeatCollection[i].endpoint &&
|
|
2388
|
+
host === this.networkStatsbeatCollection[i].host) {
|
|
2389
|
+
return this.networkStatsbeatCollection[i];
|
|
2353
2390
|
}
|
|
2354
2391
|
}
|
|
2355
2392
|
// Create a new counter if not found
|
|
2356
|
-
|
|
2357
|
-
this.
|
|
2393
|
+
const newCounter = new NetworkStatsbeat(endpoint, host);
|
|
2394
|
+
this.networkStatsbeatCollection.push(newCounter);
|
|
2358
2395
|
return newCounter;
|
|
2359
2396
|
}
|
|
2360
|
-
|
|
2397
|
+
getShortHost(originalHost) {
|
|
2361
2398
|
let shortHost = originalHost;
|
|
2362
2399
|
try {
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
if (res
|
|
2400
|
+
const hostRegex = new RegExp(/^https?:\/\/(?:www\.)?([^\/.-]+)/);
|
|
2401
|
+
const res = hostRegex.exec(originalHost);
|
|
2402
|
+
if (res !== null && res.length > 1) {
|
|
2366
2403
|
shortHost = res[1];
|
|
2367
2404
|
}
|
|
2368
2405
|
shortHost = shortHost.replace(".in.applicationinsights.azure.com", "");
|
|
@@ -2375,6 +2412,7 @@ class NetworkStatsbeatMetrics extends StatsbeatMetrics {
|
|
|
2375
2412
|
}
|
|
2376
2413
|
|
|
2377
2414
|
// Copyright (c) Microsoft Corporation.
|
|
2415
|
+
// Licensed under the MIT license.
|
|
2378
2416
|
let instance$1 = null;
|
|
2379
2417
|
/**
|
|
2380
2418
|
* Long Interval Statsbeat Metrics
|
|
@@ -2383,65 +2421,67 @@ let instance$1 = null;
|
|
|
2383
2421
|
class LongIntervalStatsbeatMetrics extends StatsbeatMetrics {
|
|
2384
2422
|
constructor(options) {
|
|
2385
2423
|
super();
|
|
2386
|
-
this.
|
|
2387
|
-
this.
|
|
2388
|
-
this.
|
|
2389
|
-
this.
|
|
2390
|
-
this.
|
|
2391
|
-
this.
|
|
2392
|
-
this.
|
|
2424
|
+
this.AZURE_MONITOR_STATSBEAT_FEATURES = process.env.AZURE_MONITOR_STATSBEAT_FEATURES;
|
|
2425
|
+
this.statsCollectionLongInterval = 86400000; // 1 day
|
|
2426
|
+
this.attach = "sdk";
|
|
2427
|
+
this.feature = 0;
|
|
2428
|
+
this.instrumentation = 0;
|
|
2429
|
+
this.isInitialized = false;
|
|
2430
|
+
this.connectionString = super.getConnectionString(options.endpointUrl);
|
|
2393
2431
|
const exporterConfig = {
|
|
2394
|
-
connectionString: this.
|
|
2432
|
+
connectionString: this.connectionString,
|
|
2395
2433
|
};
|
|
2396
|
-
if (this.
|
|
2434
|
+
if (this.AZURE_MONITOR_STATSBEAT_FEATURES) {
|
|
2397
2435
|
try {
|
|
2398
|
-
this.
|
|
2399
|
-
this.
|
|
2436
|
+
this.feature = JSON.parse(this.AZURE_MONITOR_STATSBEAT_FEATURES).feature;
|
|
2437
|
+
this.instrumentation = JSON.parse(this.AZURE_MONITOR_STATSBEAT_FEATURES).instrumentation;
|
|
2400
2438
|
}
|
|
2401
2439
|
catch (error) {
|
|
2402
2440
|
api.diag.error(`LongIntervalStatsbeat: Failed to parse features/instrumentations (error ${error})`);
|
|
2403
2441
|
}
|
|
2404
2442
|
}
|
|
2405
|
-
this.
|
|
2406
|
-
this.
|
|
2443
|
+
this.longIntervalStatsbeatMeterProvider = new sdkMetrics.MeterProvider();
|
|
2444
|
+
this.longIntervalAzureExporter = new AzureMonitorStatsbeatExporter(exporterConfig);
|
|
2407
2445
|
// Export Long Interval Statsbeats every day
|
|
2408
2446
|
const longIntervalMetricReaderOptions = {
|
|
2409
|
-
exporter: this.
|
|
2410
|
-
exportIntervalMillis: Number(process.env.LONG_INTERVAL_EXPORT_MILLIS) || this.
|
|
2447
|
+
exporter: this.longIntervalAzureExporter,
|
|
2448
|
+
exportIntervalMillis: Number(process.env.LONG_INTERVAL_EXPORT_MILLIS) || this.statsCollectionLongInterval, // 1 day
|
|
2411
2449
|
};
|
|
2412
|
-
this.
|
|
2413
|
-
this.
|
|
2414
|
-
this.
|
|
2450
|
+
this.longIntervalMetricReader = new sdkMetrics.PeriodicExportingMetricReader(longIntervalMetricReaderOptions);
|
|
2451
|
+
this.longIntervalStatsbeatMeterProvider.addMetricReader(this.longIntervalMetricReader);
|
|
2452
|
+
this.longIntervalStatsbeatMeter = this.longIntervalStatsbeatMeterProvider.getMeter("Azure Monitor Long Interval Statsbeat");
|
|
2415
2453
|
// Assign Common Properties
|
|
2416
|
-
this.
|
|
2417
|
-
this.
|
|
2418
|
-
this.
|
|
2419
|
-
this.
|
|
2420
|
-
this.
|
|
2421
|
-
this.
|
|
2422
|
-
this.
|
|
2423
|
-
os: super.
|
|
2424
|
-
rp: super.
|
|
2425
|
-
cikey: this.
|
|
2426
|
-
runtimeVersion: this.
|
|
2427
|
-
language: this.
|
|
2428
|
-
version: this.
|
|
2429
|
-
attach: this.
|
|
2454
|
+
this.runtimeVersion = process.version;
|
|
2455
|
+
this.language = STATSBEAT_LANGUAGE;
|
|
2456
|
+
this.version = packageVersion;
|
|
2457
|
+
this.cikey = options.instrumentationKey;
|
|
2458
|
+
this.featureStatsbeatGauge = this.longIntervalStatsbeatMeter.createObservableGauge(StatsbeatCounter.FEATURE);
|
|
2459
|
+
this.attachStatsbeatGauge = this.longIntervalStatsbeatMeter.createObservableGauge(StatsbeatCounter.ATTACH);
|
|
2460
|
+
this.commonProperties = {
|
|
2461
|
+
os: super.os,
|
|
2462
|
+
rp: super.resourceProvider,
|
|
2463
|
+
cikey: this.cikey,
|
|
2464
|
+
runtimeVersion: this.runtimeVersion,
|
|
2465
|
+
language: this.language,
|
|
2466
|
+
version: this.version,
|
|
2467
|
+
attach: this.attach,
|
|
2430
2468
|
};
|
|
2431
|
-
this.
|
|
2432
|
-
rpId: super.
|
|
2469
|
+
this.attachProperties = {
|
|
2470
|
+
rpId: super.resourceIdentifier,
|
|
2433
2471
|
};
|
|
2434
|
-
this.
|
|
2435
|
-
this.
|
|
2472
|
+
this.isInitialized = true;
|
|
2473
|
+
this.initialize();
|
|
2436
2474
|
}
|
|
2437
|
-
async
|
|
2475
|
+
async initialize() {
|
|
2438
2476
|
try {
|
|
2439
|
-
await this.
|
|
2477
|
+
await this.getResourceProvider();
|
|
2440
2478
|
// Add long interval observable callbacks
|
|
2441
|
-
this.
|
|
2442
|
-
this.
|
|
2479
|
+
this.attachStatsbeatGauge.addCallback(this.attachCallback.bind(this));
|
|
2480
|
+
this.longIntervalStatsbeatMeter.addBatchObservableCallback(this.featureCallback.bind(this), [
|
|
2481
|
+
this.featureStatsbeatGauge,
|
|
2482
|
+
]);
|
|
2443
2483
|
// Export Feature/Attach Statsbeat once upon app initialization
|
|
2444
|
-
this.
|
|
2484
|
+
this.longIntervalAzureExporter.export((await this.longIntervalMetricReader.collect()).resourceMetrics, (result) => {
|
|
2445
2485
|
if (result.code !== core.ExportResultCode.SUCCESS) {
|
|
2446
2486
|
api.diag.error(`LongIntervalStatsbeat: metrics export failed (error ${result.error})`);
|
|
2447
2487
|
}
|
|
@@ -2451,26 +2491,23 @@ class LongIntervalStatsbeatMetrics extends StatsbeatMetrics {
|
|
|
2451
2491
|
api.diag.debug("Call to get the resource provider failed.");
|
|
2452
2492
|
}
|
|
2453
2493
|
}
|
|
2454
|
-
|
|
2494
|
+
featureCallback(observableResult) {
|
|
2455
2495
|
let attributes;
|
|
2456
|
-
if (this.
|
|
2457
|
-
attributes = Object.assign(Object.assign({}, this.
|
|
2458
|
-
observableResult.observe(this.
|
|
2496
|
+
if (this.instrumentation) {
|
|
2497
|
+
attributes = Object.assign(Object.assign({}, this.commonProperties), { feature: this.instrumentation, type: StatsbeatFeatureType.INSTRUMENTATION });
|
|
2498
|
+
observableResult.observe(this.featureStatsbeatGauge, 1, Object.assign({}, attributes));
|
|
2459
2499
|
}
|
|
2460
|
-
if (this.
|
|
2461
|
-
attributes = Object.assign(Object.assign({}, this.
|
|
2462
|
-
observableResult.observe(this.
|
|
2500
|
+
if (this.feature) {
|
|
2501
|
+
attributes = Object.assign(Object.assign({}, this.commonProperties), { feature: this.feature, type: StatsbeatFeatureType.FEATURE });
|
|
2502
|
+
observableResult.observe(this.featureStatsbeatGauge, 1, Object.assign({}, attributes));
|
|
2463
2503
|
}
|
|
2464
2504
|
}
|
|
2465
|
-
|
|
2466
|
-
|
|
2505
|
+
attachCallback(observableResult) {
|
|
2506
|
+
const attributes = Object.assign(Object.assign({}, this.commonProperties), this.attachProperties);
|
|
2467
2507
|
observableResult.observe(1, attributes);
|
|
2468
2508
|
}
|
|
2469
|
-
isInitialized() {
|
|
2470
|
-
return this._isInitialized;
|
|
2471
|
-
}
|
|
2472
2509
|
shutdown() {
|
|
2473
|
-
this.
|
|
2510
|
+
return this.longIntervalStatsbeatMeterProvider.shutdown();
|
|
2474
2511
|
}
|
|
2475
2512
|
}
|
|
2476
2513
|
/**
|
|
@@ -2524,29 +2561,30 @@ function msToTimeSpan(ms) {
|
|
|
2524
2561
|
}
|
|
2525
2562
|
|
|
2526
2563
|
// Copyright (c) Microsoft Corporation.
|
|
2564
|
+
// Licensed under the MIT license.
|
|
2527
2565
|
const DEFAULT_BATCH_SEND_RETRY_INTERVAL_MS = 60000;
|
|
2528
2566
|
/**
|
|
2529
2567
|
* Base sender class
|
|
2530
2568
|
* @internal
|
|
2531
2569
|
*/
|
|
2532
2570
|
class BaseSender {
|
|
2533
|
-
constructor(
|
|
2534
|
-
this.
|
|
2535
|
-
this.
|
|
2536
|
-
this.
|
|
2537
|
-
this.
|
|
2538
|
-
if (trackStatsbeat) {
|
|
2571
|
+
constructor(options) {
|
|
2572
|
+
this.statsbeatFailureCount = 0;
|
|
2573
|
+
this.batchSendRetryIntervalMs = DEFAULT_BATCH_SEND_RETRY_INTERVAL_MS;
|
|
2574
|
+
this.numConsecutiveRedirects = 0;
|
|
2575
|
+
this.persister = new FileSystemPersist(options.instrumentationKey, options.exporterOptions);
|
|
2576
|
+
if (options.trackStatsbeat) {
|
|
2539
2577
|
// Initialize statsbeatMetrics
|
|
2540
|
-
this.
|
|
2541
|
-
instrumentationKey: instrumentationKey,
|
|
2542
|
-
endpointUrl: endpointUrl,
|
|
2578
|
+
this.networkStatsbeatMetrics = new NetworkStatsbeatMetrics({
|
|
2579
|
+
instrumentationKey: options.instrumentationKey,
|
|
2580
|
+
endpointUrl: options.endpointUrl,
|
|
2543
2581
|
});
|
|
2544
|
-
this.
|
|
2545
|
-
instrumentationKey: instrumentationKey,
|
|
2546
|
-
endpointUrl: endpointUrl,
|
|
2582
|
+
this.longIntervalStatsbeatMetrics = getInstance$1({
|
|
2583
|
+
instrumentationKey: options.instrumentationKey,
|
|
2584
|
+
endpointUrl: options.endpointUrl,
|
|
2547
2585
|
});
|
|
2548
2586
|
}
|
|
2549
|
-
this.
|
|
2587
|
+
this.retryTimer = null;
|
|
2550
2588
|
}
|
|
2551
2589
|
/**
|
|
2552
2590
|
* Export envelopes
|
|
@@ -2562,24 +2600,24 @@ class BaseSender {
|
|
|
2562
2600
|
const { result, statusCode } = await this.send(envelopes);
|
|
2563
2601
|
const endTime = new Date().getTime();
|
|
2564
2602
|
const duration = endTime - startTime;
|
|
2565
|
-
this.
|
|
2603
|
+
this.numConsecutiveRedirects = 0;
|
|
2566
2604
|
if (statusCode === 200) {
|
|
2567
2605
|
// Success -- @todo: start retry timer
|
|
2568
|
-
if (!this.
|
|
2569
|
-
this.
|
|
2570
|
-
this.
|
|
2571
|
-
this.
|
|
2572
|
-
}, this.
|
|
2573
|
-
this.
|
|
2606
|
+
if (!this.retryTimer) {
|
|
2607
|
+
this.retryTimer = setTimeout(() => {
|
|
2608
|
+
this.retryTimer = null;
|
|
2609
|
+
this.sendFirstPersistedFile();
|
|
2610
|
+
}, this.batchSendRetryIntervalMs);
|
|
2611
|
+
this.retryTimer.unref();
|
|
2574
2612
|
}
|
|
2575
2613
|
// If we are not exportings statsbeat and statsbeat is not disabled -- count success
|
|
2576
|
-
(_a = this.
|
|
2614
|
+
(_a = this.networkStatsbeatMetrics) === null || _a === void 0 ? void 0 : _a.countSuccess(duration);
|
|
2577
2615
|
return { code: core.ExportResultCode.SUCCESS };
|
|
2578
2616
|
}
|
|
2579
2617
|
else if (statusCode && isRetriable(statusCode)) {
|
|
2580
2618
|
// Failed -- persist failed data
|
|
2581
2619
|
if (statusCode === 429 || statusCode === 439) {
|
|
2582
|
-
(_b = this.
|
|
2620
|
+
(_b = this.networkStatsbeatMetrics) === null || _b === void 0 ? void 0 : _b.countThrottle(statusCode);
|
|
2583
2621
|
}
|
|
2584
2622
|
if (result) {
|
|
2585
2623
|
api.diag.info(result);
|
|
@@ -2593,31 +2631,31 @@ class BaseSender {
|
|
|
2593
2631
|
});
|
|
2594
2632
|
}
|
|
2595
2633
|
if (filteredEnvelopes.length > 0) {
|
|
2596
|
-
(_c = this.
|
|
2634
|
+
(_c = this.networkStatsbeatMetrics) === null || _c === void 0 ? void 0 : _c.countRetry(statusCode);
|
|
2597
2635
|
// calls resultCallback(ExportResult) based on result of persister.push
|
|
2598
|
-
return await this.
|
|
2636
|
+
return await this.persist(filteredEnvelopes);
|
|
2599
2637
|
}
|
|
2600
2638
|
// Failed -- not retriable
|
|
2601
|
-
(_d = this.
|
|
2639
|
+
(_d = this.networkStatsbeatMetrics) === null || _d === void 0 ? void 0 : _d.countFailure(duration, statusCode);
|
|
2602
2640
|
return {
|
|
2603
2641
|
code: core.ExportResultCode.FAILED,
|
|
2604
2642
|
};
|
|
2605
2643
|
}
|
|
2606
2644
|
else {
|
|
2607
2645
|
// calls resultCallback(ExportResult) based on result of persister.push
|
|
2608
|
-
(_e = this.
|
|
2609
|
-
return await this.
|
|
2646
|
+
(_e = this.networkStatsbeatMetrics) === null || _e === void 0 ? void 0 : _e.countRetry(statusCode);
|
|
2647
|
+
return await this.persist(envelopes);
|
|
2610
2648
|
}
|
|
2611
2649
|
}
|
|
2612
2650
|
else {
|
|
2613
2651
|
// Failed -- not retriable
|
|
2614
|
-
if (this.
|
|
2652
|
+
if (this.networkStatsbeatMetrics) {
|
|
2615
2653
|
if (statusCode) {
|
|
2616
|
-
this.
|
|
2654
|
+
this.networkStatsbeatMetrics.countFailure(duration, statusCode);
|
|
2617
2655
|
}
|
|
2618
2656
|
}
|
|
2619
2657
|
else {
|
|
2620
|
-
this.
|
|
2658
|
+
this.incrementStatsbeatFailure();
|
|
2621
2659
|
}
|
|
2622
2660
|
return {
|
|
2623
2661
|
code: core.ExportResultCode.FAILED,
|
|
@@ -2630,9 +2668,9 @@ class BaseSender {
|
|
|
2630
2668
|
(restError.statusCode === 307 || // Temporary redirect
|
|
2631
2669
|
restError.statusCode === 308)) {
|
|
2632
2670
|
// Permanent redirect
|
|
2633
|
-
this.
|
|
2671
|
+
this.numConsecutiveRedirects++;
|
|
2634
2672
|
// To prevent circular redirects
|
|
2635
|
-
if (this.
|
|
2673
|
+
if (this.numConsecutiveRedirects < 10) {
|
|
2636
2674
|
if (restError.response && restError.response.headers) {
|
|
2637
2675
|
const location = restError.response.headers.get("location");
|
|
2638
2676
|
if (location) {
|
|
@@ -2644,23 +2682,23 @@ class BaseSender {
|
|
|
2644
2682
|
}
|
|
2645
2683
|
}
|
|
2646
2684
|
else {
|
|
2647
|
-
|
|
2648
|
-
(_f = this.
|
|
2685
|
+
const redirectError = new Error("Circular redirect");
|
|
2686
|
+
(_f = this.networkStatsbeatMetrics) === null || _f === void 0 ? void 0 : _f.countException(redirectError);
|
|
2649
2687
|
return { code: core.ExportResultCode.FAILED, error: redirectError };
|
|
2650
2688
|
}
|
|
2651
2689
|
}
|
|
2652
2690
|
else if (restError.statusCode && isRetriable(restError.statusCode)) {
|
|
2653
|
-
(_g = this.
|
|
2654
|
-
return
|
|
2691
|
+
(_g = this.networkStatsbeatMetrics) === null || _g === void 0 ? void 0 : _g.countRetry(restError.statusCode);
|
|
2692
|
+
return this.persist(envelopes);
|
|
2655
2693
|
}
|
|
2656
|
-
if (this.
|
|
2694
|
+
if (this.isNetworkError(restError)) {
|
|
2657
2695
|
if (restError.statusCode) {
|
|
2658
|
-
(_h = this.
|
|
2696
|
+
(_h = this.networkStatsbeatMetrics) === null || _h === void 0 ? void 0 : _h.countRetry(restError.statusCode);
|
|
2659
2697
|
}
|
|
2660
2698
|
api.diag.error("Retrying due to transient client side error. Error message:", restError.message);
|
|
2661
|
-
return
|
|
2699
|
+
return this.persist(envelopes);
|
|
2662
2700
|
}
|
|
2663
|
-
(_j = this.
|
|
2701
|
+
(_j = this.networkStatsbeatMetrics) === null || _j === void 0 ? void 0 : _j.countException(restError);
|
|
2664
2702
|
api.diag.error("Envelopes could not be exported and are not retriable. Error message:", restError.message);
|
|
2665
2703
|
return { code: core.ExportResultCode.FAILED, error: restError };
|
|
2666
2704
|
}
|
|
@@ -2668,9 +2706,9 @@ class BaseSender {
|
|
|
2668
2706
|
/**
|
|
2669
2707
|
* Persist envelopes to disk
|
|
2670
2708
|
*/
|
|
2671
|
-
async
|
|
2709
|
+
async persist(envelopes) {
|
|
2672
2710
|
try {
|
|
2673
|
-
const success = await this.
|
|
2711
|
+
const success = await this.persister.push(envelopes);
|
|
2674
2712
|
return success
|
|
2675
2713
|
? { code: core.ExportResultCode.SUCCESS }
|
|
2676
2714
|
: {
|
|
@@ -2683,19 +2721,19 @@ class BaseSender {
|
|
|
2683
2721
|
}
|
|
2684
2722
|
}
|
|
2685
2723
|
// Disable collection of statsbeat metrics after max failures
|
|
2686
|
-
|
|
2724
|
+
incrementStatsbeatFailure() {
|
|
2687
2725
|
var _a, _b;
|
|
2688
|
-
this.
|
|
2689
|
-
if (this.
|
|
2690
|
-
(_a = this.
|
|
2691
|
-
(_b = this.
|
|
2692
|
-
this.
|
|
2693
|
-
this.
|
|
2726
|
+
this.statsbeatFailureCount++;
|
|
2727
|
+
if (this.statsbeatFailureCount > MAX_STATSBEAT_FAILURES) {
|
|
2728
|
+
(_a = this.networkStatsbeatMetrics) === null || _a === void 0 ? void 0 : _a.shutdown();
|
|
2729
|
+
(_b = this.longIntervalStatsbeatMetrics) === null || _b === void 0 ? void 0 : _b.shutdown();
|
|
2730
|
+
this.networkStatsbeatMetrics = undefined;
|
|
2731
|
+
this.statsbeatFailureCount = 0;
|
|
2694
2732
|
}
|
|
2695
2733
|
}
|
|
2696
|
-
async
|
|
2734
|
+
async sendFirstPersistedFile() {
|
|
2697
2735
|
try {
|
|
2698
|
-
const envelopes = (await this.
|
|
2736
|
+
const envelopes = (await this.persister.shift());
|
|
2699
2737
|
if (envelopes) {
|
|
2700
2738
|
await this.send(envelopes);
|
|
2701
2739
|
}
|
|
@@ -2704,7 +2742,7 @@ class BaseSender {
|
|
|
2704
2742
|
api.diag.warn(`Failed to fetch persisted file`, err);
|
|
2705
2743
|
}
|
|
2706
2744
|
}
|
|
2707
|
-
|
|
2745
|
+
isNetworkError(error) {
|
|
2708
2746
|
if (error && error.code && error.code === "REQUEST_SEND_ERROR") {
|
|
2709
2747
|
return true;
|
|
2710
2748
|
}
|
|
@@ -2713,23 +2751,30 @@ class BaseSender {
|
|
|
2713
2751
|
}
|
|
2714
2752
|
|
|
2715
2753
|
// Copyright (c) Microsoft Corporation.
|
|
2754
|
+
// Licensed under the MIT license.
|
|
2716
2755
|
const applicationInsightsResource = "https://monitor.azure.com//.default";
|
|
2717
2756
|
/**
|
|
2718
2757
|
* Exporter HTTP sender class
|
|
2719
2758
|
* @internal
|
|
2720
2759
|
*/
|
|
2721
2760
|
class HttpSender extends BaseSender {
|
|
2722
|
-
constructor(
|
|
2723
|
-
super(
|
|
2761
|
+
constructor(options) {
|
|
2762
|
+
super(options);
|
|
2724
2763
|
// Build endpoint using provided configuration or default values
|
|
2725
|
-
this.
|
|
2726
|
-
if (
|
|
2764
|
+
this.appInsightsClientOptions = Object.assign({ host: options.endpointUrl }, options.exporterOptions);
|
|
2765
|
+
if (this.appInsightsClientOptions.credential) {
|
|
2727
2766
|
// Add credentialScopes
|
|
2728
|
-
options.
|
|
2767
|
+
if (options.aadAudience) {
|
|
2768
|
+
this.appInsightsClientOptions.credentialScopes = [options.aadAudience];
|
|
2769
|
+
}
|
|
2770
|
+
else {
|
|
2771
|
+
// Default
|
|
2772
|
+
this.appInsightsClientOptions.credentialScopes = [applicationInsightsResource];
|
|
2773
|
+
}
|
|
2729
2774
|
}
|
|
2730
|
-
this.
|
|
2775
|
+
this.appInsightsClient = new ApplicationInsightsClient(this.appInsightsClientOptions);
|
|
2731
2776
|
// Handle redirects in HTTP Sender
|
|
2732
|
-
this.
|
|
2777
|
+
this.appInsightsClient.pipeline.removePolicy({ name: coreRestPipeline.redirectPolicyName });
|
|
2733
2778
|
}
|
|
2734
2779
|
/**
|
|
2735
2780
|
* Send Azure envelopes
|
|
@@ -2737,21 +2782,16 @@ class HttpSender extends BaseSender {
|
|
|
2737
2782
|
*/
|
|
2738
2783
|
async send(envelopes) {
|
|
2739
2784
|
var _a;
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
options.onResponse(rawResponse, flatResponse);
|
|
2747
|
-
}
|
|
2785
|
+
const options = {};
|
|
2786
|
+
let response;
|
|
2787
|
+
function onResponse(rawResponse, flatResponse) {
|
|
2788
|
+
response = rawResponse;
|
|
2789
|
+
if (options.onResponse) {
|
|
2790
|
+
options.onResponse(rawResponse, flatResponse);
|
|
2748
2791
|
}
|
|
2749
|
-
await this._appInsightsClient.track(envelopes, Object.assign(Object.assign({}, options), { onResponse }));
|
|
2750
|
-
return { statusCode: response === null || response === void 0 ? void 0 : response.status, result: (_a = response === null || response === void 0 ? void 0 : response.bodyAsText) !== null && _a !== void 0 ? _a : "" };
|
|
2751
|
-
}
|
|
2752
|
-
catch (e) {
|
|
2753
|
-
throw e;
|
|
2754
2792
|
}
|
|
2793
|
+
await this.appInsightsClient.track(envelopes, Object.assign(Object.assign({}, options), { onResponse }));
|
|
2794
|
+
return { statusCode: response === null || response === void 0 ? void 0 : response.status, result: (_a = response === null || response === void 0 ? void 0 : response.bodyAsText) !== null && _a !== void 0 ? _a : "" };
|
|
2755
2795
|
}
|
|
2756
2796
|
/**
|
|
2757
2797
|
* Shutdown sender
|
|
@@ -2762,15 +2802,16 @@ class HttpSender extends BaseSender {
|
|
|
2762
2802
|
}
|
|
2763
2803
|
handlePermanentRedirect(location) {
|
|
2764
2804
|
if (location) {
|
|
2765
|
-
const locUrl = new
|
|
2805
|
+
const locUrl = new url.URL(location);
|
|
2766
2806
|
if (locUrl && locUrl.host) {
|
|
2767
|
-
this.
|
|
2807
|
+
this.appInsightsClient.host = "https://" + locUrl.host;
|
|
2768
2808
|
}
|
|
2769
2809
|
}
|
|
2770
2810
|
}
|
|
2771
2811
|
}
|
|
2772
2812
|
|
|
2773
2813
|
// Copyright (c) Microsoft Corporation.
|
|
2814
|
+
// Licensed under the MIT license.
|
|
2774
2815
|
let instance = null;
|
|
2775
2816
|
/**
|
|
2776
2817
|
* Azure Telemetry context.
|
|
@@ -2790,13 +2831,13 @@ class Context {
|
|
|
2790
2831
|
[Context.nodeVersion] = node.split(".");
|
|
2791
2832
|
Context.opentelemetryVersion = core.SDK_INFO[semanticConventions.SemanticResourceAttributes.TELEMETRY_SDK_VERSION];
|
|
2792
2833
|
Context.sdkVersion = packageVersion;
|
|
2793
|
-
|
|
2834
|
+
const prefix = process.env["AZURE_MONITOR_AGENT_PREFIX"]
|
|
2794
2835
|
? process.env["AZURE_MONITOR_AGENT_PREFIX"]
|
|
2795
2836
|
: "";
|
|
2796
|
-
|
|
2837
|
+
const version = process.env["AZURE_MONITOR_DISTRO_VERSION"]
|
|
2797
2838
|
? `dst${process.env["AZURE_MONITOR_DISTRO_VERSION"]}`
|
|
2798
2839
|
: `ext${Context.sdkVersion}`;
|
|
2799
|
-
|
|
2840
|
+
const internalSdkVersion = `${prefix}node${Context.nodeVersion}:otel${Context.opentelemetryVersion}:${version}`;
|
|
2800
2841
|
this.tags[KnownContextTagKeys.AiInternalSdkVersion] = internalSdkVersion;
|
|
2801
2842
|
}
|
|
2802
2843
|
}
|
|
@@ -2815,6 +2856,7 @@ function getInstance() {
|
|
|
2815
2856
|
}
|
|
2816
2857
|
|
|
2817
2858
|
// Copyright (c) Microsoft Corporation.
|
|
2859
|
+
// Licensed under the MIT license.
|
|
2818
2860
|
function createTagsFromResource(resource) {
|
|
2819
2861
|
const context = getInstance();
|
|
2820
2862
|
const tags = Object.assign({}, context.tags);
|
|
@@ -2892,7 +2934,7 @@ function getCloudRoleInstance(resource) {
|
|
|
2892
2934
|
return String(serviceInstanceId);
|
|
2893
2935
|
}
|
|
2894
2936
|
// Default
|
|
2895
|
-
return
|
|
2937
|
+
return os$1 && os$1.hostname();
|
|
2896
2938
|
}
|
|
2897
2939
|
function isSqlDB(dbSystem) {
|
|
2898
2940
|
return (dbSystem === semanticConventions.DbSystemValues.DB2 ||
|
|
@@ -2976,20 +3018,20 @@ function createResourceMetricEnvelope(resource, instrumentationKey) {
|
|
|
2976
3018
|
for (const key of Object.keys(resource.attributes)) {
|
|
2977
3019
|
// Avoid duplication ignoring fields already mapped.
|
|
2978
3020
|
if (!(key.startsWith("_MS.") ||
|
|
2979
|
-
key
|
|
2980
|
-
key
|
|
2981
|
-
key
|
|
3021
|
+
key === semanticConventions.SemanticResourceAttributes.TELEMETRY_SDK_VERSION ||
|
|
3022
|
+
key === semanticConventions.SemanticResourceAttributes.TELEMETRY_SDK_LANGUAGE ||
|
|
3023
|
+
key === semanticConventions.SemanticResourceAttributes.TELEMETRY_SDK_NAME)) {
|
|
2982
3024
|
resourceAttributes[key] = resource.attributes[key];
|
|
2983
3025
|
}
|
|
2984
3026
|
}
|
|
2985
3027
|
// Only send event when resource attributes are available
|
|
2986
3028
|
if (Object.keys(resourceAttributes).length > 0) {
|
|
2987
|
-
|
|
3029
|
+
const baseData = {
|
|
2988
3030
|
version: 2,
|
|
2989
3031
|
metrics: [{ name: "_OTELRESOURCE_", value: 1 }],
|
|
2990
3032
|
properties: resourceAttributes,
|
|
2991
3033
|
};
|
|
2992
|
-
|
|
3034
|
+
const envelope = {
|
|
2993
3035
|
name: "Microsoft.ApplicationInsights.Metric",
|
|
2994
3036
|
time: new Date(),
|
|
2995
3037
|
sampleRate: 100,
|
|
@@ -3026,6 +3068,7 @@ const MicrosoftEventHub = "Microsoft.EventHub";
|
|
|
3026
3068
|
const MessageBusDestination = "message_bus.destination";
|
|
3027
3069
|
|
|
3028
3070
|
// Copyright (c) Microsoft Corporation.
|
|
3071
|
+
// Licensed under the MIT license.
|
|
3029
3072
|
/**
|
|
3030
3073
|
* Average span.links[].attributes.enqueuedTime
|
|
3031
3074
|
*/
|
|
@@ -3072,6 +3115,7 @@ const parseEventHubSpan = (span, baseData) => {
|
|
|
3072
3115
|
};
|
|
3073
3116
|
|
|
3074
3117
|
// Copyright (c) Microsoft Corporation.
|
|
3118
|
+
// Licensed under the MIT license.
|
|
3075
3119
|
function createTagsFromSpan(span) {
|
|
3076
3120
|
const tags = createTagsFromResource(span.resource);
|
|
3077
3121
|
tags[KnownContextTagKeys.AiOperationId] = span.spanContext().traceId;
|
|
@@ -3124,21 +3168,21 @@ function createPropertiesFromSpanAttributes(attributes) {
|
|
|
3124
3168
|
for (const key of Object.keys(attributes)) {
|
|
3125
3169
|
// Avoid duplication ignoring fields already mapped.
|
|
3126
3170
|
if (!(key.startsWith("_MS.") ||
|
|
3127
|
-
key
|
|
3128
|
-
key
|
|
3129
|
-
key
|
|
3130
|
-
key
|
|
3131
|
-
key
|
|
3132
|
-
key
|
|
3133
|
-
key
|
|
3134
|
-
key
|
|
3135
|
-
key
|
|
3136
|
-
key
|
|
3137
|
-
key
|
|
3138
|
-
key
|
|
3139
|
-
key
|
|
3140
|
-
key
|
|
3141
|
-
key
|
|
3171
|
+
key === semanticConventions.SemanticAttributes.NET_PEER_IP ||
|
|
3172
|
+
key === semanticConventions.SemanticAttributes.NET_PEER_NAME ||
|
|
3173
|
+
key === semanticConventions.SemanticAttributes.PEER_SERVICE ||
|
|
3174
|
+
key === semanticConventions.SemanticAttributes.HTTP_METHOD ||
|
|
3175
|
+
key === semanticConventions.SemanticAttributes.HTTP_URL ||
|
|
3176
|
+
key === semanticConventions.SemanticAttributes.HTTP_STATUS_CODE ||
|
|
3177
|
+
key === semanticConventions.SemanticAttributes.HTTP_ROUTE ||
|
|
3178
|
+
key === semanticConventions.SemanticAttributes.HTTP_HOST ||
|
|
3179
|
+
key === semanticConventions.SemanticAttributes.HTTP_URL ||
|
|
3180
|
+
key === semanticConventions.SemanticAttributes.DB_SYSTEM ||
|
|
3181
|
+
key === semanticConventions.SemanticAttributes.DB_STATEMENT ||
|
|
3182
|
+
key === semanticConventions.SemanticAttributes.DB_OPERATION ||
|
|
3183
|
+
key === semanticConventions.SemanticAttributes.DB_NAME ||
|
|
3184
|
+
key === semanticConventions.SemanticAttributes.RPC_SYSTEM ||
|
|
3185
|
+
key === semanticConventions.SemanticAttributes.RPC_GRPC_STATUS_CODE)) {
|
|
3142
3186
|
properties[key] = attributes[key];
|
|
3143
3187
|
}
|
|
3144
3188
|
}
|
|
@@ -3161,7 +3205,7 @@ function createDependencyData(span) {
|
|
|
3161
3205
|
const remoteDependencyData = {
|
|
3162
3206
|
name: span.name,
|
|
3163
3207
|
id: `${span.spanContext().spanId}`,
|
|
3164
|
-
success: span.status.code
|
|
3208
|
+
success: span.status.code !== api.SpanStatusCode.ERROR,
|
|
3165
3209
|
resultCode: "0",
|
|
3166
3210
|
type: "Dependency",
|
|
3167
3211
|
duration: msToTimeSpan(core.hrTimeToMilliseconds(span.duration)),
|
|
@@ -3198,10 +3242,11 @@ function createDependencyData(span) {
|
|
|
3198
3242
|
// Remove default port
|
|
3199
3243
|
const portRegex = new RegExp(/(https?)(:\/\/.*)(:\d+)(\S*)/);
|
|
3200
3244
|
const res = portRegex.exec(target);
|
|
3201
|
-
if (res
|
|
3245
|
+
if (res !== null) {
|
|
3202
3246
|
const protocol = res[1];
|
|
3203
3247
|
const port = res[3];
|
|
3204
|
-
if ((protocol
|
|
3248
|
+
if ((protocol === "https" && port === ":443") ||
|
|
3249
|
+
(protocol === "http" && port === ":80")) {
|
|
3205
3250
|
// Drop port
|
|
3206
3251
|
target = res[1] + res[2] + res[4];
|
|
3207
3252
|
}
|
|
@@ -3269,7 +3314,7 @@ function createDependencyData(span) {
|
|
|
3269
3314
|
function createRequestData(span) {
|
|
3270
3315
|
const requestData = {
|
|
3271
3316
|
id: `${span.spanContext().spanId}`,
|
|
3272
|
-
success: span.status.code
|
|
3317
|
+
success: span.status.code !== api.SpanStatusCode.ERROR,
|
|
3273
3318
|
responseCode: "0",
|
|
3274
3319
|
duration: msToTimeSpan(core.hrTimeToMilliseconds(span.duration)),
|
|
3275
3320
|
version: 2,
|
|
@@ -3369,7 +3414,7 @@ function spanEventsToEnvelopes(span, ikey) {
|
|
|
3369
3414
|
tags[KnownContextTagKeys.AiOperationParentId] = spanId;
|
|
3370
3415
|
}
|
|
3371
3416
|
// Only generate exception telemetry for incoming requests
|
|
3372
|
-
if (event.name
|
|
3417
|
+
if (event.name === "exception" && span.kind === api.SpanKind.SERVER) {
|
|
3373
3418
|
name = "Microsoft.ApplicationInsights.Exception";
|
|
3374
3419
|
baseType = "ExceptionData";
|
|
3375
3420
|
let typeName = "";
|
|
@@ -3387,7 +3432,7 @@ function spanEventsToEnvelopes(span, ikey) {
|
|
|
3387
3432
|
message = String(exceptionMsg);
|
|
3388
3433
|
}
|
|
3389
3434
|
const escaped = event.attributes[semanticConventions.SemanticAttributes.EXCEPTION_ESCAPED];
|
|
3390
|
-
if (escaped
|
|
3435
|
+
if (escaped !== undefined) {
|
|
3391
3436
|
properties[semanticConventions.SemanticAttributes.EXCEPTION_ESCAPED] = String(escaped);
|
|
3392
3437
|
}
|
|
3393
3438
|
}
|
|
@@ -3437,6 +3482,7 @@ function spanEventsToEnvelopes(span, ikey) {
|
|
|
3437
3482
|
}
|
|
3438
3483
|
|
|
3439
3484
|
// Copyright (c) Microsoft Corporation.
|
|
3485
|
+
// Licensed under the MIT license.
|
|
3440
3486
|
/**
|
|
3441
3487
|
* Azure Monitor OpenTelemetry Trace Exporter.
|
|
3442
3488
|
*/
|
|
@@ -3450,8 +3496,14 @@ class AzureMonitorTraceExporter extends AzureMonitorBaseExporter {
|
|
|
3450
3496
|
/**
|
|
3451
3497
|
* Flag to determine if Exporter is shutdown.
|
|
3452
3498
|
*/
|
|
3453
|
-
this.
|
|
3454
|
-
this.
|
|
3499
|
+
this.isShutdown = false;
|
|
3500
|
+
this.sender = new HttpSender({
|
|
3501
|
+
endpointUrl: this.endpointUrl,
|
|
3502
|
+
instrumentationKey: this.instrumentationKey,
|
|
3503
|
+
trackStatsbeat: this.trackStatsbeat,
|
|
3504
|
+
exporterOptions: options,
|
|
3505
|
+
aadAudience: this.aadAudience,
|
|
3506
|
+
});
|
|
3455
3507
|
api.diag.debug("AzureMonitorTraceExporter was successfully setup");
|
|
3456
3508
|
}
|
|
3457
3509
|
/**
|
|
@@ -3460,26 +3512,26 @@ class AzureMonitorTraceExporter extends AzureMonitorBaseExporter {
|
|
|
3460
3512
|
* @param resultCallback - Result callback.
|
|
3461
3513
|
*/
|
|
3462
3514
|
async export(spans, resultCallback) {
|
|
3463
|
-
if (this.
|
|
3515
|
+
if (this.isShutdown) {
|
|
3464
3516
|
api.diag.info("Exporter shut down. Failed to export spans.");
|
|
3465
3517
|
setTimeout(() => resultCallback({ code: core.ExportResultCode.FAILED }), 0);
|
|
3466
3518
|
return;
|
|
3467
3519
|
}
|
|
3468
3520
|
api.diag.info(`Exporting ${spans.length} span(s). Converting to envelopes...`);
|
|
3469
3521
|
if (spans.length > 0) {
|
|
3470
|
-
|
|
3522
|
+
const envelopes = [];
|
|
3471
3523
|
const resourceMetricEnvelope = createResourceMetricEnvelope(spans[0].resource, this.instrumentationKey);
|
|
3472
3524
|
if (resourceMetricEnvelope) {
|
|
3473
3525
|
envelopes.push(resourceMetricEnvelope);
|
|
3474
3526
|
}
|
|
3475
3527
|
spans.forEach((span) => {
|
|
3476
3528
|
envelopes.push(readableSpanToEnvelope(span, this.instrumentationKey));
|
|
3477
|
-
|
|
3529
|
+
const spanEventEnvelopes = spanEventsToEnvelopes(span, this.instrumentationKey);
|
|
3478
3530
|
if (spanEventEnvelopes.length > 0) {
|
|
3479
3531
|
envelopes.push(...spanEventEnvelopes);
|
|
3480
3532
|
}
|
|
3481
3533
|
});
|
|
3482
|
-
resultCallback(await this.
|
|
3534
|
+
resultCallback(await this.sender.exportEnvelopes(envelopes));
|
|
3483
3535
|
}
|
|
3484
3536
|
// No data to export
|
|
3485
3537
|
resultCallback({ code: core.ExportResultCode.SUCCESS });
|
|
@@ -3488,13 +3540,14 @@ class AzureMonitorTraceExporter extends AzureMonitorBaseExporter {
|
|
|
3488
3540
|
* Shutdown AzureMonitorTraceExporter.
|
|
3489
3541
|
*/
|
|
3490
3542
|
async shutdown() {
|
|
3491
|
-
this.
|
|
3543
|
+
this.isShutdown = true;
|
|
3492
3544
|
api.diag.info("AzureMonitorTraceExporter shutting down");
|
|
3493
|
-
return this.
|
|
3545
|
+
return this.sender.shutdown();
|
|
3494
3546
|
}
|
|
3495
3547
|
}
|
|
3496
3548
|
|
|
3497
3549
|
// Copyright (c) Microsoft Corporation.
|
|
3550
|
+
// Licensed under the MIT license.
|
|
3498
3551
|
/**
|
|
3499
3552
|
* Azure Monitor OpenTelemetry Metric Exporter.
|
|
3500
3553
|
*/
|
|
@@ -3509,7 +3562,13 @@ class AzureMonitorMetricExporter extends AzureMonitorBaseExporter {
|
|
|
3509
3562
|
* Flag to determine if Exporter is shutdown.
|
|
3510
3563
|
*/
|
|
3511
3564
|
this._isShutdown = false;
|
|
3512
|
-
this._sender = new HttpSender(
|
|
3565
|
+
this._sender = new HttpSender({
|
|
3566
|
+
endpointUrl: this.endpointUrl,
|
|
3567
|
+
instrumentationKey: this.instrumentationKey,
|
|
3568
|
+
trackStatsbeat: this.trackStatsbeat,
|
|
3569
|
+
exporterOptions: options,
|
|
3570
|
+
aadAudience: this.aadAudience,
|
|
3571
|
+
});
|
|
3513
3572
|
api.diag.debug("AzureMonitorMetricExporter was successfully setup");
|
|
3514
3573
|
}
|
|
3515
3574
|
/**
|
|
@@ -3524,9 +3583,9 @@ class AzureMonitorMetricExporter extends AzureMonitorBaseExporter {
|
|
|
3524
3583
|
return;
|
|
3525
3584
|
}
|
|
3526
3585
|
api.diag.info(`Exporting ${metrics.scopeMetrics.length} metrics(s). Converting to envelopes...`);
|
|
3527
|
-
|
|
3586
|
+
const envelopes = resourceMetricsToEnvelope(metrics, this.instrumentationKey);
|
|
3528
3587
|
// Supress tracing until OpenTelemetry Metrics SDK support it
|
|
3529
|
-
api.context.with(core.suppressTracing(api.context.active()), async () => {
|
|
3588
|
+
await api.context.with(core.suppressTracing(api.context.active()), async () => {
|
|
3530
3589
|
resultCallback(await this._sender.exportEnvelopes(envelopes));
|
|
3531
3590
|
});
|
|
3532
3591
|
}
|
|
@@ -3542,8 +3601,8 @@ class AzureMonitorMetricExporter extends AzureMonitorBaseExporter {
|
|
|
3542
3601
|
* Select aggregation temporality
|
|
3543
3602
|
*/
|
|
3544
3603
|
selectAggregationTemporality(instrumentType) {
|
|
3545
|
-
if (instrumentType
|
|
3546
|
-
instrumentType
|
|
3604
|
+
if (instrumentType === sdkMetrics.InstrumentType.UP_DOWN_COUNTER ||
|
|
3605
|
+
instrumentType === sdkMetrics.InstrumentType.OBSERVABLE_UP_DOWN_COUNTER) {
|
|
3547
3606
|
return sdkMetrics.AggregationTemporality.CUMULATIVE;
|
|
3548
3607
|
}
|
|
3549
3608
|
return sdkMetrics.AggregationTemporality.DELTA;
|
|
@@ -3557,13 +3616,14 @@ class AzureMonitorMetricExporter extends AzureMonitorBaseExporter {
|
|
|
3557
3616
|
}
|
|
3558
3617
|
|
|
3559
3618
|
// Copyright (c) Microsoft Corporation.
|
|
3619
|
+
// Licensed under the MIT license.
|
|
3560
3620
|
/**
|
|
3561
3621
|
* Log to Azure envelope parsing.
|
|
3562
3622
|
* @internal
|
|
3563
3623
|
*/
|
|
3564
3624
|
function logToEnvelope(log, ikey) {
|
|
3565
3625
|
const time = log.hrTime ? new Date(core.hrTimeToMilliseconds(log.hrTime)) : new Date();
|
|
3566
|
-
|
|
3626
|
+
const sampleRate = 100;
|
|
3567
3627
|
const instrumentationKey = ikey;
|
|
3568
3628
|
const tags = createTagsFromLog(log);
|
|
3569
3629
|
const [properties, measurements] = createPropertiesFromLog(log);
|
|
@@ -3572,13 +3632,13 @@ function logToEnvelope(log, ikey) {
|
|
|
3572
3632
|
let baseData;
|
|
3573
3633
|
if (!log.attributes[ApplicationInsightsBaseType]) {
|
|
3574
3634
|
// Get Exception attributes if available
|
|
3575
|
-
|
|
3635
|
+
const exceptionType = log.attributes[semanticConventions.SemanticAttributes.EXCEPTION_TYPE];
|
|
3576
3636
|
if (exceptionType) {
|
|
3577
|
-
|
|
3578
|
-
|
|
3637
|
+
const exceptionMessage = log.attributes[semanticConventions.SemanticAttributes.EXCEPTION_MESSAGE];
|
|
3638
|
+
const exceptionStacktrace = log.attributes[semanticConventions.SemanticAttributes.EXCEPTION_STACKTRACE];
|
|
3579
3639
|
name = ApplicationInsightsExceptionName;
|
|
3580
3640
|
baseType = ApplicationInsightsExceptionBaseType;
|
|
3581
|
-
|
|
3641
|
+
const exceptionDetails = {
|
|
3582
3642
|
typeName: String(exceptionType),
|
|
3583
3643
|
message: String(exceptionMessage),
|
|
3584
3644
|
hasFullStack: exceptionStacktrace ? true : false,
|
|
@@ -3644,9 +3704,9 @@ function createPropertiesFromLog(log) {
|
|
|
3644
3704
|
for (const key of Object.keys(log.attributes)) {
|
|
3645
3705
|
// Avoid duplication ignoring fields already mapped.
|
|
3646
3706
|
if (!(key.startsWith("_MS.") ||
|
|
3647
|
-
key
|
|
3648
|
-
key
|
|
3649
|
-
key
|
|
3707
|
+
key === semanticConventions.SemanticAttributes.EXCEPTION_TYPE ||
|
|
3708
|
+
key === semanticConventions.SemanticAttributes.EXCEPTION_MESSAGE ||
|
|
3709
|
+
key === semanticConventions.SemanticAttributes.EXCEPTION_STACKTRACE)) {
|
|
3650
3710
|
properties[key] = log.attributes[key];
|
|
3651
3711
|
}
|
|
3652
3712
|
}
|
|
@@ -3730,6 +3790,7 @@ function getLegacyApplicationInsightsBaseData(log) {
|
|
|
3730
3790
|
}
|
|
3731
3791
|
|
|
3732
3792
|
// Copyright (c) Microsoft Corporation.
|
|
3793
|
+
// Licensed under the MIT license.
|
|
3733
3794
|
/**
|
|
3734
3795
|
* Azure Monitor OpenTelemetry Log Exporter.
|
|
3735
3796
|
*/
|
|
@@ -3744,7 +3805,13 @@ class AzureMonitorLogExporter extends AzureMonitorBaseExporter {
|
|
|
3744
3805
|
* Flag to determine if Exporter is shutdown.
|
|
3745
3806
|
*/
|
|
3746
3807
|
this._isShutdown = false;
|
|
3747
|
-
this._sender = new HttpSender(
|
|
3808
|
+
this._sender = new HttpSender({
|
|
3809
|
+
endpointUrl: this.endpointUrl,
|
|
3810
|
+
instrumentationKey: this.instrumentationKey,
|
|
3811
|
+
trackStatsbeat: this.trackStatsbeat,
|
|
3812
|
+
exporterOptions: options,
|
|
3813
|
+
aadAudience: this.aadAudience,
|
|
3814
|
+
});
|
|
3748
3815
|
api.diag.debug("AzureMonitorLogExporter was successfully setup");
|
|
3749
3816
|
}
|
|
3750
3817
|
/**
|
|
@@ -3759,15 +3826,15 @@ class AzureMonitorLogExporter extends AzureMonitorBaseExporter {
|
|
|
3759
3826
|
return;
|
|
3760
3827
|
}
|
|
3761
3828
|
api.diag.info(`Exporting ${logs.length} logs(s). Converting to envelopes...`);
|
|
3762
|
-
|
|
3829
|
+
const envelopes = [];
|
|
3763
3830
|
logs.forEach((log) => {
|
|
3764
|
-
|
|
3831
|
+
const envelope = logToEnvelope(log, this.instrumentationKey);
|
|
3765
3832
|
if (envelope) {
|
|
3766
3833
|
envelopes.push(envelope);
|
|
3767
3834
|
}
|
|
3768
3835
|
});
|
|
3769
3836
|
// Supress tracing until OpenTelemetry Logs SDK support it
|
|
3770
|
-
api.context.with(core.suppressTracing(api.context.active()), async () => {
|
|
3837
|
+
await api.context.with(core.suppressTracing(api.context.active()), async () => {
|
|
3771
3838
|
resultCallback(await this._sender.exportEnvelopes(envelopes));
|
|
3772
3839
|
});
|
|
3773
3840
|
}
|