@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.
Files changed (42) hide show
  1. package/README.md +11 -13
  2. package/dist/index.js +706 -245
  3. package/dist-esm/src/Declarations/Constants.js +1 -1
  4. package/dist-esm/src/Declarations/Constants.js.map +1 -1
  5. package/dist-esm/src/config.js +2 -4
  6. package/dist-esm/src/config.js.map +1 -1
  7. package/dist-esm/src/export/base.js +172 -0
  8. package/dist-esm/src/export/base.js.map +1 -0
  9. package/dist-esm/src/export/metric.js +50 -0
  10. package/dist-esm/src/export/metric.js.map +1 -0
  11. package/dist-esm/src/export/trace.js +14 -145
  12. package/dist-esm/src/export/trace.js.map +1 -1
  13. package/dist-esm/src/generated/applicationInsightsClient.js.map +1 -1
  14. package/dist-esm/src/generated/applicationInsightsClientContext.js +2 -2
  15. package/dist-esm/src/generated/applicationInsightsClientContext.js.map +1 -1
  16. package/dist-esm/src/generated/models/index.js.map +1 -1
  17. package/dist-esm/src/index.js +2 -0
  18. package/dist-esm/src/index.js.map +1 -1
  19. package/dist-esm/src/platform/nodejs/constants.js +1 -1
  20. package/dist-esm/src/platform/nodejs/constants.js.map +1 -1
  21. package/dist-esm/src/platform/nodejs/httpSender.js +12 -3
  22. package/dist-esm/src/platform/nodejs/httpSender.js.map +1 -1
  23. package/dist-esm/src/platform/nodejs/persist/fileAccessControl.js +171 -0
  24. package/dist-esm/src/platform/nodejs/persist/fileAccessControl.js.map +1 -0
  25. package/dist-esm/src/platform/nodejs/persist/fileSystemHelpers.js.map +1 -1
  26. package/dist-esm/src/platform/nodejs/persist/fileSystemPersist.js +40 -19
  27. package/dist-esm/src/platform/nodejs/persist/fileSystemPersist.js.map +1 -1
  28. package/dist-esm/src/utils/breezeUtils.js +5 -4
  29. package/dist-esm/src/utils/breezeUtils.js.map +1 -1
  30. package/dist-esm/src/utils/constants/applicationinsights.js +1 -1
  31. package/dist-esm/src/utils/constants/applicationinsights.js.map +1 -1
  32. package/dist-esm/src/utils/eventhub.js +1 -1
  33. package/dist-esm/src/utils/eventhub.js.map +1 -1
  34. package/dist-esm/src/utils/metricUtils.js +53 -0
  35. package/dist-esm/src/utils/metricUtils.js.map +1 -0
  36. package/dist-esm/src/utils/resourceUtils.js +35 -0
  37. package/dist-esm/src/utils/resourceUtils.js.map +1 -0
  38. package/dist-esm/src/utils/spanUtils.js +118 -49
  39. package/dist-esm/src/utils/spanUtils.js.map +1 -1
  40. package/package.json +25 -26
  41. package/types/monitor-opentelemetry-exporter.d.ts +110 -7
  42. 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
