@azure/monitor-opentelemetry-exporter 1.0.0-beta.5 → 1.0.0-beta.8
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 +11 -13
- package/dist/index.js +706 -245
- package/dist-esm/src/Declarations/Constants.js +1 -1
- package/dist-esm/src/Declarations/Constants.js.map +1 -1
- package/dist-esm/src/config.js +2 -4
- package/dist-esm/src/config.js.map +1 -1
- package/dist-esm/src/export/base.js +172 -0
- package/dist-esm/src/export/base.js.map +1 -0
- package/dist-esm/src/export/metric.js +50 -0
- package/dist-esm/src/export/metric.js.map +1 -0
- package/dist-esm/src/export/trace.js +14 -145
- package/dist-esm/src/export/trace.js.map +1 -1
- package/dist-esm/src/generated/applicationInsightsClient.js.map +1 -1
- package/dist-esm/src/generated/applicationInsightsClientContext.js +2 -2
- package/dist-esm/src/generated/applicationInsightsClientContext.js.map +1 -1
- package/dist-esm/src/generated/models/index.js.map +1 -1
- package/dist-esm/src/index.js +2 -0
- package/dist-esm/src/index.js.map +1 -1
- package/dist-esm/src/platform/nodejs/constants.js +1 -1
- package/dist-esm/src/platform/nodejs/constants.js.map +1 -1
- package/dist-esm/src/platform/nodejs/httpSender.js +12 -3
- package/dist-esm/src/platform/nodejs/httpSender.js.map +1 -1
- package/dist-esm/src/platform/nodejs/persist/fileAccessControl.js +171 -0
- package/dist-esm/src/platform/nodejs/persist/fileAccessControl.js.map +1 -0
- package/dist-esm/src/platform/nodejs/persist/fileSystemHelpers.js.map +1 -1
- package/dist-esm/src/platform/nodejs/persist/fileSystemPersist.js +40 -19
- package/dist-esm/src/platform/nodejs/persist/fileSystemPersist.js.map +1 -1
- package/dist-esm/src/utils/breezeUtils.js +5 -4
- package/dist-esm/src/utils/breezeUtils.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/eventhub.js +1 -1
- package/dist-esm/src/utils/eventhub.js.map +1 -1
- package/dist-esm/src/utils/metricUtils.js +53 -0
- package/dist-esm/src/utils/metricUtils.js.map +1 -0
- package/dist-esm/src/utils/resourceUtils.js +35 -0
- package/dist-esm/src/utils/resourceUtils.js.map +1 -0
- package/dist-esm/src/utils/spanUtils.js +118 -49
- package/dist-esm/src/utils/spanUtils.js.map +1 -1
- package/package.json +25 -26
- package/types/monitor-opentelemetry-exporter.d.ts +110 -7
- package/CHANGELOG.md +0 -38
package/dist/index.js
CHANGED
|
@@ -2,22 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
|
-
|
|
7
5
|
var api = require('@opentelemetry/api');
|
|
8
6
|
var core = require('@opentelemetry/core');
|
|
7
|
+
var url = require('url');
|
|
8
|
+
var coreRestPipeline = require('@azure/core-rest-pipeline');
|
|
9
|
+
var coreClient = require('@azure/core-client');
|
|
9
10
|
var fs = require('fs');
|
|
10
11
|
var os = require('os');
|
|
11
|
-
var os__default = _interopDefault(os);
|
|
12
12
|
var path = require('path');
|
|
13
|
+
var child_process = require('child_process');
|
|
13
14
|
var util = require('util');
|
|
14
|
-
var url = require('url');
|
|
15
|
-
var url__default = _interopDefault(url);
|
|
16
|
-
var coreRestPipeline = require('@azure/core-rest-pipeline');
|
|
17
|
-
var coreClient = require('@azure/core-client');
|
|
18
15
|
var semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
16
|
+
var sdkMetricsBase = require('@opentelemetry/sdk-metrics-base');
|
|
17
|
+
|
|
18
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
19
|
+
|
|
20
|
+
function _interopNamespace(e) {
|
|
21
|
+
if (e && e.__esModule) return e;
|
|
22
|
+
var n = Object.create(null);
|
|
23
|
+
if (e) {
|
|
24
|
+
Object.keys(e).forEach(function (k) {
|
|
25
|
+
if (k !== 'default') {
|
|
26
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
27
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () { return e[k]; }
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
n["default"] = e;
|
|
35
|
+
return Object.freeze(n);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var url__default = /*#__PURE__*/_interopDefaultLegacy(url);
|
|
39
|
+
var coreClient__namespace = /*#__PURE__*/_interopNamespace(coreClient);
|
|
40
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
41
|
+
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
42
|
+
var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
|
|
43
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
44
|
+
var child_process__namespace = /*#__PURE__*/_interopNamespace(child_process);
|
|
19
45
|
|
|
20
46
|
// Copyright (c) Microsoft Corporation.
|
|
47
|
+
// Licensed under the MIT license.
|
|
48
|
+
/**
|
|
49
|
+
* Azure service API version.
|
|
50
|
+
*/
|
|
51
|
+
exports.ServiceApiVersion = void 0;
|
|
21
52
|
(function (ServiceApiVersion) {
|
|
22
53
|
/**
|
|
23
54
|
* V2 Version
|
|
@@ -85,7 +116,7 @@ var PerformanceCounter;
|
|
|
85
116
|
* Map a PerformanceCounter/QuickPulseCounter to a QuickPulseCounter. If no mapping exists, mapping is *undefined*
|
|
86
117
|
* @internal
|
|
87
118
|
*/
|
|
88
|
-
|
|
119
|
+
({
|
|
89
120
|
[PerformanceCounter.PROCESSOR_TIME]: QuickPulseCounter.PROCESSOR_TIME,
|
|
90
121
|
[PerformanceCounter.REQUEST_RATE]: QuickPulseCounter.REQUEST_RATE,
|
|
91
122
|
[PerformanceCounter.REQUEST_DURATION]: QuickPulseCounter.REQUEST_DURATION,
|
|
@@ -95,8 +126,8 @@ const PerformanceToQuickPulseCounter = {
|
|
|
95
126
|
[QuickPulseCounter.DEPENDENCY_RATE]: QuickPulseCounter.DEPENDENCY_RATE,
|
|
96
127
|
[QuickPulseCounter.DEPENDENCY_FAILURE_RATE]: QuickPulseCounter.DEPENDENCY_FAILURE_RATE,
|
|
97
128
|
[QuickPulseCounter.DEPENDENCY_DURATION]: QuickPulseCounter.DEPENDENCY_DURATION,
|
|
98
|
-
[QuickPulseCounter.EXCEPTION_RATE]: QuickPulseCounter.EXCEPTION_RATE
|
|
99
|
-
};
|
|
129
|
+
[QuickPulseCounter.EXCEPTION_RATE]: QuickPulseCounter.EXCEPTION_RATE,
|
|
130
|
+
});
|
|
100
131
|
|
|
101
132
|
// Copyright (c) Microsoft Corporation.
|
|
102
133
|
/**
|
|
@@ -163,7 +194,6 @@ class ConnectionStringParser {
|
|
|
163
194
|
ConnectionStringParser.FIELDS_SEPARATOR = ";";
|
|
164
195
|
ConnectionStringParser.FIELD_KEY_VALUE_SEPARATOR = "=";
|
|
165
196
|
|
|
166
|
-
// Copyright (c) Microsoft Corporation.
|
|
167
197
|
const DEFAULT_BATCH_SEND_RETRY_INTERVAL_MS = 60000;
|
|
168
198
|
const DEFAULT_MAX_CONSECUTIVE_FAILURES_BEFORE_WARNING = 10;
|
|
169
199
|
/**
|
|
@@ -175,25 +205,191 @@ const DEFAULT_EXPORTER_CONFIG = {
|
|
|
175
205
|
endpointUrl: DEFAULT_BREEZE_ENDPOINT,
|
|
176
206
|
batchSendRetryIntervalMs: DEFAULT_BATCH_SEND_RETRY_INTERVAL_MS,
|
|
177
207
|
maxConsecutiveFailuresBeforeWarning: DEFAULT_MAX_CONSECUTIVE_FAILURES_BEFORE_WARNING,
|
|
178
|
-
apiVersion: DEFAULT_BREEZE_API_VERSION
|
|
208
|
+
apiVersion: DEFAULT_BREEZE_API_VERSION,
|
|
179
209
|
};
|
|
180
210
|
|
|
181
211
|
// Copyright (c) Microsoft Corporation.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
212
|
+
class FileAccessControl {
|
|
213
|
+
// Check if file access control could be enabled
|
|
214
|
+
static checkFileProtection() {
|
|
215
|
+
if (!FileAccessControl.OS_PROVIDES_FILE_PROTECTION &&
|
|
216
|
+
!FileAccessControl.OS_FILE_PROTECTION_CHECKED) {
|
|
217
|
+
FileAccessControl.OS_FILE_PROTECTION_CHECKED = true;
|
|
218
|
+
// Node's chmod levels do not appropriately restrict file access on Windows
|
|
219
|
+
// Use the built-in command line tool ICACLS on Windows to properly restrict
|
|
220
|
+
// access to the temporary directory used for disk retry mode.
|
|
221
|
+
if (FileAccessControl.USE_ICACLS) {
|
|
222
|
+
// This should be async - but it's currently safer to have this synchronous
|
|
223
|
+
// This guarantees we can immediately fail setDiskRetryMode if we need to
|
|
224
|
+
try {
|
|
225
|
+
FileAccessControl.OS_PROVIDES_FILE_PROTECTION = fs__namespace.existsSync(FileAccessControl.ICACLS_PATH);
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
// Ignore error
|
|
229
|
+
}
|
|
230
|
+
if (!FileAccessControl.OS_PROVIDES_FILE_PROTECTION) {
|
|
231
|
+
api.diag.warn("Could not find ICACLS in expected location! This is necessary to use disk retry mode on Windows.");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// chmod works everywhere else
|
|
236
|
+
FileAccessControl.OS_PROVIDES_FILE_PROTECTION = true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
static async applyACLRules(directory) {
|
|
241
|
+
if (FileAccessControl.USE_ICACLS) {
|
|
242
|
+
if (FileAccessControl.ACLED_DIRECTORIES[directory] === undefined) {
|
|
243
|
+
// Avoid multiple calls race condition by setting ACLED_DIRECTORIES to false for this directory immediately
|
|
244
|
+
// If batches are being failed faster than the processes spawned below return, some data won't be stored to disk
|
|
245
|
+
// This is better than the alternative of potentially infinitely spawned processes
|
|
246
|
+
FileAccessControl.ACLED_DIRECTORIES[directory] = false;
|
|
247
|
+
try {
|
|
248
|
+
// Restrict this directory to only current user and administrator access
|
|
249
|
+
let identity = await this._getACLIdentity();
|
|
250
|
+
await this._runICACLS(this._getACLArguments(directory, identity));
|
|
251
|
+
FileAccessControl.ACLED_DIRECTORIES[directory] = true;
|
|
252
|
+
}
|
|
253
|
+
catch (ex) {
|
|
254
|
+
FileAccessControl.ACLED_DIRECTORIES[directory] = false; // false is used to cache failed (vs undefined which is "not yet tried")
|
|
255
|
+
throw ex;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
if (!FileAccessControl.ACLED_DIRECTORIES[directory]) {
|
|
260
|
+
throw new Error("Setting ACL restrictions did not succeed (cached result)");
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
static applyACLRulesSync(directory) {
|
|
266
|
+
if (FileAccessControl.USE_ICACLS) {
|
|
267
|
+
// For performance, only run ACL rules if we haven't already during this session
|
|
268
|
+
if (FileAccessControl.ACLED_DIRECTORIES[directory] === undefined) {
|
|
269
|
+
this._runICACLSSync(this._getACLArguments(directory, this._getACLIdentitySync()));
|
|
270
|
+
FileAccessControl.ACLED_DIRECTORIES[directory] = true; // If we get here, it succeeded. _runIACLSSync will throw on failures
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
else if (!FileAccessControl.ACLED_DIRECTORIES[directory]) {
|
|
274
|
+
// falsy but not undefined
|
|
275
|
+
throw new Error("Setting ACL restrictions did not succeed (cached result)");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
static _runICACLS(args) {
|
|
280
|
+
return new Promise((resolve, reject) => {
|
|
281
|
+
var aclProc = child_process__namespace.spawn(FileAccessControl.ICACLS_PATH, args, {
|
|
282
|
+
windowsHide: true,
|
|
283
|
+
});
|
|
284
|
+
aclProc.on("error", (e) => reject(e));
|
|
285
|
+
aclProc.on("close", (code) => {
|
|
286
|
+
if (code === 0) {
|
|
287
|
+
resolve();
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
reject(new Error(`Setting ACL restrictions did not succeed (ICACLS returned code ${code})`));
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
static _runICACLSSync(args) {
|
|
296
|
+
// Some very old versions of Node (< 0.11) don't have this
|
|
297
|
+
if (child_process__namespace.spawnSync) {
|
|
298
|
+
var aclProc = child_process__namespace.spawnSync(FileAccessControl.ICACLS_PATH, args, {
|
|
299
|
+
windowsHide: true,
|
|
300
|
+
});
|
|
301
|
+
if (aclProc.error) {
|
|
302
|
+
throw aclProc.error;
|
|
303
|
+
}
|
|
304
|
+
else if (aclProc.status !== 0) {
|
|
305
|
+
throw new Error(`Setting ACL restrictions did not succeed (ICACLS returned code ${aclProc.status})`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
throw new Error("Could not synchronously call ICACLS under current version of Node.js");
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
static _getACLIdentity() {
|
|
313
|
+
return new Promise((resolve, reject) => {
|
|
314
|
+
if (FileAccessControl.ACL_IDENTITY) {
|
|
315
|
+
resolve(FileAccessControl.ACL_IDENTITY);
|
|
316
|
+
}
|
|
317
|
+
var psProc = child_process__namespace.spawn(FileAccessControl.POWERSHELL_PATH, ["-Command", "[System.Security.Principal.WindowsIdentity]::GetCurrent().Name"], {
|
|
318
|
+
windowsHide: true,
|
|
319
|
+
stdio: ["ignore", "pipe", "pipe"], // Needed to prevent hanging on Win 7
|
|
320
|
+
});
|
|
321
|
+
let data = "";
|
|
322
|
+
psProc.stdout.on("data", (d) => (data += d));
|
|
323
|
+
psProc.on("error", (e) => reject(e));
|
|
324
|
+
psProc.on("close", (code) => {
|
|
325
|
+
FileAccessControl.ACL_IDENTITY = data && data.trim();
|
|
326
|
+
if (code === 0) {
|
|
327
|
+
resolve(FileAccessControl.ACL_IDENTITY);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
reject(new Error(`Getting ACL identity did not succeed (PS returned code ${code})`));
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
static _getACLIdentitySync() {
|
|
336
|
+
if (FileAccessControl.ACL_IDENTITY) {
|
|
337
|
+
return FileAccessControl.ACL_IDENTITY;
|
|
338
|
+
}
|
|
339
|
+
// Some very old versions of Node (< 0.11) don't have this
|
|
340
|
+
if (child_process__namespace.spawnSync) {
|
|
341
|
+
var psProc = child_process__namespace.spawnSync(FileAccessControl.POWERSHELL_PATH, ["-Command", "[System.Security.Principal.WindowsIdentity]::GetCurrent().Name"], {
|
|
342
|
+
windowsHide: true,
|
|
343
|
+
stdio: ["ignore", "pipe", "pipe"], // Needed to prevent hanging on Win 7
|
|
344
|
+
});
|
|
345
|
+
if (psProc.error) {
|
|
346
|
+
throw psProc.error;
|
|
347
|
+
}
|
|
348
|
+
else if (psProc.status !== 0) {
|
|
349
|
+
throw new Error(`Getting ACL identity did not succeed (PS returned code ${psProc.status})`);
|
|
350
|
+
}
|
|
351
|
+
FileAccessControl.ACL_IDENTITY = psProc.stdout && psProc.stdout.toString().trim();
|
|
352
|
+
return FileAccessControl.ACL_IDENTITY;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
throw new Error("Could not synchronously get ACL identity under current version of Node.js");
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
static _getACLArguments(directory, identity) {
|
|
359
|
+
return [
|
|
360
|
+
directory,
|
|
361
|
+
"/grant",
|
|
362
|
+
"*S-1-5-32-544:(OI)(CI)F",
|
|
363
|
+
"/grant",
|
|
364
|
+
`${identity}:(OI)(CI)F`,
|
|
365
|
+
"/inheritance:r",
|
|
366
|
+
]; // Remove all inherited permissions
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
FileAccessControl.ICACLS_PATH = `${process.env.systemdrive}/windows/system32/icacls.exe`;
|
|
370
|
+
FileAccessControl.POWERSHELL_PATH = `${process.env.systemdrive}/windows/system32/windowspowershell/v1.0/powershell.exe`;
|
|
371
|
+
FileAccessControl.ACLED_DIRECTORIES = {};
|
|
372
|
+
FileAccessControl.ACL_IDENTITY = null;
|
|
373
|
+
FileAccessControl.OS_FILE_PROTECTION_CHECKED = false;
|
|
374
|
+
FileAccessControl.OS_PROVIDES_FILE_PROTECTION = false;
|
|
375
|
+
FileAccessControl.USE_ICACLS = os__namespace.type() === "Windows_NT";
|
|
376
|
+
|
|
377
|
+
// Copyright (c) Microsoft Corporation.
|
|
378
|
+
const readdirAsync$1 = util.promisify(fs__namespace.readdir);
|
|
379
|
+
const statAsync$1 = util.promisify(fs__namespace.stat);
|
|
380
|
+
const lstatAsync = util.promisify(fs__namespace.lstat);
|
|
381
|
+
const mkdirAsync = util.promisify(fs__namespace.mkdir);
|
|
186
382
|
/**
|
|
187
383
|
* Computes the size (in bytes) of all files in a directory at the root level. Asynchronously.
|
|
188
384
|
* @internal
|
|
189
385
|
*/
|
|
190
386
|
const getShallowDirectorySize = async (directory) => {
|
|
191
387
|
// Get the directory listing
|
|
192
|
-
const files = await readdirAsync(directory);
|
|
388
|
+
const files = await readdirAsync$1(directory);
|
|
193
389
|
let totalSize = 0;
|
|
194
390
|
// Query all file sizes
|
|
195
391
|
for (const file of files) {
|
|
196
|
-
const fileStats = await statAsync(
|
|
392
|
+
const fileStats = await statAsync$1(path__namespace.join(directory, file));
|
|
197
393
|
if (fileStats.isFile()) {
|
|
198
394
|
totalSize += fileStats.size;
|
|
199
395
|
}
|
|
@@ -227,11 +423,11 @@ const confirmDirExists = async (directory) => {
|
|
|
227
423
|
};
|
|
228
424
|
|
|
229
425
|
// Copyright (c) Microsoft Corporation.
|
|
230
|
-
const statAsync
|
|
231
|
-
const readdirAsync
|
|
232
|
-
const readFileAsync = util.promisify(
|
|
233
|
-
const unlinkAsync = util.promisify(
|
|
234
|
-
const writeFileAsync = util.promisify(
|
|
426
|
+
const statAsync = util.promisify(fs__namespace.stat);
|
|
427
|
+
const readdirAsync = util.promisify(fs__namespace.readdir);
|
|
428
|
+
const readFileAsync = util.promisify(fs__namespace.readFile);
|
|
429
|
+
const unlinkAsync = util.promisify(fs__namespace.unlink);
|
|
430
|
+
const writeFileAsync = util.promisify(fs__namespace.writeFile);
|
|
235
431
|
/**
|
|
236
432
|
* File system persist class.
|
|
237
433
|
* @internal
|
|
@@ -241,36 +437,56 @@ class FileSystemPersist {
|
|
|
241
437
|
this.fileRetemptionPeriod = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
242
438
|
this.cleanupTimeOut = 60 * 60 * 1000; // 1 hour
|
|
243
439
|
this.maxBytesOnDisk = 50000000; // ~50MB
|
|
440
|
+
this._tempDirectory = "";
|
|
244
441
|
this._fileCleanupTimer = null;
|
|
245
442
|
this._options = Object.assign(Object.assign({}, DEFAULT_EXPORTER_CONFIG), options);
|
|
246
|
-
|
|
247
|
-
|
|
443
|
+
this._enabled = true;
|
|
444
|
+
FileAccessControl.checkFileProtection();
|
|
445
|
+
if (!FileAccessControl.OS_PROVIDES_FILE_PROTECTION) {
|
|
446
|
+
this._enabled = false;
|
|
447
|
+
api.diag.error("Sufficient file protection capabilities were not detected. Files will not be persisted");
|
|
248
448
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
449
|
+
if (!this._options.instrumentationKey) {
|
|
450
|
+
this._enabled = false;
|
|
451
|
+
api.diag.error(`No instrumentation key was provided to FileSystemPersister. Files will not be persisted`);
|
|
452
|
+
}
|
|
453
|
+
if (this._enabled) {
|
|
454
|
+
this._tempDirectory = path__namespace.join(os__namespace.tmpdir(), FileSystemPersist.TEMPDIR_PREFIX + this._options.instrumentationKey);
|
|
455
|
+
// Starts file cleanup task
|
|
456
|
+
if (!this._fileCleanupTimer) {
|
|
457
|
+
this._fileCleanupTimer = setTimeout(() => {
|
|
458
|
+
this._fileCleanupTask();
|
|
459
|
+
}, this.cleanupTimeOut);
|
|
460
|
+
this._fileCleanupTimer.unref();
|
|
461
|
+
}
|
|
256
462
|
}
|
|
257
463
|
}
|
|
258
464
|
push(value) {
|
|
259
|
-
|
|
260
|
-
|
|
465
|
+
if (this._enabled) {
|
|
466
|
+
api.diag.debug("Pushing value to persistent storage", value.toString());
|
|
467
|
+
return this._storeToDisk(JSON.stringify(value));
|
|
468
|
+
}
|
|
469
|
+
return new Promise((resolve) => {
|
|
470
|
+
resolve(false);
|
|
471
|
+
});
|
|
261
472
|
}
|
|
262
473
|
async shift() {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
474
|
+
if (this._enabled) {
|
|
475
|
+
api.diag.debug("Searching for filesystem persisted files");
|
|
476
|
+
try {
|
|
477
|
+
const buffer = await this._getFirstFileOnDisk();
|
|
478
|
+
if (buffer) {
|
|
479
|
+
return JSON.parse(buffer.toString("utf8"));
|
|
480
|
+
}
|
|
268
481
|
}
|
|
482
|
+
catch (e) {
|
|
483
|
+
api.diag.debug("Failed to read persisted file", e);
|
|
484
|
+
}
|
|
485
|
+
return null;
|
|
269
486
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
487
|
+
return new Promise((resolve) => {
|
|
488
|
+
resolve(null);
|
|
489
|
+
});
|
|
274
490
|
}
|
|
275
491
|
/**
|
|
276
492
|
* Check for temp telemetry files
|
|
@@ -278,16 +494,16 @@ class FileSystemPersist {
|
|
|
278
494
|
*/
|
|
279
495
|
async _getFirstFileOnDisk() {
|
|
280
496
|
try {
|
|
281
|
-
const stats = await statAsync
|
|
497
|
+
const stats = await statAsync(this._tempDirectory);
|
|
282
498
|
if (stats.isDirectory()) {
|
|
283
|
-
const origFiles = await readdirAsync
|
|
284
|
-
const files = origFiles.filter((f) =>
|
|
499
|
+
const origFiles = await readdirAsync(this._tempDirectory);
|
|
500
|
+
const files = origFiles.filter((f) => path__namespace.basename(f).includes(FileSystemPersist.FILENAME_SUFFIX));
|
|
285
501
|
if (files.length === 0) {
|
|
286
502
|
return null;
|
|
287
503
|
}
|
|
288
504
|
else {
|
|
289
505
|
const firstFile = files[0];
|
|
290
|
-
const filePath =
|
|
506
|
+
const filePath = path__namespace.join(this._tempDirectory, firstFile);
|
|
291
507
|
const payload = await readFileAsync(filePath);
|
|
292
508
|
// delete the file first to prevent double sending
|
|
293
509
|
await unlinkAsync(filePath);
|
|
@@ -326,7 +542,7 @@ class FileSystemPersist {
|
|
|
326
542
|
return false;
|
|
327
543
|
}
|
|
328
544
|
const fileName = `${new Date().getTime()}${FileSystemPersist.FILENAME_SUFFIX}`;
|
|
329
|
-
const fileFullPath =
|
|
545
|
+
const fileFullPath = path__namespace.join(this._tempDirectory, fileName);
|
|
330
546
|
// Mode 600 is w/r for creator and no read access for others
|
|
331
547
|
api.diag.info(`saving data to disk at: ${fileFullPath}`);
|
|
332
548
|
try {
|
|
@@ -340,10 +556,10 @@ class FileSystemPersist {
|
|
|
340
556
|
}
|
|
341
557
|
async _fileCleanupTask() {
|
|
342
558
|
try {
|
|
343
|
-
const stats = await statAsync
|
|
559
|
+
const stats = await statAsync(this._tempDirectory);
|
|
344
560
|
if (stats.isDirectory()) {
|
|
345
|
-
const origFiles = await readdirAsync
|
|
346
|
-
const files = origFiles.filter((f) =>
|
|
561
|
+
const origFiles = await readdirAsync(this._tempDirectory);
|
|
562
|
+
const files = origFiles.filter((f) => path__namespace.basename(f).includes(FileSystemPersist.FILENAME_SUFFIX));
|
|
347
563
|
if (files.length === 0) {
|
|
348
564
|
return false;
|
|
349
565
|
}
|
|
@@ -353,7 +569,7 @@ class FileSystemPersist {
|
|
|
353
569
|
const fileCreationDate = new Date(parseInt(file.split(FileSystemPersist.FILENAME_SUFFIX)[0]));
|
|
354
570
|
const expired = new Date(+new Date() - this.fileRetemptionPeriod) > fileCreationDate;
|
|
355
571
|
if (expired) {
|
|
356
|
-
const filePath =
|
|
572
|
+
const filePath = path__namespace.join(this._tempDirectory, file);
|
|
357
573
|
await unlinkAsync(filePath);
|
|
358
574
|
}
|
|
359
575
|
});
|
|
@@ -1356,7 +1572,7 @@ var Mappers = /*#__PURE__*/Object.freeze({
|
|
|
1356
1572
|
* Code generated by Microsoft (R) AutoRest Code Generator.
|
|
1357
1573
|
* Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
1358
1574
|
*/
|
|
1359
|
-
class ApplicationInsightsClientContext extends
|
|
1575
|
+
class ApplicationInsightsClientContext extends coreClient__namespace.ServiceClient {
|
|
1360
1576
|
/**
|
|
1361
1577
|
* Initializes a new instance of the ApplicationInsightsClientContext class.
|
|
1362
1578
|
* @param options The parameter options
|
|
@@ -1369,13 +1585,13 @@ class ApplicationInsightsClientContext extends coreClient.ServiceClient {
|
|
|
1369
1585
|
const defaults = {
|
|
1370
1586
|
requestContentType: "application/json; charset=utf-8"
|
|
1371
1587
|
};
|
|
1372
|
-
const packageDetails = `azsdk-js-monitor-opentelemetry-exporter/1.0.0-beta.
|
|
1588
|
+
const packageDetails = `azsdk-js-monitor-opentelemetry-exporter/1.0.0-beta.7`;
|
|
1373
1589
|
const userAgentPrefix = options.userAgentOptions && options.userAgentOptions.userAgentPrefix
|
|
1374
1590
|
? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}`
|
|
1375
1591
|
: `${packageDetails}`;
|
|
1376
1592
|
const optionsWithDefaults = Object.assign(Object.assign(Object.assign({}, defaults), options), { userAgentOptions: {
|
|
1377
1593
|
userAgentPrefix
|
|
1378
|
-
}, baseUri: options.endpoint || "{Host}/v2" });
|
|
1594
|
+
}, baseUri: options.endpoint || "{Host}/v2.1" });
|
|
1379
1595
|
super(optionsWithDefaults);
|
|
1380
1596
|
// Assigning values to Constant parameters
|
|
1381
1597
|
this.host = options.host || "https://dc.services.visualstudio.com";
|
|
@@ -1407,7 +1623,7 @@ class ApplicationInsightsClient extends ApplicationInsightsClientContext {
|
|
|
1407
1623
|
}
|
|
1408
1624
|
}
|
|
1409
1625
|
// Operation Specifications
|
|
1410
|
-
const serializer =
|
|
1626
|
+
const serializer = coreClient__namespace.createSerializer(Mappers, /* isXml */ false);
|
|
1411
1627
|
const trackOperationSpec = {
|
|
1412
1628
|
path: "/track",
|
|
1413
1629
|
httpMethod: "POST",
|
|
@@ -1447,6 +1663,7 @@ const trackOperationSpec = {
|
|
|
1447
1663
|
};
|
|
1448
1664
|
|
|
1449
1665
|
// Copyright (c) Microsoft Corporation.
|
|
1666
|
+
const applicationInsightsResource = "https://monitor.azure.com//.default";
|
|
1450
1667
|
/**
|
|
1451
1668
|
* Exporter HTTP sender class
|
|
1452
1669
|
* @internal
|
|
@@ -1456,10 +1673,18 @@ class HttpSender {
|
|
|
1456
1673
|
this._exporterOptions = _exporterOptions;
|
|
1457
1674
|
// Build endpoint using provided configuration or default values
|
|
1458
1675
|
this._appInsightsClientOptions = {
|
|
1459
|
-
host: this._exporterOptions.endpointUrl
|
|
1676
|
+
host: this._exporterOptions.endpointUrl,
|
|
1460
1677
|
};
|
|
1461
1678
|
this._appInsightsClient = new ApplicationInsightsClient(Object.assign({}, this._appInsightsClientOptions));
|
|
1679
|
+
// Handle redirects in HTTP Sender
|
|
1462
1680
|
this._appInsightsClient.pipeline.removePolicy({ name: coreRestPipeline.redirectPolicyName });
|
|
1681
|
+
if (this._exporterOptions.aadTokenCredential) {
|
|
1682
|
+
let scopes = [applicationInsightsResource];
|
|
1683
|
+
this._appInsightsClient.pipeline.addPolicy(coreRestPipeline.bearerTokenAuthenticationPolicy({
|
|
1684
|
+
credential: this._exporterOptions.aadTokenCredential,
|
|
1685
|
+
scopes: scopes,
|
|
1686
|
+
}));
|
|
1687
|
+
}
|
|
1463
1688
|
}
|
|
1464
1689
|
/**
|
|
1465
1690
|
* Send Azure envelopes
|
|
@@ -1492,7 +1717,7 @@ class HttpSender {
|
|
|
1492
1717
|
}
|
|
1493
1718
|
handlePermanentRedirect(location) {
|
|
1494
1719
|
if (location) {
|
|
1495
|
-
const locUrl = new url__default.URL(location);
|
|
1720
|
+
const locUrl = new url__default["default"].URL(location);
|
|
1496
1721
|
if (locUrl && locUrl.host) {
|
|
1497
1722
|
this._appInsightsClient.host = "https://" + locUrl.host;
|
|
1498
1723
|
}
|
|
@@ -1521,7 +1746,7 @@ const TIME_SINCE_ENQUEUED = "timeSinceEnqueued";
|
|
|
1521
1746
|
* AzureMonitorTraceExporter version.
|
|
1522
1747
|
* @internal
|
|
1523
1748
|
*/
|
|
1524
|
-
const packageVersion = "1.0.0-beta.
|
|
1749
|
+
const packageVersion = "1.0.0-beta.8";
|
|
1525
1750
|
var DependencyTypes;
|
|
1526
1751
|
(function (DependencyTypes) {
|
|
1527
1752
|
DependencyTypes["InProc"] = "InProc";
|
|
@@ -1544,7 +1769,7 @@ class Context {
|
|
|
1544
1769
|
this._loadInternalContext();
|
|
1545
1770
|
}
|
|
1546
1771
|
_loadDeviceContext() {
|
|
1547
|
-
this.tags[KnownContextTagKeys.AiDeviceOsVersion] =
|
|
1772
|
+
this.tags[KnownContextTagKeys.AiDeviceOsVersion] = os__namespace && `${os__namespace.type()} ${os__namespace.release()}`;
|
|
1548
1773
|
}
|
|
1549
1774
|
_loadInternalContext() {
|
|
1550
1775
|
const { node } = process.versions;
|
|
@@ -1575,12 +1800,13 @@ function getInstance() {
|
|
|
1575
1800
|
* @internal
|
|
1576
1801
|
*/
|
|
1577
1802
|
function isRetriable(statusCode) {
|
|
1578
|
-
return (statusCode === 206 || //
|
|
1803
|
+
return (statusCode === 206 || // Partial Accept
|
|
1804
|
+
statusCode === 401 || // Unauthorized
|
|
1805
|
+
statusCode === 403 || // Forbidden
|
|
1579
1806
|
statusCode === 408 || // Timeout
|
|
1580
|
-
statusCode === 429 || //
|
|
1581
|
-
statusCode === 439 || // Quota
|
|
1807
|
+
statusCode === 429 || // Too many requests
|
|
1582
1808
|
statusCode === 500 || // Server Error
|
|
1583
|
-
statusCode === 503 // Server
|
|
1809
|
+
statusCode === 503 // Server Unavailable
|
|
1584
1810
|
);
|
|
1585
1811
|
}
|
|
1586
1812
|
/**
|
|
@@ -1603,6 +1829,200 @@ function msToTimeSpan(ms) {
|
|
|
1603
1829
|
return `${daysText + hour}:${min}:${sec}`;
|
|
1604
1830
|
}
|
|
1605
1831
|
|
|
1832
|
+
// Copyright (c) Microsoft Corporation.
|
|
1833
|
+
/**
|
|
1834
|
+
* Azure Monitor OpenTelemetry Trace Exporter.
|
|
1835
|
+
*/
|
|
1836
|
+
class AzureMonitorBaseExporter {
|
|
1837
|
+
/**
|
|
1838
|
+
* Initializes a new instance of the AzureMonitorBaseExporter class.
|
|
1839
|
+
* @param AzureExporterConfig - Exporter configuration.
|
|
1840
|
+
*/
|
|
1841
|
+
constructor(options = {}) {
|
|
1842
|
+
var _a, _b, _c, _d;
|
|
1843
|
+
this._numConsecutiveRedirects = 0;
|
|
1844
|
+
const connectionString = options.connectionString || process.env[ENV_CONNECTION_STRING];
|
|
1845
|
+
this._options = Object.assign({}, DEFAULT_EXPORTER_CONFIG);
|
|
1846
|
+
this._options.apiVersion = (_a = options.apiVersion) !== null && _a !== void 0 ? _a : this._options.apiVersion;
|
|
1847
|
+
this._options.aadTokenCredential = options.aadTokenCredential;
|
|
1848
|
+
if (connectionString) {
|
|
1849
|
+
const parsedConnectionString = ConnectionStringParser.parse(connectionString);
|
|
1850
|
+
this._options.instrumentationKey =
|
|
1851
|
+
(_b = parsedConnectionString.instrumentationkey) !== null && _b !== void 0 ? _b : this._options.instrumentationKey;
|
|
1852
|
+
this._options.endpointUrl =
|
|
1853
|
+
(_d = (_c = parsedConnectionString.ingestionendpoint) === null || _c === void 0 ? void 0 : _c.trim()) !== null && _d !== void 0 ? _d : this._options.endpointUrl;
|
|
1854
|
+
}
|
|
1855
|
+
// Instrumentation key is required
|
|
1856
|
+
if (!this._options.instrumentationKey) {
|
|
1857
|
+
const message = "No instrumentation key or connection string was provided to the Azure Monitor Exporter";
|
|
1858
|
+
api.diag.error(message);
|
|
1859
|
+
throw new Error(message);
|
|
1860
|
+
}
|
|
1861
|
+
this._instrumentationKey = this._options.instrumentationKey;
|
|
1862
|
+
this._sender = new HttpSender(this._options);
|
|
1863
|
+
this._persister = new FileSystemPersist(this._options);
|
|
1864
|
+
this._retryTimer = null;
|
|
1865
|
+
api.diag.debug("AzureMonitorTraceExporter was successfully setup");
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* Persist envelopes to disk
|
|
1869
|
+
*/
|
|
1870
|
+
async _persist(envelopes) {
|
|
1871
|
+
try {
|
|
1872
|
+
const success = await this._persister.push(envelopes);
|
|
1873
|
+
return success
|
|
1874
|
+
? { code: core.ExportResultCode.SUCCESS }
|
|
1875
|
+
: {
|
|
1876
|
+
code: core.ExportResultCode.FAILED,
|
|
1877
|
+
error: new Error("Failed to persist envelope in disk."),
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
catch (ex) {
|
|
1881
|
+
return { code: core.ExportResultCode.FAILED, error: ex };
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
/**
|
|
1885
|
+
* Shutdown exporter
|
|
1886
|
+
*/
|
|
1887
|
+
async _shutdown() {
|
|
1888
|
+
return this._sender.shutdown();
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* Export envelopes
|
|
1892
|
+
*/
|
|
1893
|
+
async _exportEnvelopes(envelopes) {
|
|
1894
|
+
api.diag.info(`Exporting ${envelopes.length} envelope(s)`);
|
|
1895
|
+
try {
|
|
1896
|
+
const { result, statusCode } = await this._sender.send(envelopes);
|
|
1897
|
+
this._numConsecutiveRedirects = 0;
|
|
1898
|
+
if (statusCode === 200) {
|
|
1899
|
+
// Success -- @todo: start retry timer
|
|
1900
|
+
if (!this._retryTimer) {
|
|
1901
|
+
this._retryTimer = setTimeout(() => {
|
|
1902
|
+
this._retryTimer = null;
|
|
1903
|
+
this._sendFirstPersistedFile();
|
|
1904
|
+
}, this._options.batchSendRetryIntervalMs);
|
|
1905
|
+
this._retryTimer.unref();
|
|
1906
|
+
}
|
|
1907
|
+
return { code: core.ExportResultCode.SUCCESS };
|
|
1908
|
+
}
|
|
1909
|
+
else if (statusCode && isRetriable(statusCode)) {
|
|
1910
|
+
// Failed -- persist failed data
|
|
1911
|
+
if (result) {
|
|
1912
|
+
api.diag.info(result);
|
|
1913
|
+
const breezeResponse = JSON.parse(result);
|
|
1914
|
+
const filteredEnvelopes = [];
|
|
1915
|
+
if (breezeResponse.errors) {
|
|
1916
|
+
breezeResponse.errors.forEach((error) => {
|
|
1917
|
+
if (error.statusCode && isRetriable(error.statusCode)) {
|
|
1918
|
+
filteredEnvelopes.push(envelopes[error.index]);
|
|
1919
|
+
}
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
if (filteredEnvelopes.length > 0) {
|
|
1923
|
+
// calls resultCallback(ExportResult) based on result of persister.push
|
|
1924
|
+
return await this._persist(filteredEnvelopes);
|
|
1925
|
+
}
|
|
1926
|
+
// Failed -- not retriable
|
|
1927
|
+
return {
|
|
1928
|
+
code: core.ExportResultCode.FAILED,
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
else {
|
|
1932
|
+
// calls resultCallback(ExportResult) based on result of persister.push
|
|
1933
|
+
return await this._persist(envelopes);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
// Failed -- not retriable
|
|
1938
|
+
return {
|
|
1939
|
+
code: core.ExportResultCode.FAILED,
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
catch (error) {
|
|
1944
|
+
const restError = error;
|
|
1945
|
+
if (restError.statusCode &&
|
|
1946
|
+
(restError.statusCode === 307 || // Temporary redirect
|
|
1947
|
+
restError.statusCode === 308)) {
|
|
1948
|
+
// Permanent redirect
|
|
1949
|
+
this._numConsecutiveRedirects++;
|
|
1950
|
+
// To prevent circular redirects
|
|
1951
|
+
if (this._numConsecutiveRedirects < 10) {
|
|
1952
|
+
if (restError.response && restError.response.headers) {
|
|
1953
|
+
const location = restError.response.headers.get("location");
|
|
1954
|
+
if (location) {
|
|
1955
|
+
// Update sender URL
|
|
1956
|
+
this._sender.handlePermanentRedirect(location);
|
|
1957
|
+
// Send to redirect endpoint as HTTPs library doesn't handle redirect automatically
|
|
1958
|
+
return this._exportEnvelopes(envelopes);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
else {
|
|
1963
|
+
return { code: core.ExportResultCode.FAILED, error: new Error("Circular redirect") };
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
else if (restError.statusCode && isRetriable(restError.statusCode)) {
|
|
1967
|
+
return await this._persist(envelopes);
|
|
1968
|
+
}
|
|
1969
|
+
if (this._isNetworkError(restError)) {
|
|
1970
|
+
api.diag.error("Retrying due to transient client side error. Error message:", restError.message);
|
|
1971
|
+
return await this._persist(envelopes);
|
|
1972
|
+
}
|
|
1973
|
+
api.diag.error("Envelopes could not be exported and are not retriable. Error message:", restError.message);
|
|
1974
|
+
return { code: core.ExportResultCode.FAILED, error: restError };
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
async _sendFirstPersistedFile() {
|
|
1978
|
+
try {
|
|
1979
|
+
const envelopes = (await this._persister.shift());
|
|
1980
|
+
if (envelopes) {
|
|
1981
|
+
await this._sender.send(envelopes);
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
catch (err) {
|
|
1985
|
+
api.diag.warn(`Failed to fetch persisted file`, err);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
_isNetworkError(error) {
|
|
1989
|
+
if (error && error.code && error.code === "REQUEST_SEND_ERROR") {
|
|
1990
|
+
return true;
|
|
1991
|
+
}
|
|
1992
|
+
return false;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
// Copyright (c) Microsoft Corporation.
|
|
1997
|
+
function createTagsFromResource(resource) {
|
|
1998
|
+
const context = getInstance();
|
|
1999
|
+
const tags = Object.assign({}, context.tags);
|
|
2000
|
+
if (resource && resource.attributes) {
|
|
2001
|
+
const serviceName = resource.attributes[semanticConventions.SemanticResourceAttributes.SERVICE_NAME];
|
|
2002
|
+
const serviceNamespace = resource.attributes[semanticConventions.SemanticResourceAttributes.SERVICE_NAMESPACE];
|
|
2003
|
+
if (serviceName) {
|
|
2004
|
+
if (serviceNamespace) {
|
|
2005
|
+
tags[KnownContextTagKeys.AiCloudRole] = `${serviceNamespace}.${serviceName}`;
|
|
2006
|
+
}
|
|
2007
|
+
else {
|
|
2008
|
+
tags[KnownContextTagKeys.AiCloudRole] = String(serviceName);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
const serviceInstanceId = resource.attributes[semanticConventions.SemanticResourceAttributes.SERVICE_INSTANCE_ID];
|
|
2012
|
+
if (serviceInstanceId) {
|
|
2013
|
+
tags[KnownContextTagKeys.AiCloudRoleInstance] = String(serviceInstanceId);
|
|
2014
|
+
}
|
|
2015
|
+
else {
|
|
2016
|
+
tags[KnownContextTagKeys.AiCloudRoleInstance] = os__default["default"] && os__default["default"].hostname();
|
|
2017
|
+
}
|
|
2018
|
+
const endUserId = resource.attributes[semanticConventions.SemanticAttributes.ENDUSER_ID];
|
|
2019
|
+
if (endUserId) {
|
|
2020
|
+
tags[KnownContextTagKeys.AiUserId] = String(endUserId);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
return tags;
|
|
2024
|
+
}
|
|
2025
|
+
|
|
1606
2026
|
// Copyright (c) Microsoft Corporation.
|
|
1607
2027
|
// Licensed under the MIT license.
|
|
1608
2028
|
/**
|
|
@@ -1668,36 +2088,21 @@ const parseEventHubSpan = (span, baseData) => {
|
|
|
1668
2088
|
};
|
|
1669
2089
|
|
|
1670
2090
|
// Copyright (c) Microsoft Corporation.
|
|
1671
|
-
function
|
|
1672
|
-
const
|
|
1673
|
-
const tags = Object.assign({}, context.tags);
|
|
2091
|
+
function createGenericTagsFromSpan(span) {
|
|
2092
|
+
const tags = createTagsFromResource(span.resource);
|
|
1674
2093
|
tags[KnownContextTagKeys.AiOperationId] = span.spanContext().traceId;
|
|
1675
2094
|
if (span.parentSpanId) {
|
|
1676
2095
|
tags[KnownContextTagKeys.AiOperationParentId] = span.parentSpanId;
|
|
1677
2096
|
}
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
if (serviceNamespace) {
|
|
1683
|
-
tags[KnownContextTagKeys.AiCloudRole] = `${serviceNamespace}.${serviceName}`;
|
|
1684
|
-
}
|
|
1685
|
-
else {
|
|
1686
|
-
tags[KnownContextTagKeys.AiCloudRole] = String(serviceName);
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1689
|
-
const serviceInstanceId = span.resource.attributes[semanticConventions.SemanticResourceAttributes.SERVICE_INSTANCE_ID];
|
|
1690
|
-
if (serviceInstanceId) {
|
|
1691
|
-
tags[KnownContextTagKeys.AiCloudRoleInstance] = String(serviceInstanceId);
|
|
1692
|
-
}
|
|
1693
|
-
else {
|
|
1694
|
-
tags[KnownContextTagKeys.AiCloudRoleInstance] = os__default && os__default.hostname();
|
|
1695
|
-
}
|
|
1696
|
-
const endUserId = span.resource.attributes[semanticConventions.SemanticAttributes.ENDUSER_ID];
|
|
1697
|
-
if (endUserId) {
|
|
1698
|
-
tags[KnownContextTagKeys.AiUserId] = String(endUserId);
|
|
1699
|
-
}
|
|
2097
|
+
const httpUserAgent = span.attributes[semanticConventions.SemanticAttributes.HTTP_USER_AGENT];
|
|
2098
|
+
if (httpUserAgent) {
|
|
2099
|
+
// TODO: Not exposed in Swagger, need to update def
|
|
2100
|
+
tags["ai.user.userAgent"] = String(httpUserAgent);
|
|
1700
2101
|
}
|
|
2102
|
+
return tags;
|
|
2103
|
+
}
|
|
2104
|
+
function createTagsFromSpan(span) {
|
|
2105
|
+
const tags = createGenericTagsFromSpan(span);
|
|
1701
2106
|
if (span.kind === api.SpanKind.SERVER) {
|
|
1702
2107
|
const httpMethod = span.attributes[semanticConventions.SemanticAttributes.HTTP_METHOD];
|
|
1703
2108
|
const httpClientIp = span.attributes[semanticConventions.SemanticAttributes.HTTP_CLIENT_IP];
|
|
@@ -1731,28 +2136,36 @@ function createTagsFromSpan(span) {
|
|
|
1731
2136
|
}
|
|
1732
2137
|
}
|
|
1733
2138
|
// TODO: Operation Name and Location IP TBD for non server spans
|
|
1734
|
-
const httpUserAgent = span.attributes[semanticConventions.SemanticAttributes.HTTP_USER_AGENT];
|
|
1735
|
-
if (httpUserAgent) {
|
|
1736
|
-
// TODO: Not exposed in Swagger, need to update def
|
|
1737
|
-
tags["ai.user.userAgent"] = String(httpUserAgent);
|
|
1738
|
-
}
|
|
1739
2139
|
return tags;
|
|
1740
2140
|
}
|
|
1741
|
-
function
|
|
2141
|
+
function createPropertiesFromSpanAttributes(attributes) {
|
|
1742
2142
|
const properties = {};
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
2143
|
+
if (attributes) {
|
|
2144
|
+
for (const key of Object.keys(attributes)) {
|
|
2145
|
+
if (!(key.startsWith("http.") ||
|
|
2146
|
+
key.startsWith("rpc.") ||
|
|
2147
|
+
key.startsWith("db.") ||
|
|
2148
|
+
key.startsWith("peer.") ||
|
|
2149
|
+
key.startsWith("message.") ||
|
|
2150
|
+
key.startsWith("messaging.") ||
|
|
2151
|
+
key.startsWith("enduser.") ||
|
|
2152
|
+
key.startsWith("net.") ||
|
|
2153
|
+
key.startsWith("exception.") ||
|
|
2154
|
+
key.startsWith("thread.") ||
|
|
2155
|
+
key.startsWith("faas.") ||
|
|
2156
|
+
key.startsWith("code."))) {
|
|
2157
|
+
properties[key] = attributes[key];
|
|
2158
|
+
}
|
|
1751
2159
|
}
|
|
1752
2160
|
}
|
|
2161
|
+
return properties;
|
|
2162
|
+
}
|
|
2163
|
+
function createPropertiesFromSpan(span) {
|
|
2164
|
+
const properties = createPropertiesFromSpanAttributes(span.attributes);
|
|
2165
|
+
const measurements = {};
|
|
1753
2166
|
const links = span.links.map((link) => ({
|
|
1754
2167
|
operation_Id: link.context.traceId,
|
|
1755
|
-
id: link.context.spanId
|
|
2168
|
+
id: link.context.spanId,
|
|
1756
2169
|
}));
|
|
1757
2170
|
if (links.length > 0) {
|
|
1758
2171
|
properties[MS_LINKS] = JSON.stringify(links);
|
|
@@ -1836,7 +2249,7 @@ function createDependencyData(span) {
|
|
|
1836
2249
|
resultCode: "0",
|
|
1837
2250
|
type: "Dependency",
|
|
1838
2251
|
duration: msToTimeSpan(core.hrTimeToMilliseconds(span.duration)),
|
|
1839
|
-
version: 2
|
|
2252
|
+
version: 2,
|
|
1840
2253
|
};
|
|
1841
2254
|
if (span.kind === api.SpanKind.PRODUCER) {
|
|
1842
2255
|
remoteDependencyData.type = DependencyTypes.QueueMessage;
|
|
@@ -1878,7 +2291,7 @@ function createDependencyData(span) {
|
|
|
1878
2291
|
}
|
|
1879
2292
|
}
|
|
1880
2293
|
}
|
|
1881
|
-
catch (
|
|
2294
|
+
catch (ex) { }
|
|
1882
2295
|
remoteDependencyData.target = `${target}`;
|
|
1883
2296
|
}
|
|
1884
2297
|
}
|
|
@@ -1944,7 +2357,7 @@ function createRequestData(span) {
|
|
|
1944
2357
|
responseCode: "0",
|
|
1945
2358
|
duration: msToTimeSpan(core.hrTimeToMilliseconds(span.duration)),
|
|
1946
2359
|
version: 2,
|
|
1947
|
-
source: undefined
|
|
2360
|
+
source: undefined,
|
|
1948
2361
|
};
|
|
1949
2362
|
const httpMethod = span.attributes[semanticConventions.SemanticAttributes.HTTP_METHOD];
|
|
1950
2363
|
const grpcStatusCode = span.attributes[semanticConventions.SemanticAttributes.RPC_GRPC_STATUS_CODE];
|
|
@@ -2012,140 +2425,101 @@ function readableSpanToEnvelope(span, ikey) {
|
|
|
2012
2425
|
data: {
|
|
2013
2426
|
baseType,
|
|
2014
2427
|
baseData: Object.assign(Object.assign({}, baseData), { properties,
|
|
2015
|
-
measurements })
|
|
2016
|
-
}
|
|
2428
|
+
measurements }),
|
|
2429
|
+
},
|
|
2017
2430
|
};
|
|
2018
2431
|
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Span Events to Azure envelopes parsing.
|
|
2434
|
+
* @internal
|
|
2435
|
+
*/
|
|
2436
|
+
function spanEventsToEnvelopes(span, ikey) {
|
|
2437
|
+
let envelopes = [];
|
|
2438
|
+
if (span.events) {
|
|
2439
|
+
span.events.forEach((event) => {
|
|
2440
|
+
let baseType;
|
|
2441
|
+
const sampleRate = 100;
|
|
2442
|
+
let time = new Date(core.hrTimeToMilliseconds(event.time));
|
|
2443
|
+
let name = "";
|
|
2444
|
+
let baseData;
|
|
2445
|
+
const properties = createPropertiesFromSpanAttributes(event.attributes);
|
|
2446
|
+
const tags = createGenericTagsFromSpan(span);
|
|
2447
|
+
if (event.name == "exception") {
|
|
2448
|
+
name = "Microsoft.ApplicationInsights.Exception";
|
|
2449
|
+
baseType = "ExceptionData";
|
|
2450
|
+
let typeName = "";
|
|
2451
|
+
let message = "Exception";
|
|
2452
|
+
let stack = "";
|
|
2453
|
+
let hasFullStack = false;
|
|
2454
|
+
if (event.attributes) {
|
|
2455
|
+
typeName = String(event.attributes[semanticConventions.SemanticAttributes.EXCEPTION_TYPE]);
|
|
2456
|
+
stack = String(event.attributes[semanticConventions.SemanticAttributes.EXCEPTION_STACKTRACE]);
|
|
2457
|
+
if (stack) {
|
|
2458
|
+
hasFullStack = true;
|
|
2459
|
+
}
|
|
2460
|
+
let exceptionMsg = event.attributes[semanticConventions.SemanticAttributes.EXCEPTION_MESSAGE];
|
|
2461
|
+
if (exceptionMsg) {
|
|
2462
|
+
message = String(exceptionMsg);
|
|
2463
|
+
}
|
|
2464
|
+
let escaped = event.attributes[semanticConventions.SemanticAttributes.EXCEPTION_ESCAPED];
|
|
2465
|
+
if (escaped != undefined) {
|
|
2466
|
+
properties[semanticConventions.SemanticAttributes.EXCEPTION_ESCAPED] = String(escaped);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
let exceptionDetails = {
|
|
2470
|
+
typeName: typeName,
|
|
2471
|
+
message: message,
|
|
2472
|
+
stack: stack,
|
|
2473
|
+
hasFullStack: hasFullStack,
|
|
2474
|
+
};
|
|
2475
|
+
let exceptionData = {
|
|
2476
|
+
exceptions: [exceptionDetails],
|
|
2477
|
+
version: 2,
|
|
2478
|
+
properties: properties,
|
|
2479
|
+
};
|
|
2480
|
+
baseData = exceptionData;
|
|
2481
|
+
}
|
|
2482
|
+
else {
|
|
2483
|
+
name = "Microsoft.ApplicationInsights.Message";
|
|
2484
|
+
baseType = "MessageData";
|
|
2485
|
+
let messageData = {
|
|
2486
|
+
message: event.name,
|
|
2487
|
+
version: 2,
|
|
2488
|
+
properties: properties,
|
|
2489
|
+
};
|
|
2490
|
+
baseData = messageData;
|
|
2491
|
+
}
|
|
2492
|
+
let env = {
|
|
2493
|
+
name: name,
|
|
2494
|
+
time: time,
|
|
2495
|
+
instrumentationKey: ikey,
|
|
2496
|
+
version: 1,
|
|
2497
|
+
sampleRate: sampleRate,
|
|
2498
|
+
data: {
|
|
2499
|
+
baseType: baseType,
|
|
2500
|
+
baseData: baseData,
|
|
2501
|
+
},
|
|
2502
|
+
tags: tags,
|
|
2503
|
+
};
|
|
2504
|
+
envelopes.push(env);
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
return envelopes;
|
|
2508
|
+
}
|
|
2019
2509
|
|
|
2020
2510
|
// Copyright (c) Microsoft Corporation.
|
|
2021
2511
|
/**
|
|
2022
2512
|
* Azure Monitor OpenTelemetry Trace Exporter.
|
|
2023
2513
|
*/
|
|
2024
|
-
class AzureMonitorTraceExporter {
|
|
2514
|
+
class AzureMonitorTraceExporter extends AzureMonitorBaseExporter {
|
|
2025
2515
|
/**
|
|
2026
2516
|
* Initializes a new instance of the AzureMonitorTraceExporter class.
|
|
2027
2517
|
* @param AzureExporterConfig - Exporter configuration.
|
|
2028
2518
|
*/
|
|
2029
2519
|
constructor(options = {}) {
|
|
2030
|
-
|
|
2031
|
-
this._numConsecutiveRedirects = 0;
|
|
2032
|
-
const connectionString = options.connectionString || process.env[ENV_CONNECTION_STRING];
|
|
2033
|
-
this._options = Object.assign({}, DEFAULT_EXPORTER_CONFIG);
|
|
2034
|
-
this._options.apiVersion = (_a = options.apiVersion) !== null && _a !== void 0 ? _a : this._options.apiVersion;
|
|
2035
|
-
if (connectionString) {
|
|
2036
|
-
const parsedConnectionString = ConnectionStringParser.parse(connectionString);
|
|
2037
|
-
this._options.instrumentationKey =
|
|
2038
|
-
(_b = parsedConnectionString.instrumentationkey) !== null && _b !== void 0 ? _b : this._options.instrumentationKey;
|
|
2039
|
-
this._options.endpointUrl =
|
|
2040
|
-
(_d = (_c = parsedConnectionString.ingestionendpoint) === null || _c === void 0 ? void 0 : _c.trim()) !== null && _d !== void 0 ? _d : this._options.endpointUrl;
|
|
2041
|
-
}
|
|
2042
|
-
// Instrumentation key is required
|
|
2043
|
-
if (!this._options.instrumentationKey) {
|
|
2044
|
-
const message = "No instrumentation key or connection string was provided to the Azure Monitor Exporter";
|
|
2045
|
-
api.diag.error(message);
|
|
2046
|
-
throw new Error(message);
|
|
2047
|
-
}
|
|
2048
|
-
this._sender = new HttpSender(this._options);
|
|
2049
|
-
this._persister = new FileSystemPersist(this._options);
|
|
2050
|
-
this._retryTimer = null;
|
|
2520
|
+
super(options);
|
|
2051
2521
|
api.diag.debug("AzureMonitorTraceExporter was successfully setup");
|
|
2052
2522
|
}
|
|
2053
|
-
async _persist(envelopes) {
|
|
2054
|
-
try {
|
|
2055
|
-
const success = await this._persister.push(envelopes);
|
|
2056
|
-
return success
|
|
2057
|
-
? { code: core.ExportResultCode.SUCCESS }
|
|
2058
|
-
: {
|
|
2059
|
-
code: core.ExportResultCode.FAILED,
|
|
2060
|
-
error: new Error("Failed to persist envelope in disk.")
|
|
2061
|
-
};
|
|
2062
|
-
}
|
|
2063
|
-
catch (ex) {
|
|
2064
|
-
return { code: core.ExportResultCode.FAILED, error: ex };
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
async exportEnvelopes(envelopes) {
|
|
2068
|
-
api.diag.info(`Exporting ${envelopes.length} envelope(s)`);
|
|
2069
|
-
try {
|
|
2070
|
-
const { result, statusCode } = await this._sender.send(envelopes);
|
|
2071
|
-
this._numConsecutiveRedirects = 0;
|
|
2072
|
-
if (statusCode === 200) {
|
|
2073
|
-
// Success -- @todo: start retry timer
|
|
2074
|
-
if (!this._retryTimer) {
|
|
2075
|
-
this._retryTimer = setTimeout(() => {
|
|
2076
|
-
this._retryTimer = null;
|
|
2077
|
-
this._sendFirstPersistedFile();
|
|
2078
|
-
}, this._options.batchSendRetryIntervalMs);
|
|
2079
|
-
this._retryTimer.unref();
|
|
2080
|
-
}
|
|
2081
|
-
return { code: core.ExportResultCode.SUCCESS };
|
|
2082
|
-
}
|
|
2083
|
-
else if (statusCode && isRetriable(statusCode)) {
|
|
2084
|
-
// Failed -- persist failed data
|
|
2085
|
-
if (result) {
|
|
2086
|
-
api.diag.info(result);
|
|
2087
|
-
const breezeResponse = JSON.parse(result);
|
|
2088
|
-
const filteredEnvelopes = [];
|
|
2089
|
-
breezeResponse.errors.forEach((error) => {
|
|
2090
|
-
if (error.statusCode && isRetriable(error.statusCode)) {
|
|
2091
|
-
filteredEnvelopes.push(envelopes[error.index]);
|
|
2092
|
-
}
|
|
2093
|
-
});
|
|
2094
|
-
if (filteredEnvelopes.length > 0) {
|
|
2095
|
-
// calls resultCallback(ExportResult) based on result of persister.push
|
|
2096
|
-
return await this._persist(filteredEnvelopes);
|
|
2097
|
-
}
|
|
2098
|
-
// Failed -- not retriable
|
|
2099
|
-
return {
|
|
2100
|
-
code: core.ExportResultCode.FAILED
|
|
2101
|
-
};
|
|
2102
|
-
}
|
|
2103
|
-
else {
|
|
2104
|
-
// calls resultCallback(ExportResult) based on result of persister.push
|
|
2105
|
-
return await this._persist(envelopes);
|
|
2106
|
-
}
|
|
2107
|
-
}
|
|
2108
|
-
else {
|
|
2109
|
-
// Failed -- not retriable
|
|
2110
|
-
return {
|
|
2111
|
-
code: core.ExportResultCode.FAILED
|
|
2112
|
-
};
|
|
2113
|
-
}
|
|
2114
|
-
}
|
|
2115
|
-
catch (error) {
|
|
2116
|
-
const restError = error;
|
|
2117
|
-
if (restError.statusCode &&
|
|
2118
|
-
(restError.statusCode === 307 || // Temporary redirect
|
|
2119
|
-
restError.statusCode === 308)) {
|
|
2120
|
-
// Permanent redirect
|
|
2121
|
-
this._numConsecutiveRedirects++;
|
|
2122
|
-
// To prevent circular redirects
|
|
2123
|
-
if (this._numConsecutiveRedirects < 10) {
|
|
2124
|
-
if (restError.response && restError.response.headers) {
|
|
2125
|
-
const location = restError.response.headers.get("location");
|
|
2126
|
-
if (location) {
|
|
2127
|
-
// Update sender URL
|
|
2128
|
-
this._sender.handlePermanentRedirect(location);
|
|
2129
|
-
// Send to redirect endpoint as HTTPs library doesn't handle redirect automatically
|
|
2130
|
-
return this.exportEnvelopes(envelopes);
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
}
|
|
2134
|
-
else {
|
|
2135
|
-
return { code: core.ExportResultCode.FAILED, error: new Error("Circular redirect") };
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
else if (restError.statusCode && isRetriable(restError.statusCode)) {
|
|
2139
|
-
return await this._persist(envelopes);
|
|
2140
|
-
}
|
|
2141
|
-
if (this._isNetworkError(restError)) {
|
|
2142
|
-
api.diag.error("Retrying due to transient client side error. Error message:", restError.message);
|
|
2143
|
-
return await this._persist(envelopes);
|
|
2144
|
-
}
|
|
2145
|
-
api.diag.error("Envelopes could not be exported and are not retriable. Error message:", restError.message);
|
|
2146
|
-
return { code: core.ExportResultCode.FAILED, error: restError };
|
|
2147
|
-
}
|
|
2148
|
-
}
|
|
2149
2523
|
/**
|
|
2150
2524
|
* Export OpenTelemetry spans.
|
|
2151
2525
|
* @param spans - Spans to export.
|
|
@@ -2153,34 +2527,121 @@ class AzureMonitorTraceExporter {
|
|
|
2153
2527
|
*/
|
|
2154
2528
|
async export(spans, resultCallback) {
|
|
2155
2529
|
api.diag.info(`Exporting ${spans.length} span(s). Converting to envelopes...`);
|
|
2156
|
-
|
|
2157
|
-
|
|
2530
|
+
let envelopes = [];
|
|
2531
|
+
spans.forEach((span) => {
|
|
2532
|
+
envelopes.push(readableSpanToEnvelope(span, this._instrumentationKey));
|
|
2533
|
+
let spanEventEnvelopes = spanEventsToEnvelopes(span, this._instrumentationKey);
|
|
2534
|
+
if (spanEventEnvelopes.length > 0) {
|
|
2535
|
+
envelopes.push(...spanEventEnvelopes);
|
|
2536
|
+
}
|
|
2537
|
+
});
|
|
2538
|
+
resultCallback(await this._exportEnvelopes(envelopes));
|
|
2158
2539
|
}
|
|
2159
2540
|
/**
|
|
2160
2541
|
* Shutdown AzureMonitorTraceExporter.
|
|
2161
2542
|
*/
|
|
2162
2543
|
async shutdown() {
|
|
2163
2544
|
api.diag.info("Azure Monitor Trace Exporter shutting down");
|
|
2164
|
-
return this.
|
|
2545
|
+
return this._shutdown();
|
|
2165
2546
|
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
// Copyright (c) Microsoft Corporation.
|
|
2550
|
+
/**
|
|
2551
|
+
* Metric to Azure envelope parsing.
|
|
2552
|
+
* @internal
|
|
2553
|
+
*/
|
|
2554
|
+
function resourceMetricsToEnvelope(metrics, ikey) {
|
|
2555
|
+
let envelopes = [];
|
|
2556
|
+
const time = new Date();
|
|
2557
|
+
const instrumentationKey = ikey;
|
|
2558
|
+
const tags = createTagsFromResource(metrics.resource);
|
|
2559
|
+
metrics.scopeMetrics.forEach((scopeMetric) => {
|
|
2560
|
+
let baseData = {
|
|
2561
|
+
metrics: [],
|
|
2562
|
+
version: 2,
|
|
2563
|
+
};
|
|
2564
|
+
scopeMetric.metrics.forEach((metric) => {
|
|
2565
|
+
metric.dataPoints.forEach((dataPoint) => {
|
|
2566
|
+
var metricDataPoint = {
|
|
2567
|
+
name: metric.descriptor.name,
|
|
2568
|
+
value: 0,
|
|
2569
|
+
dataPointType: "Aggregation",
|
|
2570
|
+
};
|
|
2571
|
+
if (metric.dataPointType == sdkMetricsBase.DataPointType.SINGULAR) {
|
|
2572
|
+
metricDataPoint.value = dataPoint.value;
|
|
2573
|
+
metricDataPoint.count = 1;
|
|
2574
|
+
}
|
|
2575
|
+
else {
|
|
2576
|
+
metricDataPoint.value = dataPoint.value.sum;
|
|
2577
|
+
metricDataPoint.count = dataPoint.value.count;
|
|
2578
|
+
}
|
|
2579
|
+
baseData.metrics.push(metricDataPoint);
|
|
2580
|
+
});
|
|
2581
|
+
});
|
|
2582
|
+
let envelope = {
|
|
2583
|
+
name: "Microsoft.ApplicationInsights.Metric",
|
|
2584
|
+
time: time,
|
|
2585
|
+
sampleRate: 100,
|
|
2586
|
+
instrumentationKey: instrumentationKey,
|
|
2587
|
+
tags: tags,
|
|
2588
|
+
version: 1,
|
|
2589
|
+
data: {
|
|
2590
|
+
baseType: "MetricData",
|
|
2591
|
+
baseData: Object.assign({}, baseData),
|
|
2592
|
+
},
|
|
2593
|
+
};
|
|
2594
|
+
envelopes.push(envelope);
|
|
2595
|
+
});
|
|
2596
|
+
return envelopes;
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
// Copyright (c) Microsoft Corporation.
|
|
2600
|
+
/**
|
|
2601
|
+
* Azure Monitor OpenTelemetry Metric Exporter.
|
|
2602
|
+
*/
|
|
2603
|
+
class AzureMonitorMetricExporter extends AzureMonitorBaseExporter {
|
|
2604
|
+
/**
|
|
2605
|
+
* Initializes a new instance of the AzureMonitorMetricExporter class.
|
|
2606
|
+
* @param AzureExporterConfig - Exporter configuration.
|
|
2607
|
+
*/
|
|
2608
|
+
constructor(options = {}) {
|
|
2609
|
+
super(options);
|
|
2610
|
+
api.diag.debug("AzureMonitorMetricExporter was successfully setup");
|
|
2176
2611
|
}
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2612
|
+
/**
|
|
2613
|
+
* Export OpenTelemetry resource metrics.
|
|
2614
|
+
* @param metrics - Resource metrics to export.
|
|
2615
|
+
* @param resultCallback - Result callback.
|
|
2616
|
+
*/
|
|
2617
|
+
async export(metrics, resultCallback) {
|
|
2618
|
+
api.diag.info(`Exporting ${metrics.scopeMetrics.length} metrics(s). Converting to envelopes...`);
|
|
2619
|
+
let envelopes = resourceMetricsToEnvelope(metrics, this._instrumentationKey);
|
|
2620
|
+
resultCallback(await this._exportEnvelopes(envelopes));
|
|
2621
|
+
}
|
|
2622
|
+
/**
|
|
2623
|
+
* Shutdown AzureMonitorMetricExporter.
|
|
2624
|
+
*/
|
|
2625
|
+
async shutdown() {
|
|
2626
|
+
api.diag.info("Azure Monitor Trace Exporter shutting down");
|
|
2627
|
+
return this._shutdown();
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Select aggregation temporality
|
|
2631
|
+
*/
|
|
2632
|
+
selectAggregationTemporality() {
|
|
2633
|
+
return sdkMetricsBase.AggregationTemporality.CUMULATIVE;
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* Force flush
|
|
2637
|
+
*/
|
|
2638
|
+
async forceFlush() {
|
|
2639
|
+
// TODO: https://github.com/open-telemetry/opentelemetry-js/issues/3060
|
|
2640
|
+
throw new Error("Method not implemented.");
|
|
2182
2641
|
}
|
|
2183
2642
|
}
|
|
2184
2643
|
|
|
2644
|
+
exports.AzureMonitorBaseExporter = AzureMonitorBaseExporter;
|
|
2645
|
+
exports.AzureMonitorMetricExporter = AzureMonitorMetricExporter;
|
|
2185
2646
|
exports.AzureMonitorTraceExporter = AzureMonitorTraceExporter;
|
|
2186
2647
|
//# sourceMappingURL=index.js.map
|