- const PerformanceToQuickPulseCounter = {
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
- const readdirAsync = util.promisify(fs.readdir);
183
- const statAsync = util.promisify(fs.stat);
184
- const lstatAsync = util.promisify(fs.lstat);
185
- const mkdirAsync = util.promisify(fs.mkdir);
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(path.join(directory, file));
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$1 = util.promisify(fs.stat);
231
- const readdirAsync$1 = util.promisify(fs.readdir);
232
- const readFileAsync = util.promisify(fs.readFile);
233
- const unlinkAsync = util.promisify(fs.unlink);
234
- const writeFileAsync = util.promisify(fs.writeFile);
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
- if (!this._options.instrumentationKey) {
247
- api.diag.error(`No instrumentation key was provided to FileSystemPersister. Files may not be properly persisted`);
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
- this._tempDirectory = path.join(os.tmpdir(), FileSystemPersist.TEMPDIR_PREFIX + this._options.instrumentationKey);
250
- // Starts file cleanup task
251
- if (!this._fileCleanupTimer) {
252
- this._fileCleanupTimer = setTimeout(() => {
253
- this._fileCleanupTask();
254
- }, this.cleanupTimeOut);
255
- this._fileCleanupTimer.unref();
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
- api.diag.debug("Pushing value to persistent storage", value.toString());
260
- return this._storeToDisk(JSON.stringify(value));
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
- api.diag.debug("Searching for filesystem persisted files");
264
- try {
265
- const buffer = await this._getFirstFileOnDisk();
266
- if (buffer) {
267
- return JSON.parse(buffer.toString("utf8"));
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
- catch (e) {
271
- api.diag.debug("Failed to read persisted file", e);
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$1(this._tempDirectory);
497
+ const stats = await statAsync(this._tempDirectory);
282
498
  if (stats.isDirectory()) {
283
- const origFiles = await readdirAsync$1(this._tempDirectory);
284
- const files = origFiles.filter((f) => path.basename(f).includes(FileSystemPersist.FILENAME_SUFFIX));
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 = path.join(this._tempDirectory, firstFile);
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 = path.join(this._tempDirectory, fileName);
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$1(this._tempDirectory);
559
+ const stats = await statAsync(this._tempDirectory);
344
560
  if (stats.isDirectory()) {
345
- const origFiles = await readdirAsync$1(this._tempDirectory);
346
- const files = origFiles.filter((f) => path.basename(f).includes(FileSystemPersist.FILENAME_SUFFIX));
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 = path.join(this._tempDirectory, file);
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 coreClient.ServiceClient {
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.4`;
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 = coreClient.createSerializer(Mappers, /* isXml */ false);
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.5";
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] = os && `${os.type()} ${os.release()}`;
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 || // Retriable
1803
+ return (statusCode === 206 || // Partial Accept
1804
+ statusCode === 401 || // Unauthorized
1805
+ statusCode === 403 || // Forbidden
1579
1806
  statusCode === 408 || // Timeout
1580
- statusCode === 429 || // Throttle
1581
- statusCode === 439 || // Quota
1807
+ statusCode === 429 || // Too many requests
1582
1808
  statusCode === 500 || // Server Error
1583
- statusCode === 503 // Server Unavilable
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 createTagsFromSpan(span) {
1672
- const context = getInstance();
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
- if (span.resource && span.resource.attributes) {
1679
- const serviceName = span.resource.attributes[semanticConventions.SemanticResourceAttributes.SERVICE_NAME];
1680
- const serviceNamespace = span.resource.attributes[semanticConventions.SemanticResourceAttributes.SERVICE_NAMESPACE];
1681
- if (serviceName) {
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 createPropertiesFromSpan(span) {
2141
+ function createPropertiesFromSpanAttributes(attributes) {
1742
2142
  const properties = {};
1743
- const measurements = {};
1744
- for (const key of Object.keys(span.attributes)) {
1745
- if (!(key.startsWith("http.") ||
1746
- key.startsWith("rpc.") ||
1747
- key.startsWith("db.") ||
1748
- key.startsWith("peer.") ||
1749
- key.startsWith("net."))) {
1750
- properties[key] = span.attributes[key];
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 (error) { }
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
- var _a, _b, _c, _d;
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
- const envelopes = spans.map((span) => readableSpanToEnvelope(span, this._options.instrumentationKey));
2157
- resultCallback(await this.exportEnvelopes(envelopes));
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._sender.shutdown();
2545
+ return this._shutdown();
2165
2546
  }
2166
- async _sendFirstPersistedFile() {
2167
- try {
2168
- const envelopes = (await this._persister.shift());
2169
- if (envelopes) {
2170
- await this._sender.send(envelopes);
2171
- }
2172
- }
2173
- catch (err) {
2174
- api.diag.warn(`Failed to fetch persisted file`, err);
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
- _isNetworkError(error) {
2178
- if (error && error.code && error.code === "REQUEST_SEND_ERROR") {
2179
- return true;
2180
- }
2181
- return false;
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