From 6ac04b5dfcc8e818f72da1352a7c9ea9aca58e44 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 10 Feb 2020 11:22:31 -0500 Subject: [PATCH 01/66] Created skeleton of Azure Monitor Exporter project. --- .../package-lock.json | 73 +++++++++++++++++++ .../opencensus-exporter-azure/package.json | 14 ++++ .../src/azure-stats.ts | 23 ++++++ .../src/azure-trace.ts | 22 ++++++ .../opencensus-exporter-azure/src/index.ts | 2 + 5 files changed, 134 insertions(+) create mode 100644 packages/opencensus-exporter-azure/package-lock.json create mode 100644 packages/opencensus-exporter-azure/package.json create mode 100644 packages/opencensus-exporter-azure/src/azure-stats.ts create mode 100644 packages/opencensus-exporter-azure/src/azure-trace.ts create mode 100644 packages/opencensus-exporter-azure/src/index.ts diff --git a/packages/opencensus-exporter-azure/package-lock.json b/packages/opencensus-exporter-azure/package-lock.json new file mode 100644 index 000000000..79d688192 --- /dev/null +++ b/packages/opencensus-exporter-azure/package-lock.json @@ -0,0 +1,73 @@ +{ + "name": "@opencensus/exporter-azure", + "version": "0.0.19", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@opencensus/core": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.19.tgz", + "integrity": "sha512-Y5QXa7vggMU0+jveLcworfX9jNnztix7x1NraAV0uGkTp4y46HrFl0DnNcnNxUDvBu/cYeWRwlmhiWlr9+adOQ==", + "requires": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^6.0.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + } + }, + "async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "requires": { + "shimmer": "^1.2.0" + } + }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } +} diff --git a/packages/opencensus-exporter-azure/package.json b/packages/opencensus-exporter-azure/package.json new file mode 100644 index 000000000..8868492df --- /dev/null +++ b/packages/opencensus-exporter-azure/package.json @@ -0,0 +1,14 @@ +{ + "name": "@opencensus/exporter-azure", + "version": "0.0.19", + "description": "OpenCensus Azure Exporter allows the user to send stats and traces collected with OpenCensus Node.js to Azure Monitor.", + "main": "index.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "NCSU SDC Spring 2020 Team 05", + "license": "Apache-2.0", + "dependencies": { + "@opencensus/core": "^0.0.19" + } +} diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts new file mode 100644 index 000000000..30b94889f --- /dev/null +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -0,0 +1,23 @@ +import { + Exporter, + ExporterConfig +} from '@opencensus/core'; + +export interface AzureStatsExporterOption extends ExporterConfig { + +} + +export class AzureStatsExporter implements Exporter { + + publish(spans: import("@opencensus/core").Span[]): Promise { + throw new Error("Method not implemented."); + } + + onStartSpan(span: import("@opencensus/core").Span): void { + throw new Error("Method not implemented."); + } + onEndSpan(span: import("@opencensus/core").Span): void { + throw new Error("Method not implemented."); + } + +} \ No newline at end of file diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts new file mode 100644 index 000000000..cd0ce63c1 --- /dev/null +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -0,0 +1,22 @@ +import { + Exporter, + ExporterConfig +} from '@opencensus/core'; + +export interface AzureTraceExporterOptions extends ExporterConfig { + +} + +export class AzureTraceExporter implements Exporter { + + publish(spans: import("@opencensus/core").Span[]): Promise { + throw new Error("Method not implemented."); + } + + onStartSpan(span: import("@opencensus/core").Span): void { + throw new Error("Method not implemented."); + } + onEndSpan(span: import("@opencensus/core").Span): void { + throw new Error("Method not implemented."); + } +} \ No newline at end of file diff --git a/packages/opencensus-exporter-azure/src/index.ts b/packages/opencensus-exporter-azure/src/index.ts new file mode 100644 index 000000000..0f925d3c6 --- /dev/null +++ b/packages/opencensus-exporter-azure/src/index.ts @@ -0,0 +1,2 @@ +import AzureStatsExporter, AzureStatsExporterOptions from './azure-stats'; +import * from './azure-trace'; \ No newline at end of file From 5cf602cdf9eafacdf33fa763babc3ccfdcb204b5 Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 12 Feb 2020 13:39:37 -0500 Subject: [PATCH 02/66] Changed inheritance of AzureStatsExporter. --- .../src/azure-stats.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 30b94889f..f74c13efe 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -1,22 +1,25 @@ import { - Exporter, - ExporterConfig + ExporterConfig, + StatsEventListener } from '@opencensus/core'; -export interface AzureStatsExporterOption extends ExporterConfig { +export interface AzureStatsExporterOptions extends ExporterConfig { } -export class AzureStatsExporter implements Exporter { +export class AzureStatsExporter implements StatsEventListener { - publish(spans: import("@opencensus/core").Span[]): Promise { + onRegisterView(view: import("@opencensus/core").View): void { + throw new Error("Method not implemented."); + } onRecord(views: import("@opencensus/core").View[], measurement: import("@opencensus/core").Measurement, tags: Map): void { throw new Error("Method not implemented."); } - - onStartSpan(span: import("@opencensus/core").Span): void { + + start(): void { throw new Error("Method not implemented."); } - onEndSpan(span: import("@opencensus/core").Span): void { + + stop(): void { throw new Error("Method not implemented."); } From 12bcf3f0a170dc6b202f661c37d245c8e57f574e Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 12 Feb 2020 14:03:03 -0500 Subject: [PATCH 03/66] Documented and organized the exporter skeleton. --- .../src/azure-stats.ts | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index f74c13efe..5ccc4277a 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -3,22 +3,47 @@ import { StatsEventListener } from '@opencensus/core'; +/** + * Options for Azure Monitor configuration. + */ export interface AzureStatsExporterOptions extends ExporterConfig { } +/** + * Formats and sends Stats to Azure Monitor. + */ export class AzureStatsExporter implements StatsEventListener { + /** + * Is called whenever a view is registered. + * @param view The registered view. + */ onRegisterView(view: import("@opencensus/core").View): void { throw new Error("Method not implemented."); - } onRecord(views: import("@opencensus/core").View[], measurement: import("@opencensus/core").Measurement, tags: Map): void { + } + + /** + * Is called whenever a measure is recorded. + * @param views The views related to the measurement + * @param measurement The recorded measurement + * @param tags The tags to which the value is applied + */ + onRecord(views: import("@opencensus/core").View[], measurement: import("@opencensus/core").Measurement, tags: Map): void { throw new Error("Method not implemented."); } + /** + * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. + */ start(): void { throw new Error("Method not implemented."); } + /** + * Clear the interval timer to stop uploading metrics. It should be called + * whenever the exporter is not needed anymore. + */ stop(): void { throw new Error("Method not implemented."); } From 9b92b52e67f8858817fa428c037cc8be1be191ee Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 12 Feb 2020 17:06:28 -0500 Subject: [PATCH 04/66] Began implementing the expoter. Started by adding a few basic options that can be configured. Added a timer to handle batching of metric exports. --- .../src/azure-stats.ts | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 5ccc4277a..7fe5772b0 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -1,6 +1,7 @@ import { ExporterConfig, - StatsEventListener + StatsEventListener, + clear } from '@opencensus/core'; /** @@ -8,12 +9,40 @@ import { */ export interface AzureStatsExporterOptions extends ExporterConfig { + /** + * If specified, defines the number of milliseconds between uploading metrics + * to Azure Monitor. Optional, defaults to 60,000 (1 minute). + */ + period?: number; + + /** + * If specified, this will override the default OpenCensus prefix of an + * Azure Monitor metric. Optional. + */ + prefix?: string; + } /** * Formats and sends Stats to Azure Monitor. */ export class AzureStatsExporter implements StatsEventListener { + // Define configurable variables. + private period: number; + private metricPrefix: string; + private onMetricUploadError?: (err: Error) => void; + + // Define defaults for each configurable variable. + private static readonly PERIOD: number = 60000; + private static readonly METRIC_PREFIX: string = 'OpenCensus'; + + // Define all other exporter variables. + private timer: NodeJS.Timer; + + constructor(options: AzureStatsExporterOptions) { + this.period = options.period !== undefined ? options.period : AzureStatsExporter.PERIOD; + this.metricPrefix = options.prefix !== undefined ? options.prefix : AzureStatsExporter.METRIC_PREFIX; + } /** * Is called whenever a view is registered. @@ -37,7 +66,15 @@ export class AzureStatsExporter implements StatsEventListener { * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. */ start(): void { - throw new Error("Method not implemented."); + this.timer = setInterval(async () => { + try { + await this.export(); + } catch (err) { + if (typeof this.onMetricUploadError === 'function') { + this.onMetricUploadError(err); + } + } + }, this.period); } /** @@ -45,7 +82,14 @@ export class AzureStatsExporter implements StatsEventListener { * whenever the exporter is not needed anymore. */ stop(): void { - throw new Error("Method not implemented."); + clearInterval(this.timer); + } + + /** + * Polls the Metrics library for all registered metrics and uploads these to Azure Monitor. + */ + async export() { + } } \ No newline at end of file From 59a2e9556acfb77a4c747eb904d96369a38059d3 Mon Sep 17 00:00:00 2001 From: jwlong Date: Fri, 14 Feb 2020 14:35:21 -0500 Subject: [PATCH 05/66] Added Application Insights SDK. --- package.json | 3 +++ packages/opencensus-exporter-azure/package.json | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 48ea6e5b5..b4f08587c 100644 --- a/package.json +++ b/package.json @@ -45,5 +45,8 @@ "lerna": "^2.11.0", "typedoc": "^0.14.2", "typescript": "^3.0.0" + }, + "dependencies": { + "applicationinsights": "^1.7.2" } } diff --git a/packages/opencensus-exporter-azure/package.json b/packages/opencensus-exporter-azure/package.json index 8868492df..3df6f9b95 100644 --- a/packages/opencensus-exporter-azure/package.json +++ b/packages/opencensus-exporter-azure/package.json @@ -9,6 +9,7 @@ "author": "NCSU SDC Spring 2020 Team 05", "license": "Apache-2.0", "dependencies": { - "@opencensus/core": "^0.0.19" + "@opencensus/core": "^0.0.19", + "applicationinsights": "^1.7.2" } } From 2317ac2c97d240791dbba30671d1a6ca63677e09 Mon Sep 17 00:00:00 2001 From: jwlong Date: Fri, 14 Feb 2020 14:35:52 -0500 Subject: [PATCH 06/66] Refined options. Started integration of App Insights SDK. --- .../src/azure-stats.ts | 86 +++++++++++++++---- 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 7fe5772b0..5f0150041 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -1,14 +1,33 @@ import { ExporterConfig, StatsEventListener, - clear + View, + Measurement, + TagKey, + TagValue, + logger, + Logger } from '@opencensus/core'; +import { + start as startAppInsights, + setup as setupAppInsights, + dispose as disposeAppInsights, + defaultClient as telemetry, + TelemetryClient } +from 'applicationinsights'; + /** * Options for Azure Monitor configuration. */ export interface AzureStatsExporterOptions extends ExporterConfig { + /** + * The Instrumentation Key found in your application's Azure Monitor Application Insights + * Overview page. Required. + */ + instrumentationKey: string; + /** * If specified, defines the number of milliseconds between uploading metrics * to Azure Monitor. Optional, defaults to 60,000 (1 minute). @@ -21,44 +40,71 @@ export interface AzureStatsExporterOptions extends ExporterConfig { */ prefix?: string; + /** + * If specified, this will serve as the logger used by the exporter. + * Optional, default to use whatever logger is registered with OpenCensus. + */ + logger?: Logger; + + /** + * If specified, this function will be called whenever an error occurs uploading + * stats to Azure monitor. Optional. + */ + onMetricUploadError?: (err: Error) => void; + +} + +const AzureStatsExporterDefaults: AzureStatsExporterOptions = { + instrumentationKey: undefined, + period: 60000, + prefix: 'OpenCensus', + logger: logger.logger() } /** * Formats and sends Stats to Azure Monitor. */ export class AzureStatsExporter implements StatsEventListener { - // Define configurable variables. - private period: number; - private metricPrefix: string; - private onMetricUploadError?: (err: Error) => void; - - // Define defaults for each configurable variable. - private static readonly PERIOD: number = 60000; - private static readonly METRIC_PREFIX: string = 'OpenCensus'; + // Define the options that will be used within the exporter. + private options: AzureStatsExporterOptions; // Define all other exporter variables. private timer: NodeJS.Timer; + /** + * Configures a new Stats Exporter given a set of options. + * @param options Specific configuration information to use when constructing the exporter. + */ constructor(options: AzureStatsExporterOptions) { - this.period = options.period !== undefined ? options.period : AzureStatsExporter.PERIOD; - this.metricPrefix = options.prefix !== undefined ? options.prefix : AzureStatsExporter.METRIC_PREFIX; + // Verify that the options passed in have actual values (no undefined values) + // for require parameters. + if (options.instrumentationKey === undefined) { + AzureStatsExporterDefaults.logger.error('You must specify an Instrumentation Key to create an Azure Monitor Stats Exporter.'); + } + + // Start with the default options, and overwrite the defaults with any options specified + // in the constructor's options parameter. + this.options = { ...AzureStatsExporterDefaults, ...options }; + + // Configure the Application Insights SDK to use the Instrumentation Key from our options. + setupAppInsights(this.options.instrumentationKey); } /** * Is called whenever a view is registered. * @param view The registered view. */ - onRegisterView(view: import("@opencensus/core").View): void { + onRegisterView(view: View): void { throw new Error("Method not implemented."); } /** * Is called whenever a measure is recorded. - * @param views The views related to the measurement - * @param measurement The recorded measurement - * @param tags The tags to which the value is applied + * @param views The views related to the measurement. + * @param measurement The recorded measurement. + * @param tags The tags to which the value is applied. */ - onRecord(views: import("@opencensus/core").View[], measurement: import("@opencensus/core").Measurement, tags: Map): void { + onRecord(views: View[], measurement: Measurement, tags: Map): void { throw new Error("Method not implemented."); } @@ -66,15 +112,16 @@ export class AzureStatsExporter implements StatsEventListener { * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. */ start(): void { + startAppInsights(); this.timer = setInterval(async () => { try { await this.export(); } catch (err) { - if (typeof this.onMetricUploadError === 'function') { - this.onMetricUploadError(err); + if (typeof this.options.onMetricUploadError === 'function') { + this.options.onMetricUploadError(err); } } - }, this.period); + }, this.options.period); } /** @@ -83,6 +130,7 @@ export class AzureStatsExporter implements StatsEventListener { */ stop(): void { clearInterval(this.timer); + disposeAppInsights(); } /** From 281fa91aeba2393b0ba8171df0053eb13c890277 Mon Sep 17 00:00:00 2001 From: jwlong Date: Fri, 14 Feb 2020 14:40:26 -0500 Subject: [PATCH 07/66] Added a TODO to the onRecord() function. --- packages/opencensus-exporter-azure/src/azure-stats.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 5f0150041..b640c774d 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -105,7 +105,9 @@ export class AzureStatsExporter implements StatsEventListener { * @param tags The tags to which the value is applied. */ onRecord(views: View[], measurement: Measurement, tags: Map): void { - throw new Error("Method not implemented."); + // Use the App Insights SDK to track this measurement. + // TODO: Build out the MetricTelemetry object to pass to the SDK. + telemetry.trackMetric(undefined); } /** From 961e5e6d6cf3899b55d181c840cbb4dfdac4c203 Mon Sep 17 00:00:00 2001 From: jwlong Date: Fri, 14 Feb 2020 14:42:36 -0500 Subject: [PATCH 08/66] Improved documentation. --- packages/opencensus-exporter-azure/src/azure-stats.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index b640c774d..f855178ea 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -54,6 +54,9 @@ export interface AzureStatsExporterOptions extends ExporterConfig { } +/** + * Configuration defaults for an AzureStatsExporter. + */ const AzureStatsExporterDefaults: AzureStatsExporterOptions = { instrumentationKey: undefined, period: 60000, @@ -114,7 +117,12 @@ export class AzureStatsExporter implements StatsEventListener { * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. */ start(): void { + // Start the App Insights SDK. startAppInsights(); + + // Set a timer using the interval (period) defined in the exporter's options. + // Each time the timer ticks, export any data that has been tracked by utilizing + // the exporter's export() function. this.timer = setInterval(async () => { try { await this.export(); @@ -131,7 +139,10 @@ export class AzureStatsExporter implements StatsEventListener { * whenever the exporter is not needed anymore. */ stop(): void { + // Stop the timer. clearInterval(this.timer); + + // Pass the stop signal on to the App Insights SDK. disposeAppInsights(); } From b65c8d6b372663d1ac5e6281d597c4ba2e154e04 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 17 Feb 2020 10:41:19 -0500 Subject: [PATCH 09/66] Added some information log statements. --- .../src/azure-stats.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index f855178ea..b8785859b 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -6,16 +6,18 @@ import { TagKey, TagValue, logger, - Logger + Logger, + Metric, + MetricProducerManager, + Metrics } from '@opencensus/core'; import { start as startAppInsights, setup as setupAppInsights, dispose as disposeAppInsights, - defaultClient as telemetry, - TelemetryClient } -from 'applicationinsights'; + defaultClient as telemetry +} from 'applicationinsights'; /** * Options for Azure Monitor configuration. @@ -119,6 +121,7 @@ export class AzureStatsExporter implements StatsEventListener { start(): void { // Start the App Insights SDK. startAppInsights(); + this.options.logger.info('Started App Insights SDK.'); // Set a timer using the interval (period) defined in the exporter's options. // Each time the timer ticks, export any data that has been tracked by utilizing @@ -132,6 +135,7 @@ export class AzureStatsExporter implements StatsEventListener { } } }, this.options.period); + this.options.logger.info('Set export interval to ' + this.options.period + ' ms.'); } /** @@ -141,15 +145,22 @@ export class AzureStatsExporter implements StatsEventListener { stop(): void { // Stop the timer. clearInterval(this.timer); + this.options.logger.info('Clearing export interval.'); // Pass the stop signal on to the App Insights SDK. disposeAppInsights(); + this.options.logger.info('Disposed App Insights SDK.') } /** * Polls the Metrics library for all registered metrics and uploads these to Azure Monitor. */ async export() { + this.options.logger.info('Starting export of metric batch.'); + + const metricList: Metric[] = []; + const metricProducerManager: MetricProducerManager = Metrics.getMetricProducerManager(); + } From 166ea994eaf001ee19fe6578ed7cb01b3533c297 Mon Sep 17 00:00:00 2001 From: Gaven Kerr Date: Mon, 17 Feb 2020 11:35:35 -0500 Subject: [PATCH 10/66] added onRecord functionality. Not sure if it works yet, but its built up through other exporter files --- .../src/azure-stats.ts | 78 +++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index f855178ea..de6b102dc 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -6,9 +6,13 @@ import { TagKey, TagValue, logger, - Logger + Logger, + Measure, + AggregationData, } from '@opencensus/core'; +import Contracts = require("../node_modules/applicationinsights/out/Declarations/Contracts/TelemetryTypes/MetricTelemetry"); + import { start as startAppInsights, setup as setupAppInsights, @@ -17,6 +21,12 @@ import { TelemetryClient } from 'applicationinsights'; +export interface StatsParams { + registeredViews: View[]; + registeredMeasures: Measure[]; + recordedData: { [key: string]: AggregationData[] }; + } + /** * Options for Azure Monitor configuration. */ @@ -74,6 +84,12 @@ export class AzureStatsExporter implements StatsEventListener { // Define all other exporter variables. private timer: NodeJS.Timer; + private statsParams: StatsParams = { + registeredViews: [], + registeredMeasures: [], + recordedData: {}, + }; + /** * Configures a new Stats Exporter given a set of options. * @param options Specific configuration information to use when constructing the exporter. @@ -98,7 +114,19 @@ export class AzureStatsExporter implements StatsEventListener { * @param view The registered view. */ onRegisterView(view: View): void { - throw new Error("Method not implemented."); + // Adds the view to registeredViews array if it doesn't contain yet + if (!this.statsParams.registeredViews.find(v => v.name === view.name)) { + this.statsParams.registeredViews.push(view); + } + // Adds the measure to registeredMeasures array if it doesn't contain yet + if ( + !this.statsParams.registeredMeasures.find( + m => m.name === view.measure.name + ) + ) { + this.statsParams.registeredMeasures.push(view.measure); + } + } /** @@ -107,11 +135,49 @@ export class AzureStatsExporter implements StatsEventListener { * @param measurement The recorded measurement. * @param tags The tags to which the value is applied. */ - onRecord(views: View[], measurement: Measurement, tags: Map): void { - // Use the App Insights SDK to track this measurement. - // TODO: Build out the MetricTelemetry object to pass to the SDK. - telemetry.trackMetric(undefined); + // Use the App Insights SDK to track this measurement. + // TODO: Build out the MetricTelemetry object to pass to the SDK. + onRecord( + views: View[], + measurement: Measurement, + tags: Map + ): void { + const tagValues = [...tags.values()]; + views.map(view => { + const snapshot = view.getSnapshot(tagValues); + // Check if there is no data for the current view + if (!this.statsParams.recordedData[view.name]) { + this.statsParams.recordedData[view.name] = [snapshot]; + } else if ( + !this.statsParams.recordedData[view.name].find(s => s === snapshot) + ) { + // Push the snapshot if it hasn't recoreded before + this.statsParams.recordedData[view.name].push(snapshot); + } + }); + var newMetric: Contracts.MetricTelemetry; + newMetric.name = measurement.measure.name; + newMetric.value = measurement.value; + var mapIter = tags.entries(); + var tags_string:{ + [key: string]: string; + }; + for(var i =0; i < tags.size; i++){ + tags_string = tags_string + tags[i] as {key: string}; + } + newMetric.properties = tags_string; + telemetry.trackMetric(newMetric); } + + // var newMetric: Contracts.MetricTelemetry; + // newMetric.name = measurement.measure.name; + // newMetric.value = measurement.value; + // var mapIter = tags.entries(); + + // newMetric.properties = mapIter.next().value; + + // telemetry.trackMetric(newMetric); + /** * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. From e039d6aa5b3371ec0b6396e1a07e3d9320bc9425 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Wed, 19 Feb 2020 09:43:07 -0500 Subject: [PATCH 11/66] Started working on export() --- .../opencensus-exporter-azure/src/azure-stats.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index b8785859b..21715b529 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -157,11 +157,21 @@ export class AzureStatsExporter implements StatsEventListener { */ async export() { this.options.logger.info('Starting export of metric batch.'); - + + // Collect all of the metrics that will need to be exported in this batch. const metricList: Metric[] = []; const metricProducerManager: MetricProducerManager = Metrics.getMetricProducerManager(); + for (const metricProducer of metricProducerManager.getAllMetricProducer()) { + for (const metric of metricProducer.getMetrics()) { + if (metric) { + metricList.push(metric); + } + } + } + // Aggregate each metric before sending them to Azure Monitor. + } } \ No newline at end of file From 6cb9b9319c0b76cc8f326172e252690b2f7749cf Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Wed, 19 Feb 2020 09:45:19 -0500 Subject: [PATCH 12/66] Switched import statements to export statements. --- packages/opencensus-exporter-azure/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/index.ts b/packages/opencensus-exporter-azure/src/index.ts index 0f925d3c6..5b9c26ad1 100644 --- a/packages/opencensus-exporter-azure/src/index.ts +++ b/packages/opencensus-exporter-azure/src/index.ts @@ -1,2 +1,2 @@ -import AzureStatsExporter, AzureStatsExporterOptions from './azure-stats'; -import * from './azure-trace'; \ No newline at end of file +export * from './azure-stats'; +export * from './azure-trace'; \ No newline at end of file From 7932d636b57a95cf3092b434978db0727873d31d Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 24 Feb 2020 03:20:18 -0500 Subject: [PATCH 13/66] Comments from code review. --- packages/opencensus-exporter-azure/src/azure-stats.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 9c9086d75..85f2390d5 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -139,6 +139,8 @@ export class AzureStatsExporter implements StatsEventListener { */ // Use the App Insights SDK to track this measurement. // TODO: Build out the MetricTelemetry object to pass to the SDK. + // TODO: Try to break this out into smaller methods so we can clearly see + // the inputs and outputs. onRecord( views: View[], measurement: Measurement, @@ -237,7 +239,12 @@ export class AzureStatsExporter implements StatsEventListener { } // Aggregate each metric before sending them to Azure Monitor. - + // TODO: Aggregate metrics. + for (const metric of metricList) { + switch (metric.descriptor.type) { + + } + } } } \ No newline at end of file From 167b5065d40acd6c326400af92b9b502d4655653 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 24 Feb 2020 12:04:29 -0500 Subject: [PATCH 14/66] Added google typescript tools to the module --- .../opencensus-exporter-azure/package.json | 18 ++++++++++++++++-- .../prettier.config.js | 4 ++++ .../opencensus-exporter-azure/tsconfig.json | 11 +++++++++++ packages/opencensus-exporter-azure/tslint.json | 8 ++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 packages/opencensus-exporter-azure/prettier.config.js create mode 100644 packages/opencensus-exporter-azure/tsconfig.json create mode 100644 packages/opencensus-exporter-azure/tslint.json diff --git a/packages/opencensus-exporter-azure/package.json b/packages/opencensus-exporter-azure/package.json index 3df6f9b95..bc20e5376 100644 --- a/packages/opencensus-exporter-azure/package.json +++ b/packages/opencensus-exporter-azure/package.json @@ -2,14 +2,28 @@ "name": "@opencensus/exporter-azure", "version": "0.0.19", "description": "OpenCensus Azure Exporter allows the user to send stats and traces collected with OpenCensus Node.js to Azure Monitor.", + "type": "module", "main": "index.ts", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "compile": "tsc -p .", + "check": "gts check", + "clean": "gts clean", + "fix": "gts fix", + "prepare": "npm run compile", + "pretest": "npm run compile", + "posttest": "npm run check" }, "author": "NCSU SDC Spring 2020 Team 05", "license": "Apache-2.0", "dependencies": { "@opencensus/core": "^0.0.19", - "applicationinsights": "^1.7.2" + "applicationinsights": "^1.7.2", + "readline": "^1.3.0" + }, + "devDependencies": { + "gts": "^1.1.2", + "typescript": "~3.7.0", + "@types/node": "^10.0.3" } } diff --git a/packages/opencensus-exporter-azure/prettier.config.js b/packages/opencensus-exporter-azure/prettier.config.js new file mode 100644 index 000000000..a425d3f76 --- /dev/null +++ b/packages/opencensus-exporter-azure/prettier.config.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'es5', +}; diff --git a/packages/opencensus-exporter-azure/tsconfig.json b/packages/opencensus-exporter-azure/tsconfig.json new file mode 100644 index 000000000..d1646f011 --- /dev/null +++ b/packages/opencensus-exporter-azure/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/packages/opencensus-exporter-azure/tslint.json b/packages/opencensus-exporter-azure/tslint.json new file mode 100644 index 000000000..27872a139 --- /dev/null +++ b/packages/opencensus-exporter-azure/tslint.json @@ -0,0 +1,8 @@ +{ + "extends": "gts/tslint.json", + "linterOptions": { + "exclude": [ + "**/*.json" + ] + } +} From df8ed774305fe52763f3c0c404def7c095442c1a Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 24 Feb 2020 12:04:43 -0500 Subject: [PATCH 15/66] Started a test file --- .../opencensus-exporter-azure/test/repl.ts | 96 +++++++++++++++++++ .../opencensus-exporter-azure/test/test.txt | 34 +++++++ 2 files changed, 130 insertions(+) create mode 100644 packages/opencensus-exporter-azure/test/repl.ts create mode 100644 packages/opencensus-exporter-azure/test/test.txt diff --git a/packages/opencensus-exporter-azure/test/repl.ts b/packages/opencensus-exporter-azure/test/repl.ts new file mode 100644 index 000000000..336ea02a9 --- /dev/null +++ b/packages/opencensus-exporter-azure/test/repl.ts @@ -0,0 +1,96 @@ +/** + * This file is a simple Read, Execute, and Print loop to test sending + * metrics to Azure Monitor. + */ +import { + globalStats, + MeasureUnit, + AggregationType, + TagMap +} from '@opencensus/core'; +import { createReadStream } from 'fs'; +import { createInterface } from 'readline'; +import { AzureStatsExporter } from '../src/'; + +const exporter = new AzureStatsExporter({ + instrumentationKey: 'e3efe46f-5f1e-4b96-80de-60667b680b23' +}); +globalStats.registerExporter(exporter); + +const stream = createReadStream('./test.txt'); +const lineReader = createInterface({ input: stream }); + +// Configure OpenCensus Telemetry Tracking +const mLatencyMs = globalStats.createMeasureDouble('repl/latency', MeasureUnit.MS, 'The latency in milliseconds per REPL loop.'); +const mLineLengths = globalStats.createMeasureInt64('repl/line_lengths', MeasureUnit.BYTE, 'The distribution of line lengths.'); + +const methodTagKey = { name: 'method' }; +const statusTagKey = { name: 'status' }; +const errorTagKey = { name: 'error' }; + +const latencyView = globalStats.createView( + 'demo/latency', + mLatencyMs, + AggregationType.DISTRIBUTION, + [methodTagKey, statusTagKey, errorTagKey], + 'The distribution of the latencies', + [0, 25, 50, 75, 100, 200, 400, 600, 800, 1000, 2000, 4000, 6000] +); +globalStats.registerView(latencyView); + +const lineCountView = globalStats.createView( + 'demo/lines_in', + mLineLengths, + AggregationType.COUNT, + [methodTagKey], + 'The number of lines form standard input.' +); +globalStats.registerView(lineCountView); + +const lineLengthView = globalStats.createView( + 'demo/line_lengths', + mLineLengths, + AggregationType.DISTRIBUTION, + [methodTagKey], + 'Groups the lengths of keys in buckets.', + [0, 5, 10, 15, 20, 40, 60, 80, 100, 200, 400, 600, 800, 1000] +); +globalStats.registerView(lineLengthView); + +let startTime = new Date(); +let endTime; + +lineReader.on('line', function (line) { + const tags = new TagMap(); + tags.set(methodTagKey, { value: 'REPL' }); + tags.set(statusTagKey, { value: 'OK' }); + + try { + const processedLine = processLine(line); + console.log(processedLine); + + globalStats.record([{ + measure: mLineLengths, + value: processedLine.length + }, { + measure: mLatencyMs, + value: (new Date()).getTime() - startTime.getTime() + }], tags); + } catch (err) { + const errTags = new TagMap(); + errTags.set(methodTagKey, { value: 'REPL' }); + errTags.set(statusTagKey, { value: 'ERROR' }); + errTags.set(errorTagKey, { value: err.message }); + + globalStats.record([{ + measure: mLatencyMs, + value: (new Date()).getTime() - startTime.getTime() + }], errTags); + } + + startTime = new Date(); +}); + +function processLine(line) { + return line.toUpperCase(); +} \ No newline at end of file diff --git a/packages/opencensus-exporter-azure/test/test.txt b/packages/opencensus-exporter-azure/test/test.txt new file mode 100644 index 000000000..a9c38d29c --- /dev/null +++ b/packages/opencensus-exporter-azure/test/test.txt @@ -0,0 +1,34 @@ +You know what, Kelly? This is the real world. Not The Real World: Scranton. +Oh my God, this is super weird. +When Ryan had two girlfriends, he used to take me to some diner in Hazelton just so the other girl wouldn't see. +Through these blinds is where I first saw you, and you had all these boxes, and I thought you were the prettiest mover I had ever seen. +And I was sitting at this desk when I called you to tell you that I had herpes and that I was still in love with you and you said that it was over, and that you didn't love me. +Thank goodness none of that was true. +Including the herpes. +Dunder-Mifflin is the big picture! +Can't you understand that? No, you can't. +You're too young. +Ryan... has never made a sale. +And he started a fire trying to make a cheesy pita. +And everybody thinks he's a tease. +Well you know what? He doesn't know anything, and neither do you. +[walks out] SO SUCK ON THAT! +Do I have a special someone? +Uh well, yeah of course. +A bunch of 'em. My employees. +If I had to choose between a one-night-stand with some stupid cow I pick-up in a bar, and these people? +I'd pick them every time. +Because with them, it is an everyday stand and I still know their names in the morning. +This is a little character I like to do [places a green turban with a yellow feather on his head], it is, uh, loosely based on Karnack, one of Carson's classic characters. +[puts an envelope to his head] Here we go. The PLO, the IRA, and the hot dog stand behind the warehouse. +[tears open envelope and pulls out card] +"Name three businesses that have a better health care plans than Dunder Mifflin." +Here's the problem. +There's no open bar because of Jan and it's the reason why comedy clubs have a two drink minimum. +It'll be fine, I just...wish people were going to be drunk. +Well, that was not at all what I expected. +Hoo hoo! Whoo. +My heart's still racing. +I just looked a man in the eyes and I shook his hand. +All the time I was thinking, "I'm sleeping with your wife." +And you know who does that? James freakin' Bond. \ No newline at end of file From 2fd32fa2f395a3ebdcf48af738b5b2a0c09eeb65 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 24 Feb 2020 12:05:00 -0500 Subject: [PATCH 16/66] Whitespace changes from linting --- packages/opencensus-exporter-azure/src/azure-stats.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 85f2390d5..0565826af 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -27,7 +27,7 @@ export interface StatsParams { registeredViews: View[]; registeredMeasures: Measure[]; recordedData: { [key: string]: AggregationData[] }; - } +} /** * Options for Azure Monitor configuration. From 38d3f73df3b712ea748ff41a7580a86db61e14f5 Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 24 Feb 2020 12:16:25 -0500 Subject: [PATCH 17/66] Renamed period variable to specify ms --- packages/opencensus-exporter-azure/src/azure-stats.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 85f2390d5..d37ebbe46 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -44,7 +44,7 @@ export interface AzureStatsExporterOptions extends ExporterConfig { * If specified, defines the number of milliseconds between uploading metrics * to Azure Monitor. Optional, defaults to 60,000 (1 minute). */ - period?: number; + periodInMillis?: number; /** * If specified, this will override the default OpenCensus prefix of an @@ -71,7 +71,7 @@ export interface AzureStatsExporterOptions extends ExporterConfig { */ const AzureStatsExporterDefaults: AzureStatsExporterOptions = { instrumentationKey: undefined, - period: 60000, + periodInMillis: 60000, prefix: 'OpenCensus', logger: logger.logger() } @@ -202,8 +202,8 @@ export class AzureStatsExporter implements StatsEventListener { this.options.onMetricUploadError(err); } } - }, this.options.period); - this.options.logger.info('Set export interval to ' + this.options.period + ' ms.'); + }, this.options.periodInMillis); + this.options.logger.info('Set export interval to ' + this.options.periodInMillis + ' ms.'); } /** From fa8d5437c790d85d8e25f3361d0347cf36054c0b Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 26 Feb 2020 00:29:36 -0500 Subject: [PATCH 18/66] Added code coverage tracking --- packages/opencensus-exporter-azure/.nycrc | 8 ++++++ .../opencensus-exporter-azure/package.json | 27 +++++++++++-------- 2 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 packages/opencensus-exporter-azure/.nycrc diff --git a/packages/opencensus-exporter-azure/.nycrc b/packages/opencensus-exporter-azure/.nycrc new file mode 100644 index 000000000..9ca138bd4 --- /dev/null +++ b/packages/opencensus-exporter-azure/.nycrc @@ -0,0 +1,8 @@ +{ + "nyc": { + "all": true, + "include": [ + "test/**/*.ts" + ] + } +} \ No newline at end of file diff --git a/packages/opencensus-exporter-azure/package.json b/packages/opencensus-exporter-azure/package.json index bc20e5376..c950d2f0f 100644 --- a/packages/opencensus-exporter-azure/package.json +++ b/packages/opencensus-exporter-azure/package.json @@ -5,25 +5,30 @@ "type": "module", "main": "index.ts", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "nyc mocha -r ts-node/register test/**/*.ts", "compile": "tsc -p .", - "check": "gts check", - "clean": "gts clean", - "fix": "gts fix", "prepare": "npm run compile", - "pretest": "npm run compile", - "posttest": "npm run check" + "pretest": "npm run compile" }, "author": "NCSU SDC Spring 2020 Team 05", "license": "Apache-2.0", "dependencies": { - "@opencensus/core": "^0.0.19", + "@opencensus/core": "0.0.19", + "@types/continuation-local-storage": "^3.2.2", "applicationinsights": "^1.7.2", - "readline": "^1.3.0" + "continuation-local-storage": "^3.2.1" }, "devDependencies": { - "gts": "^1.1.2", - "typescript": "~3.7.0", - "@types/node": "^10.0.3" + "@types/chai": "^4.2.9", + "@types/mocha": "^7.0.1", + "@types/node": "^10.17.16", + "chai": "^4.2.0", + "fs": "0.0.1-security", + "mocha": "^7.0.1", + "nyc": "^15.0.0", + "readline": "^1.3.0", + "sinon": "^9.0.0", + "ts-node": "^8.6.2", + "typescript": "~3.7.0" } } From 8b18488db8991c63d162d512d022a8c7ae6dcfd7 Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 26 Feb 2020 00:30:07 -0500 Subject: [PATCH 19/66] Added linting and compiler rules. --- .../opencensus-exporter-azure/tsconfig.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/opencensus-exporter-azure/tsconfig.json b/packages/opencensus-exporter-azure/tsconfig.json index d1646f011..8622c984c 100644 --- a/packages/opencensus-exporter-azure/tsconfig.json +++ b/packages/opencensus-exporter-azure/tsconfig.json @@ -1,11 +1,22 @@ { - "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "pretty": true, + "module": "commonjs", + "target": "es6", + "strictNullChecks": false, + "baseUrl": ".", + "paths": { + "continuation-local-storage": ["node_modules/@types/continuation-local-storage"] + }, + "sourceMap": true }, + "exclude": [ + "node_modules" + ], "include": [ "src/**/*.ts", - "test/**/*.ts" + "test/**/*.ts", "repl.ts" ] } From d5816dd25641965550e2672169596e3bce660be1 Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 26 Feb 2020 00:30:24 -0500 Subject: [PATCH 20/66] Fixed a linting issue --- packages/opencensus-exporter-azure/src/azure-trace.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts index cd0ce63c1..d7a374db7 100644 --- a/packages/opencensus-exporter-azure/src/azure-trace.ts +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -1,6 +1,7 @@ import { Exporter, - ExporterConfig + ExporterConfig, + Span } from '@opencensus/core'; export interface AzureTraceExporterOptions extends ExporterConfig { @@ -9,14 +10,14 @@ export interface AzureTraceExporterOptions extends ExporterConfig { export class AzureTraceExporter implements Exporter { - publish(spans: import("@opencensus/core").Span[]): Promise { + publish(spans: Span[]): Promise { throw new Error("Method not implemented."); } - onStartSpan(span: import("@opencensus/core").Span): void { + onStartSpan(span: Span): void { throw new Error("Method not implemented."); } - onEndSpan(span: import("@opencensus/core").Span): void { + onEndSpan(span: Span): void { throw new Error("Method not implemented."); } -} \ No newline at end of file +} From 1c7b168ddbdc8a70f7aa88f2659828f9cf653e0c Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 26 Feb 2020 00:30:40 -0500 Subject: [PATCH 21/66] Moved location of test file --- .../{test => }/repl.ts | 52 ++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) rename packages/opencensus-exporter-azure/{test => }/repl.ts (60%) diff --git a/packages/opencensus-exporter-azure/test/repl.ts b/packages/opencensus-exporter-azure/repl.ts similarity index 60% rename from packages/opencensus-exporter-azure/test/repl.ts rename to packages/opencensus-exporter-azure/repl.ts index 336ea02a9..68b693347 100644 --- a/packages/opencensus-exporter-azure/test/repl.ts +++ b/packages/opencensus-exporter-azure/repl.ts @@ -2,66 +2,60 @@ * This file is a simple Read, Execute, and Print loop to test sending * metrics to Azure Monitor. */ -import { - globalStats, - MeasureUnit, - AggregationType, - TagMap -} from '@opencensus/core'; -import { createReadStream } from 'fs'; -import { createInterface } from 'readline'; -import { AzureStatsExporter } from '../src/'; +const oc = require('@opencensus/core'); +const fs = require('fs'); +const readline = require('readline'); +const AzureStatsExporter = require('./build/src/azure-stats'); const exporter = new AzureStatsExporter({ instrumentationKey: 'e3efe46f-5f1e-4b96-80de-60667b680b23' }); -globalStats.registerExporter(exporter); +oc.globalStats.registerExporter(exporter); -const stream = createReadStream('./test.txt'); -const lineReader = createInterface({ input: stream }); +const stream = fs.createReadStream('./test/test.txt'); +const lineReader = readline.createInterface({ input: stream }); // Configure OpenCensus Telemetry Tracking -const mLatencyMs = globalStats.createMeasureDouble('repl/latency', MeasureUnit.MS, 'The latency in milliseconds per REPL loop.'); -const mLineLengths = globalStats.createMeasureInt64('repl/line_lengths', MeasureUnit.BYTE, 'The distribution of line lengths.'); +const mLatencyMs = oc.globalStats.createMeasureDouble('repl/latency', oc.MeasureUnit.MS, 'The latency in milliseconds per REPL loop.'); +const mLineLengths = oc.globalStats.createMeasureInt64('repl/line_lengths', oc.MeasureUnit.BYTE, 'The distribution of line lengths.'); const methodTagKey = { name: 'method' }; const statusTagKey = { name: 'status' }; const errorTagKey = { name: 'error' }; -const latencyView = globalStats.createView( +const latencyView = oc.globalStats.createView( 'demo/latency', mLatencyMs, - AggregationType.DISTRIBUTION, + oc.AggregationType.DISTRIBUTION, [methodTagKey, statusTagKey, errorTagKey], 'The distribution of the latencies', [0, 25, 50, 75, 100, 200, 400, 600, 800, 1000, 2000, 4000, 6000] ); -globalStats.registerView(latencyView); +oc.globalStats.registerView(latencyView); -const lineCountView = globalStats.createView( +const lineCountView = oc.globalStats.createView( 'demo/lines_in', mLineLengths, - AggregationType.COUNT, + oc.AggregationType.COUNT, [methodTagKey], 'The number of lines form standard input.' ); -globalStats.registerView(lineCountView); +oc.globalStats.registerView(lineCountView); -const lineLengthView = globalStats.createView( +const lineLengthView = oc.globalStats.createView( 'demo/line_lengths', mLineLengths, - AggregationType.DISTRIBUTION, + oc.AggregationType.DISTRIBUTION, [methodTagKey], 'Groups the lengths of keys in buckets.', [0, 5, 10, 15, 20, 40, 60, 80, 100, 200, 400, 600, 800, 1000] ); -globalStats.registerView(lineLengthView); +oc.globalStats.registerView(lineLengthView); let startTime = new Date(); -let endTime; lineReader.on('line', function (line) { - const tags = new TagMap(); + const tags = new oc.TagMap(); tags.set(methodTagKey, { value: 'REPL' }); tags.set(statusTagKey, { value: 'OK' }); @@ -69,7 +63,7 @@ lineReader.on('line', function (line) { const processedLine = processLine(line); console.log(processedLine); - globalStats.record([{ + oc.globalStats.record([{ measure: mLineLengths, value: processedLine.length }, { @@ -77,12 +71,12 @@ lineReader.on('line', function (line) { value: (new Date()).getTime() - startTime.getTime() }], tags); } catch (err) { - const errTags = new TagMap(); + const errTags = new oc.TagMap(); errTags.set(methodTagKey, { value: 'REPL' }); errTags.set(statusTagKey, { value: 'ERROR' }); errTags.set(errorTagKey, { value: err.message }); - globalStats.record([{ + oc.globalStats.record([{ measure: mLatencyMs, value: (new Date()).getTime() - startTime.getTime() }], errTags); @@ -93,4 +87,4 @@ lineReader.on('line', function (line) { function processLine(line) { return line.toUpperCase(); -} \ No newline at end of file +} From 7d33fdb8b8f0831e298d9ed06ab4a55723a7fc58 Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 26 Feb 2020 00:30:52 -0500 Subject: [PATCH 22/66] Fixed linting issue --- packages/opencensus-exporter-azure/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/src/index.ts b/packages/opencensus-exporter-azure/src/index.ts index 5b9c26ad1..4fd23f72a 100644 --- a/packages/opencensus-exporter-azure/src/index.ts +++ b/packages/opencensus-exporter-azure/src/index.ts @@ -1,2 +1,2 @@ export * from './azure-stats'; -export * from './azure-trace'; \ No newline at end of file +export * from './azure-trace'; From 37580391184df3a97006d67a45d06123ebdcfe7e Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 26 Feb 2020 00:31:26 -0500 Subject: [PATCH 23/66] Linting issues fixed. Better error handling. --- .../src/azure-stats.ts | 60 +++++++++++++------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index c36b30aa3..8122f774e 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -66,11 +66,18 @@ export interface AzureStatsExporterOptions extends ExporterConfig { } +export class IllegalOptionsError extends Error { + constructor(message: string) { + super(message); + this.name = 'IllegalOptionsError'; + } +} + /** * Configuration defaults for an AzureStatsExporter. */ -const AzureStatsExporterDefaults: AzureStatsExporterOptions = { - instrumentationKey: undefined, +const AZURE_STATS_EXPORTER_DEFAULTS: AzureStatsExporterOptions = { + instrumentationKey: 'undefined', periodInMillis: 60000, prefix: 'OpenCensus', logger: logger.logger() @@ -100,12 +107,18 @@ export class AzureStatsExporter implements StatsEventListener { // Verify that the options passed in have actual values (no undefined values) // for require parameters. if (options.instrumentationKey === undefined) { - AzureStatsExporterDefaults.logger.error('You must specify an Instrumentation Key to create an Azure Monitor Stats Exporter.'); + logger.logger().error('You must specify an instrumentation key.'); + throw new IllegalOptionsError('You must provide an instrumentation key.'); } + if (options.instrumentationKey === '') { + logger.logger().error('You must specify a valid instrumentation key.'); + throw new IllegalOptionsError('You must provide a valid instrumentation key.'); + } + // Start with the default options, and overwrite the defaults with any options specified // in the constructor's options parameter. - this.options = { ...AzureStatsExporterDefaults, ...options }; + this.options = { ...AZURE_STATS_EXPORTER_DEFAULTS, ...options }; // Configure the Application Insights SDK to use the Instrumentation Key from our options. setupAppInsights(this.options.instrumentationKey); @@ -159,17 +172,30 @@ export class AzureStatsExporter implements StatsEventListener { this.statsParams.recordedData[view.name].push(snapshot); } }); - var newMetric: Contracts.MetricTelemetry; - newMetric.name = measurement.measure.name; - newMetric.value = measurement.value; - var mapIter = tags.entries(); - var tags_string:{ - [key: string]: string; - }; - for(var i =0; i < tags.size; i++){ - tags_string = tags_string + tags[i] as {key: string}; - } - newMetric.properties = tags_string; + let newMetric: Contracts.MetricTelemetry; + newMetric = { + name: measurement.measure.name, + value: measurement.value + }; + + // let tagMapAsStrings: { + // [key: string]: string; + // }[] = []; + + // for (let key in tags.keys()) { + // tagMapAsStrings.push( + + // ) + // } + + // let mapIter = tags.entries(); + // let tagsString: { + // [key: string]: string; + // } = {}; + // for(let i =0; i < tags.size; i++){ + // tagsString = tagsString + tags[i] as {key: string}; + // } + // newMetric.properties = tagsString; telemetry.trackMetric(newMetric); } @@ -242,9 +268,9 @@ export class AzureStatsExporter implements StatsEventListener { // TODO: Aggregate metrics. for (const metric of metricList) { switch (metric.descriptor.type) { - + default: } } } -} \ No newline at end of file +} From 6d670b3323df0743c2aa482e68f7716b5b88794d Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 26 Feb 2020 00:31:40 -0500 Subject: [PATCH 24/66] Added mocha chai and basic tests. --- .../test/test-stats-exporter.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 packages/opencensus-exporter-azure/test/test-stats-exporter.ts diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts new file mode 100644 index 000000000..597ca8858 --- /dev/null +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -0,0 +1,37 @@ +import { + AzureStatsExporter, + AzureStatsExporterOptions, + IllegalOptionsError +} from '../src/azure-stats'; +import { + describe, + it +} from 'mocha'; +import { + assert +} from 'chai'; +import * as sinon from 'sinon'; + +describe('Exporter Construction', () => { + const sandbox = sinon.createSandbox(); + + it('Throws an error if no instrumentation key is provided.', () => { + const options: AzureStatsExporterOptions = { + instrumentationKey: undefined + }; + assert.throws(() => { + // This should throw an error. + const exporter = new AzureStatsExporter(options); + }, IllegalOptionsError, 'You must provide an instrumentation key.') + }); + + it('Throws an error if the provided instrumentation key is an empty string.', () => { + const options: AzureStatsExporterOptions = { + instrumentationKey: '' + }; + assert.throws(() => { + // This should throw an error. + const exporter = new AzureStatsExporter(options); + }, IllegalOptionsError, 'You must provide a valid instrumentation key.'); + }); +}); From ac2d1db4a5c917655e317e7c3187763fdf5fac0c Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Wed, 26 Feb 2020 10:44:44 -0500 Subject: [PATCH 25/66] Added a mock logger and new describes --- .../test/test-stats-exporter.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index 597ca8858..310afbb03 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -1,3 +1,6 @@ +import { + Logger +} from '@opencensus/core'; import { AzureStatsExporter, AzureStatsExporterOptions, @@ -12,6 +15,28 @@ import { } from 'chai'; import * as sinon from 'sinon'; +class MockLogger implements Logger { + level?: string; + // tslint:disable-next-line:no-any + debugBuffer: any[] = []; + + cleanAll() { + this.debugBuffer = []; + } + + // tslint:disable-next-line:no-any + debug(message: string, ...args: any[]) { + this.debugBuffer.push(...args); + } + + // tslint:disable-next-line:no-any + error(...args: any[]) {} + // tslint:disable-next-line:no-any + warn(...args: any[]) {} + // tslint:disable-next-line:no-any + info(...args: any[]) {} + } + describe('Exporter Construction', () => { const sandbox = sinon.createSandbox(); @@ -35,3 +60,11 @@ describe('Exporter Construction', () => { }, IllegalOptionsError, 'You must provide a valid instrumentation key.'); }); }); + +describe('Single-Value Stats Exporting', () => { + +}); + +describe('Batched Stats Exporter', () => { + +}); From 01213272202573161fe6b661c68b0ed76fdbd728 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Fri, 28 Feb 2020 12:20:45 -0500 Subject: [PATCH 26/66] Added tests to verify proper construction --- .../test/test-stats-exporter.ts | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index 310afbb03..64afab84c 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -19,9 +19,11 @@ class MockLogger implements Logger { level?: string; // tslint:disable-next-line:no-any debugBuffer: any[] = []; + errorMessagesBuffer: any[] = []; cleanAll() { this.debugBuffer = []; + this.errorMessagesBuffer = []; } // tslint:disable-next-line:no-any @@ -30,24 +32,39 @@ class MockLogger implements Logger { } // tslint:disable-next-line:no-any - error(...args: any[]) {} + error(message: string, ...args: any[]) { + this.errorMessagesBuffer.push(message); + } // tslint:disable-next-line:no-any warn(...args: any[]) {} // tslint:disable-next-line:no-any info(...args: any[]) {} - } +} describe('Exporter Construction', () => { - const sandbox = sinon.createSandbox(); + const UNDEFINED_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide an instrumentation key.'; + const INVALID_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide a valid instrumentation key.'; + + let exporter: AzureStatsExporter; + const mockLogger = new MockLogger(); + + afterEach(() => { + if (exporter) exporter.stop(); + mockLogger.cleanAll(); + }); it('Throws an error if no instrumentation key is provided.', () => { const options: AzureStatsExporterOptions = { - instrumentationKey: undefined + instrumentationKey: undefined, + logger: mockLogger }; assert.throws(() => { // This should throw an error. - const exporter = new AzureStatsExporter(options); - }, IllegalOptionsError, 'You must provide an instrumentation key.') + exporter = new AzureStatsExporter(options); + }, IllegalOptionsError, UNDEFINED_INSTRUMENTATION_KEY_ERROR_MSG) + assert(mockLogger.debugBuffer.length === 0, 'An unexpected debug log occured.'); + assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); + assert(mockLogger.errorMessagesBuffer[0] === UNDEFINED_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); }); it('Throws an error if the provided instrumentation key is an empty string.', () => { @@ -56,8 +73,11 @@ describe('Exporter Construction', () => { }; assert.throws(() => { // This should throw an error. - const exporter = new AzureStatsExporter(options); - }, IllegalOptionsError, 'You must provide a valid instrumentation key.'); + exporter = new AzureStatsExporter(options); + }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG); + assert(mockLogger.debugBuffer.length === 0, 'An unexpected debug log occured.'); + assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); + assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); }); }); From 1dd86094cffe7938fc80ab3b505ee19c20398b7a Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Fri, 28 Feb 2020 12:20:59 -0500 Subject: [PATCH 27/66] Fixed improper error logging --- .../opencensus-exporter-azure/src/azure-stats.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 8122f774e..28bdb509b 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -104,22 +104,23 @@ export class AzureStatsExporter implements StatsEventListener { * @param options Specific configuration information to use when constructing the exporter. */ constructor(options: AzureStatsExporterOptions) { + // Start with the default options, and overwrite the defaults with any options specified + // in the constructor's options parameter. We do this before validating input so that + // the logger gets configured with the user specified logger, if provided. + this.options = { ...AZURE_STATS_EXPORTER_DEFAULTS, ...options }; + // Verify that the options passed in have actual values (no undefined values) // for require parameters. if (options.instrumentationKey === undefined) { - logger.logger().error('You must specify an instrumentation key.'); + this.options.logger.error('You must provide an instrumentation key.'); throw new IllegalOptionsError('You must provide an instrumentation key.'); } if (options.instrumentationKey === '') { - logger.logger().error('You must specify a valid instrumentation key.'); + this.options.logger.error('You must provide a valid instrumentation key.'); throw new IllegalOptionsError('You must provide a valid instrumentation key.'); } - // Start with the default options, and overwrite the defaults with any options specified - // in the constructor's options parameter. - this.options = { ...AZURE_STATS_EXPORTER_DEFAULTS, ...options }; - // Configure the Application Insights SDK to use the Instrumentation Key from our options. setupAppInsights(this.options.instrumentationKey); } From d79872ddfb58467945f0ab647fdbd6e93477c7ef Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Fri, 28 Feb 2020 14:28:33 -0500 Subject: [PATCH 28/66] Changed require statement to import --- packages/opencensus-exporter-azure/src/azure-stats.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 28bdb509b..e207a5831 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -14,15 +14,17 @@ import { AggregationData, } from '@opencensus/core'; -import Contracts = require("../node_modules/applicationinsights/out/Declarations/Contracts/TelemetryTypes/MetricTelemetry"); - import { start as startAppInsights, setup as setupAppInsights, dispose as disposeAppInsights, - defaultClient as telemetry + defaultClient as telemetry, } from 'applicationinsights'; +import { + MetricTelemetry +} from 'applicationinsights/out/Declarations/Contracts'; + export interface StatsParams { registeredViews: View[]; registeredMeasures: Measure[]; @@ -173,7 +175,7 @@ export class AzureStatsExporter implements StatsEventListener { this.statsParams.recordedData[view.name].push(snapshot); } }); - let newMetric: Contracts.MetricTelemetry; + let newMetric: MetricTelemetry; newMetric = { name: measurement.measure.name, value: measurement.value From 70e1202e0dd12bf56168133547c0b795cdf8baa9 Mon Sep 17 00:00:00 2001 From: ahnivert Date: Fri, 28 Feb 2020 15:27:33 -0500 Subject: [PATCH 29/66] Single-Value Stats Export Test --- .../test/test-stats-exporter.ts | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index 310afbb03..4162af094 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -1,5 +1,15 @@ import { - Logger + Logger, + globalStats, + MeasureUnit, + Metrics, + Measure, + AggregationType, + TagKey, + TagValue, + TagMap, + View, + Measurement } from '@opencensus/core'; import { AzureStatsExporter, @@ -62,6 +72,71 @@ describe('Exporter Construction', () => { }); describe('Single-Value Stats Exporting', () => { + const mockLogger = new MockLogger(); + let exporterOptions: AzureStatsExporterOptions; + let exporter: AzureStatsExporter; + let measure: Measure; + let measurement: Measurement; + let aggregationType: AggregationType; + const tagKeys = [{ name: 'testKey1' }, { name: 'testKey2' }]; + const tagValues = [{ value: 'testValue1' }, { value: 'testValue2' }]; + const tagMap = new TagMap(); + tagMap.set(tagKeys[0], tagValues[0]); + tagMap.set(tagKeys[1], tagValues[1]); + + before(() => { + exporterOptions = { + instrumentationKey: '', + logger: mockLogger, + }; + exporter = new AzureStatsExporter(exporterOptions); + }); + + afterEach(() => { + exporter.stop(); + mockLogger.cleanAll(); + }); + + it('should not export for empty data', () => { + globalStats.registerExporter(exporter); + assert.strictEqual(mockLogger.debugBuffer.length, 0); + }); + + it('should export the data', async () => { + const METRIC_NAME = 'metric-name'; + const METRIC_DESCRIPTION = 'metric-description'; + const UNIT = MeasureUnit.UNIT; + const METRIC_OPTIONS = { + description: METRIC_DESCRIPTION, + unit: UNIT, + labelKeys: [{ key: 'code', description: 'desc' }], + }; + + let views: View[] = [ + globalStats.createView( + 'test/firstView', + measure, + AggregationType.LAST_VALUE, + tagKeys, + 'The first view' + ), + globalStats.createView( + 'test/secondView', + measure, + AggregationType.LAST_VALUE, + tagKeys, + 'The second view' + ) + ]; + let registeredViews: View[] = []; + let recordedMeasurements: Measurement[] = []; + let map: Map; + + const metricRegistry = Metrics.getMetricRegistry(); + exporter.onRecord(views, measurement, map); + + + }); }); From 9dd6e7078ab0b79dbc815642bf432284aed04536 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Fri, 28 Feb 2020 15:34:59 -0500 Subject: [PATCH 30/66] Style fixes --- packages/opencensus-exporter-azure/repl.ts | 5 +++-- packages/opencensus-exporter-azure/src/azure-stats.ts | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/opencensus-exporter-azure/repl.ts b/packages/opencensus-exporter-azure/repl.ts index 68b693347..9040077dc 100644 --- a/packages/opencensus-exporter-azure/repl.ts +++ b/packages/opencensus-exporter-azure/repl.ts @@ -5,11 +5,12 @@ const oc = require('@opencensus/core'); const fs = require('fs'); const readline = require('readline'); -const AzureStatsExporter = require('./build/src/azure-stats'); +const statsExporterModule = require('./build/src/azure-stats'); -const exporter = new AzureStatsExporter({ +const exporter = new statsExporterModule.AzureStatsExporter({ instrumentationKey: 'e3efe46f-5f1e-4b96-80de-60667b680b23' }); +exporter.start(); oc.globalStats.registerExporter(exporter); const stream = fs.createReadStream('./test/test.txt'); diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index e207a5831..6da5da97c 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -199,7 +199,8 @@ export class AzureStatsExporter implements StatsEventListener { // tagsString = tagsString + tags[i] as {key: string}; // } // newMetric.properties = tagsString; - telemetry.trackMetric(newMetric); + telemetry.trackMetric(newMetric); + this.options.logger.debug('Tracked metric: ', newMetric); } // var newMetric: Contracts.MetricTelemetry; From b4c601df3ce83f9638533fe7106913a85ab2fc5b Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 2 Mar 2020 06:33:36 -0500 Subject: [PATCH 31/66] Reorganized tests. --- packages/opencensus-exporter-azure/repl.ts | 5 ++- packages/opencensus-exporter-azure/test.txt | 34 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 packages/opencensus-exporter-azure/test.txt diff --git a/packages/opencensus-exporter-azure/repl.ts b/packages/opencensus-exporter-azure/repl.ts index 9040077dc..404302f1a 100644 --- a/packages/opencensus-exporter-azure/repl.ts +++ b/packages/opencensus-exporter-azure/repl.ts @@ -10,10 +10,9 @@ const statsExporterModule = require('./build/src/azure-stats'); const exporter = new statsExporterModule.AzureStatsExporter({ instrumentationKey: 'e3efe46f-5f1e-4b96-80de-60667b680b23' }); -exporter.start(); oc.globalStats.registerExporter(exporter); -const stream = fs.createReadStream('./test/test.txt'); +const stream = fs.createReadStream('./test.txt'); const lineReader = readline.createInterface({ input: stream }); // Configure OpenCensus Telemetry Tracking @@ -88,4 +87,4 @@ lineReader.on('line', function (line) { function processLine(line) { return line.toUpperCase(); -} +} \ No newline at end of file diff --git a/packages/opencensus-exporter-azure/test.txt b/packages/opencensus-exporter-azure/test.txt new file mode 100644 index 000000000..54dec1fad --- /dev/null +++ b/packages/opencensus-exporter-azure/test.txt @@ -0,0 +1,34 @@ +You know what, Kelly? This is the real world. Not The Real World: Scranton. +Oh my God, this is super weird. +When Ryan had two girlfriends, he used to take me to some diner in Hazelton just so the other girl wouldn't see. +Through these blinds is where I first saw you, and you had all these boxes, and I thought you were the prettiest mover I had ever seen. +And I was sitting at this desk when I called you to tell you that I had herpes and that I was still in love with you and you said that it was over, and that you didn't love me. +Thank goodness none of that was true. +Including the herpes. +Dunder-Mifflin is the big picture! +Can't you understand that? No, you can't. +You're too young. +Ryan... has never made a sale. +And he started a fire trying to make a cheesy pita. +And everybody thinks he's a tease. +Well you know what? He doesn't know anything, and neither do you. +[walks out] SO SUCK ON THAT! +Do I have a special someone? +Uh well, yeah of course. +A bunch of 'em. My employees. +If I had to choose between a one-night-stand with some stupid cow I pick-up in a bar, and these people? +I'd pick them every time. +Because with them, it is an everyday stand and I still know their names in the morning. +This is a little character I like to do [places a green turban with a yellow feather on his head], it is, uh, loosely based on Karnack, one of Carson's classic characters. +[puts an envelope to his head] Here we go. The PLO, the IRA, and the hot dog stand behind the warehouse. +[tears open envelope and pulls out card] +"Name three businesses that have a better health care plans than Dunder Mifflin." +Here's the problem. +There's no open bar because of Jan and it's the reason why comedy clubs have a two drink minimum. +It'll be fine, I just...wish people were going to be drunk. +Well, that was not at all what I expected. +Hoo hoo! Whoo. +My heart's still racing. +I just looked a man in the eyes and I shook his hand. +All the time I was thinking, "I'm sleeping with your wife." +And you know who does that? James freakin' Bond. From 5b1a1c291ac756e8e7f6b9be2a43204fe717b91d Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Mon, 2 Mar 2020 06:34:09 -0500 Subject: [PATCH 32/66] Changed syntax for importing Azure SDK --- .../src/azure-stats.ts | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 6da5da97c..b7acd1daf 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -14,12 +14,7 @@ import { AggregationData, } from '@opencensus/core'; -import { - start as startAppInsights, - setup as setupAppInsights, - dispose as disposeAppInsights, - defaultClient as telemetry, -} from 'applicationinsights'; +import * as ApplicationInsights from 'applicationinsights'; import { MetricTelemetry @@ -124,7 +119,7 @@ export class AzureStatsExporter implements StatsEventListener { } // Configure the Application Insights SDK to use the Instrumentation Key from our options. - setupAppInsights(this.options.instrumentationKey); + ApplicationInsights.setup(this.options.instrumentationKey).start(); } /** @@ -157,11 +152,7 @@ export class AzureStatsExporter implements StatsEventListener { // TODO: Build out the MetricTelemetry object to pass to the SDK. // TODO: Try to break this out into smaller methods so we can clearly see // the inputs and outputs. - onRecord( - views: View[], - measurement: Measurement, - tags: Map - ): void { + onRecord(views: View[], measurement: Measurement, tags: Map): void { const tagValues = [...tags.values()]; views.map(view => { const snapshot = view.getSnapshot(tagValues); @@ -199,7 +190,7 @@ export class AzureStatsExporter implements StatsEventListener { // tagsString = tagsString + tags[i] as {key: string}; // } // newMetric.properties = tagsString; - telemetry.trackMetric(newMetric); + ApplicationInsights.defaultClient.trackMetric(newMetric); this.options.logger.debug('Tracked metric: ', newMetric); } @@ -217,10 +208,6 @@ export class AzureStatsExporter implements StatsEventListener { * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. */ start(): void { - // Start the App Insights SDK. - startAppInsights(); - this.options.logger.info('Started App Insights SDK.'); - // Set a timer using the interval (period) defined in the exporter's options. // Each time the timer ticks, export any data that has been tracked by utilizing // the exporter's export() function. @@ -246,7 +233,7 @@ export class AzureStatsExporter implements StatsEventListener { this.options.logger.info('Clearing export interval.'); // Pass the stop signal on to the App Insights SDK. - disposeAppInsights(); + ApplicationInsights.dispose(); this.options.logger.info('Disposed App Insights SDK.') } From c5dbc19ae5e1c6f69772b8feb3b39550fcd7cb6b Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 2 Mar 2020 07:18:48 -0500 Subject: [PATCH 33/66] Updated exporter to use ConsoleLogger --- packages/opencensus-exporter-azure/repl.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/repl.ts b/packages/opencensus-exporter-azure/repl.ts index 404302f1a..3b4cb9dc4 100644 --- a/packages/opencensus-exporter-azure/repl.ts +++ b/packages/opencensus-exporter-azure/repl.ts @@ -8,7 +8,8 @@ const readline = require('readline'); const statsExporterModule = require('./build/src/azure-stats'); const exporter = new statsExporterModule.AzureStatsExporter({ - instrumentationKey: 'e3efe46f-5f1e-4b96-80de-60667b680b23' + instrumentationKey: 'e3efe46f-5f1e-4b96-80de-60667b680b23', + logger: new oc.logger.ConsoleLogger(process.argv[2] || 'info') }); oc.globalStats.registerExporter(exporter); From 4090472a1050a600eb9dfaf4743c5f0829881968 Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 2 Mar 2020 07:19:02 -0500 Subject: [PATCH 34/66] Moved test input to exist with repl test file --- .../opencensus-exporter-azure/test/test.txt | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 packages/opencensus-exporter-azure/test/test.txt diff --git a/packages/opencensus-exporter-azure/test/test.txt b/packages/opencensus-exporter-azure/test/test.txt deleted file mode 100644 index a9c38d29c..000000000 --- a/packages/opencensus-exporter-azure/test/test.txt +++ /dev/null @@ -1,34 +0,0 @@ -You know what, Kelly? This is the real world. Not The Real World: Scranton. -Oh my God, this is super weird. -When Ryan had two girlfriends, he used to take me to some diner in Hazelton just so the other girl wouldn't see. -Through these blinds is where I first saw you, and you had all these boxes, and I thought you were the prettiest mover I had ever seen. -And I was sitting at this desk when I called you to tell you that I had herpes and that I was still in love with you and you said that it was over, and that you didn't love me. -Thank goodness none of that was true. -Including the herpes. -Dunder-Mifflin is the big picture! -Can't you understand that? No, you can't. -You're too young. -Ryan... has never made a sale. -And he started a fire trying to make a cheesy pita. -And everybody thinks he's a tease. -Well you know what? He doesn't know anything, and neither do you. -[walks out] SO SUCK ON THAT! -Do I have a special someone? -Uh well, yeah of course. -A bunch of 'em. My employees. -If I had to choose between a one-night-stand with some stupid cow I pick-up in a bar, and these people? -I'd pick them every time. -Because with them, it is an everyday stand and I still know their names in the morning. -This is a little character I like to do [places a green turban with a yellow feather on his head], it is, uh, loosely based on Karnack, one of Carson's classic characters. -[puts an envelope to his head] Here we go. The PLO, the IRA, and the hot dog stand behind the warehouse. -[tears open envelope and pulls out card] -"Name three businesses that have a better health care plans than Dunder Mifflin." -Here's the problem. -There's no open bar because of Jan and it's the reason why comedy clubs have a two drink minimum. -It'll be fine, I just...wish people were going to be drunk. -Well, that was not at all what I expected. -Hoo hoo! Whoo. -My heart's still racing. -I just looked a man in the eyes and I shook his hand. -All the time I was thinking, "I'm sleeping with your wife." -And you know who does that? James freakin' Bond. \ No newline at end of file From 7f5505dc9e3de71d6586731b03ccdd5497eb972e Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 2 Mar 2020 07:19:23 -0500 Subject: [PATCH 35/66] Style changes, removal of unecessary comments --- .../src/azure-stats.ts | 41 +++---------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index b7acd1daf..79e01accd 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -130,16 +130,14 @@ export class AzureStatsExporter implements StatsEventListener { // Adds the view to registeredViews array if it doesn't contain yet if (!this.statsParams.registeredViews.find(v => v.name === view.name)) { this.statsParams.registeredViews.push(view); + this.options.logger.debug('New view registered: ' + view.name); } + // Adds the measure to registeredMeasures array if it doesn't contain yet - if ( - !this.statsParams.registeredMeasures.find( - m => m.name === view.measure.name - ) - ) { + if (!this.statsParams.registeredMeasures.find(m => m.name === view.measure.name)) { this.statsParams.registeredMeasures.push(view.measure); + this.options.logger.debug('New metric registered in ' + view.name + ': ' + view.measure.name); } - } /** @@ -149,7 +147,6 @@ export class AzureStatsExporter implements StatsEventListener { * @param tags The tags to which the value is applied. */ // Use the App Insights SDK to track this measurement. - // TODO: Build out the MetricTelemetry object to pass to the SDK. // TODO: Try to break this out into smaller methods so we can clearly see // the inputs and outputs. onRecord(views: View[], measurement: Measurement, tags: Map): void { @@ -172,37 +169,9 @@ export class AzureStatsExporter implements StatsEventListener { value: measurement.value }; - // let tagMapAsStrings: { - // [key: string]: string; - // }[] = []; - - // for (let key in tags.keys()) { - // tagMapAsStrings.push( - - // ) - // } - - // let mapIter = tags.entries(); - // let tagsString: { - // [key: string]: string; - // } = {}; - // for(let i =0; i < tags.size; i++){ - // tagsString = tagsString + tags[i] as {key: string}; - // } - // newMetric.properties = tagsString; ApplicationInsights.defaultClient.trackMetric(newMetric); this.options.logger.debug('Tracked metric: ', newMetric); - } - - // var newMetric: Contracts.MetricTelemetry; - // newMetric.name = measurement.measure.name; - // newMetric.value = measurement.value; - // var mapIter = tags.entries(); - - // newMetric.properties = mapIter.next().value; - - // telemetry.trackMetric(newMetric); - + } /** * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. From 08a8b6bd1601dda556e7c1b1b3a22dd40ab8c690 Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 2 Mar 2020 09:10:43 -0500 Subject: [PATCH 36/66] Refactored construction tests --- .../test/test-stats-exporter.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index ecd4ef9c7..addae8935 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -52,7 +52,6 @@ class MockLogger implements Logger { } describe('Exporter Construction', () => { - const UNDEFINED_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide an instrumentation key.'; const INVALID_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide a valid instrumentation key.'; let exporter: AzureStatsExporter; @@ -71,21 +70,20 @@ describe('Exporter Construction', () => { assert.throws(() => { // This should throw an error. exporter = new AzureStatsExporter(options); - }, IllegalOptionsError, UNDEFINED_INSTRUMENTATION_KEY_ERROR_MSG) - assert(mockLogger.debugBuffer.length === 0, 'An unexpected debug log occured.'); + }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG) assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); - assert(mockLogger.errorMessagesBuffer[0] === UNDEFINED_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); + assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); }); it('Throws an error if the provided instrumentation key is an empty string.', () => { const options: AzureStatsExporterOptions = { - instrumentationKey: '' + instrumentationKey: '', + logger: mockLogger }; assert.throws(() => { // This should throw an error. exporter = new AzureStatsExporter(options); }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG); - assert(mockLogger.debugBuffer.length === 0, 'An unexpected debug log occured.'); assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); }); @@ -106,7 +104,7 @@ describe('Single-Value Stats Exporting', () => { before(() => { exporterOptions = { - instrumentationKey: '', + instrumentationKey: 'fake-instrumentation-key', logger: mockLogger, }; exporter = new AzureStatsExporter(exporterOptions); From f6155520333df9d28422682bf917dcdf967c0790 Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 2 Mar 2020 09:10:54 -0500 Subject: [PATCH 37/66] Consolidated error messages --- packages/opencensus-exporter-azure/src/azure-stats.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 79e01accd..b7bb359ea 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -108,15 +108,10 @@ export class AzureStatsExporter implements StatsEventListener { // Verify that the options passed in have actual values (no undefined values) // for require parameters. - if (options.instrumentationKey === undefined) { - this.options.logger.error('You must provide an instrumentation key.'); - throw new IllegalOptionsError('You must provide an instrumentation key.'); - } - - if (options.instrumentationKey === '') { + if (!options.instrumentationKey) { this.options.logger.error('You must provide a valid instrumentation key.'); throw new IllegalOptionsError('You must provide a valid instrumentation key.'); - } + } // Configure the Application Insights SDK to use the Instrumentation Key from our options. ApplicationInsights.setup(this.options.instrumentationKey).start(); @@ -132,7 +127,7 @@ export class AzureStatsExporter implements StatsEventListener { this.statsParams.registeredViews.push(view); this.options.logger.debug('New view registered: ' + view.name); } - + // Adds the measure to registeredMeasures array if it doesn't contain yet if (!this.statsParams.registeredMeasures.find(m => m.name === view.measure.name)) { this.statsParams.registeredMeasures.push(view.measure); From 3ba3e88704fb106473c9cb2b2b7bc838c1f8b790 Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Wed, 4 Mar 2020 10:42:05 -0500 Subject: [PATCH 38/66] Removing initial repl. Added blackbox script. --- .../bbtest/blackbox.ts | 84 +++++++++++++++++ packages/opencensus-exporter-azure/repl.ts | 91 ------------------- packages/opencensus-exporter-azure/test.txt | 34 ------- 3 files changed, 84 insertions(+), 125 deletions(-) create mode 100644 packages/opencensus-exporter-azure/bbtest/blackbox.ts delete mode 100644 packages/opencensus-exporter-azure/repl.ts delete mode 100644 packages/opencensus-exporter-azure/test.txt diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox.ts b/packages/opencensus-exporter-azure/bbtest/blackbox.ts new file mode 100644 index 000000000..f45b7c6b3 --- /dev/null +++ b/packages/opencensus-exporter-azure/bbtest/blackbox.ts @@ -0,0 +1,84 @@ +// Import Core OpenCensus and our Azure Exporter module. +const OpenCensus = require('@opencensus/core'); +const AzureStats = require('../build/src/azure-stats'); + +// Construct and register an AzureStatsExporter with the OpenCensus library. +const exporter = new AzureStats.AzureStatsExporter({ + instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', + logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info') +}); +OpenCensus.globalStats.registerExporter(exporter); + +// Create a dummy metric. +const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); + +// Create some dummy tags. +const dumbTagKey = { name: 'dumb' }; +const dumberTagKey = { name: 'dumber' }; +const evenDumberTagKey = { name: 'evenDumber' }; +const dumbestTagKey = { name: 'dumbest' }; + +// Create some dummy views. +const sumView = OpenCensus.globalStats.createView( + 'dummy/sumView', + mDummy, + OpenCensus.AggregationType.SUM, + [dumbTagKey], + 'A sum of the dummy measure.' +); +OpenCensus.globalStats.registerView(sumView); + +const distributionView = OpenCensus.globalStats.createView( + 'dummy/distView', + mDummy, + OpenCensus.AggregationType.DISTRIBUTION, + [dumbTagKey, dumberTagKey], + 'A distribution of the dummy measure.', + [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] +); +OpenCensus.globalStats.registerView(distributionView); + +const countView = OpenCensus.globalStats.createView( + 'dummy/countView', + mDummy, + OpenCensus.AggregationType.COUNT, + [dumbTagKey, dumberTagKey, evenDumberTagKey], + 'A count of the dummy measure.' +); +OpenCensus.globalStats.registerView(countView); + +const lastValueView = OpenCensus.globalStats.createView( + 'dummy/lastValueView', + mDummy, + OpenCensus.AggregationType.LAST_VALUE, + [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], + 'The last value of the dummy measure.' +); +OpenCensus.globalStats.registerView(lastValueView); + +// Loop through an arbitrary amount of numbers, and record them as 'metrics'. +for (let i = 0; i < 42; i++) { + // Create the tag map so we can set values for our dummy tags. + const tags = new OpenCensus.TagMap(); + + // Set a value for each. + tags.set(dumbTagKey, { value: 'dumb' }); + tags.set(dumberTagKey, { value: 'dumber' }); + tags.set(evenDumberTagKey, { value: 'evenDumber' }); + tags.set(dumbestTagKey, { value: 'dumbest' }); + + OpenCensus.globalStats.record([{ + measure: mDummy, + value: i + }], tags); + + // Do something special if i is greater than 30 so we have extra things to look for in + // AppInsights. + if (i > 30) { + tags.set(dumbTagKey, { value: 'dumb but over 30' }); + OpenCensus.globalStats.record([{ + measure: mDummy, + value: i + }], tags); + } +} \ No newline at end of file diff --git a/packages/opencensus-exporter-azure/repl.ts b/packages/opencensus-exporter-azure/repl.ts deleted file mode 100644 index 3b4cb9dc4..000000000 --- a/packages/opencensus-exporter-azure/repl.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * This file is a simple Read, Execute, and Print loop to test sending - * metrics to Azure Monitor. - */ -const oc = require('@opencensus/core'); -const fs = require('fs'); -const readline = require('readline'); -const statsExporterModule = require('./build/src/azure-stats'); - -const exporter = new statsExporterModule.AzureStatsExporter({ - instrumentationKey: 'e3efe46f-5f1e-4b96-80de-60667b680b23', - logger: new oc.logger.ConsoleLogger(process.argv[2] || 'info') -}); -oc.globalStats.registerExporter(exporter); - -const stream = fs.createReadStream('./test.txt'); -const lineReader = readline.createInterface({ input: stream }); - -// Configure OpenCensus Telemetry Tracking -const mLatencyMs = oc.globalStats.createMeasureDouble('repl/latency', oc.MeasureUnit.MS, 'The latency in milliseconds per REPL loop.'); -const mLineLengths = oc.globalStats.createMeasureInt64('repl/line_lengths', oc.MeasureUnit.BYTE, 'The distribution of line lengths.'); - -const methodTagKey = { name: 'method' }; -const statusTagKey = { name: 'status' }; -const errorTagKey = { name: 'error' }; - -const latencyView = oc.globalStats.createView( - 'demo/latency', - mLatencyMs, - oc.AggregationType.DISTRIBUTION, - [methodTagKey, statusTagKey, errorTagKey], - 'The distribution of the latencies', - [0, 25, 50, 75, 100, 200, 400, 600, 800, 1000, 2000, 4000, 6000] -); -oc.globalStats.registerView(latencyView); - -const lineCountView = oc.globalStats.createView( - 'demo/lines_in', - mLineLengths, - oc.AggregationType.COUNT, - [methodTagKey], - 'The number of lines form standard input.' -); -oc.globalStats.registerView(lineCountView); - -const lineLengthView = oc.globalStats.createView( - 'demo/line_lengths', - mLineLengths, - oc.AggregationType.DISTRIBUTION, - [methodTagKey], - 'Groups the lengths of keys in buckets.', - [0, 5, 10, 15, 20, 40, 60, 80, 100, 200, 400, 600, 800, 1000] -); -oc.globalStats.registerView(lineLengthView); - -let startTime = new Date(); - -lineReader.on('line', function (line) { - const tags = new oc.TagMap(); - tags.set(methodTagKey, { value: 'REPL' }); - tags.set(statusTagKey, { value: 'OK' }); - - try { - const processedLine = processLine(line); - console.log(processedLine); - - oc.globalStats.record([{ - measure: mLineLengths, - value: processedLine.length - }, { - measure: mLatencyMs, - value: (new Date()).getTime() - startTime.getTime() - }], tags); - } catch (err) { - const errTags = new oc.TagMap(); - errTags.set(methodTagKey, { value: 'REPL' }); - errTags.set(statusTagKey, { value: 'ERROR' }); - errTags.set(errorTagKey, { value: err.message }); - - oc.globalStats.record([{ - measure: mLatencyMs, - value: (new Date()).getTime() - startTime.getTime() - }], errTags); - } - - startTime = new Date(); -}); - -function processLine(line) { - return line.toUpperCase(); -} \ No newline at end of file diff --git a/packages/opencensus-exporter-azure/test.txt b/packages/opencensus-exporter-azure/test.txt deleted file mode 100644 index 54dec1fad..000000000 --- a/packages/opencensus-exporter-azure/test.txt +++ /dev/null @@ -1,34 +0,0 @@ -You know what, Kelly? This is the real world. Not The Real World: Scranton. -Oh my God, this is super weird. -When Ryan had two girlfriends, he used to take me to some diner in Hazelton just so the other girl wouldn't see. -Through these blinds is where I first saw you, and you had all these boxes, and I thought you were the prettiest mover I had ever seen. -And I was sitting at this desk when I called you to tell you that I had herpes and that I was still in love with you and you said that it was over, and that you didn't love me. -Thank goodness none of that was true. -Including the herpes. -Dunder-Mifflin is the big picture! -Can't you understand that? No, you can't. -You're too young. -Ryan... has never made a sale. -And he started a fire trying to make a cheesy pita. -And everybody thinks he's a tease. -Well you know what? He doesn't know anything, and neither do you. -[walks out] SO SUCK ON THAT! -Do I have a special someone? -Uh well, yeah of course. -A bunch of 'em. My employees. -If I had to choose between a one-night-stand with some stupid cow I pick-up in a bar, and these people? -I'd pick them every time. -Because with them, it is an everyday stand and I still know their names in the morning. -This is a little character I like to do [places a green turban with a yellow feather on his head], it is, uh, loosely based on Karnack, one of Carson's classic characters. -[puts an envelope to his head] Here we go. The PLO, the IRA, and the hot dog stand behind the warehouse. -[tears open envelope and pulls out card] -"Name three businesses that have a better health care plans than Dunder Mifflin." -Here's the problem. -There's no open bar because of Jan and it's the reason why comedy clubs have a two drink minimum. -It'll be fine, I just...wish people were going to be drunk. -Well, that was not at all what I expected. -Hoo hoo! Whoo. -My heart's still racing. -I just looked a man in the eyes and I shook his hand. -All the time I was thinking, "I'm sleeping with your wife." -And you know who does that? James freakin' Bond. From 43fd74ecd4356c2bdbe0db50d00dbe133855c0ca Mon Sep 17 00:00:00 2001 From: ahnivert Date: Wed, 4 Mar 2020 11:22:24 -0500 Subject: [PATCH 39/66] Testing coverage --- .../src/azure-stats.ts | 13 +++++-- .../test/test-stats-exporter.ts | 39 ++++++++++++------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index b7bb359ea..32ab423b0 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -145,7 +145,7 @@ export class AzureStatsExporter implements StatsEventListener { // TODO: Try to break this out into smaller methods so we can clearly see // the inputs and outputs. onRecord(views: View[], measurement: Measurement, tags: Map): void { - const tagValues = [...tags.values()]; + const tagValues = [...(tags.values())]; views.map(view => { const snapshot = view.getSnapshot(tagValues); // Check if there is no data for the current view @@ -164,10 +164,17 @@ export class AzureStatsExporter implements StatsEventListener { value: measurement.value }; - ApplicationInsights.defaultClient.trackMetric(newMetric); - this.options.logger.debug('Tracked metric: ', newMetric); + + this.exportSingleMetric(newMetric); + // ApplicationInsights.defaultClient.trackMetric(newMetric); + // this.options.logger.debug('Tracked metric: ', newMetric); } + exportSingleMetric(metric: MetricTelemetry){ + ApplicationInsights.defaultClient.trackMetric(metric); + this.options.logger.debug('Tracked metric: ',metric); + } + /** * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. */ diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index addae8935..017de7253 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -1,15 +1,16 @@ import { Logger, - globalStats, MeasureUnit, Metrics, + globalStats, Measure, AggregationType, TagKey, TagValue, TagMap, View, - Measurement + Measurement, + MeasureType } from '@opencensus/core'; import { AzureStatsExporter, @@ -89,6 +90,8 @@ describe('Exporter Construction', () => { }); }); +//Sends simple metric to onRecord method +//Checks Logger and hopefully telemetry object describe('Single-Value Stats Exporting', () => { const mockLogger = new MockLogger(); let exporterOptions: AzureStatsExporterOptions; @@ -98,9 +101,14 @@ describe('Single-Value Stats Exporting', () => { let aggregationType: AggregationType; const tagKeys = [{ name: 'testKey1' }, { name: 'testKey2' }]; const tagValues = [{ value: 'testValue1' }, { value: 'testValue2' }]; - const tagMap = new TagMap(); - tagMap.set(tagKeys[0], tagValues[0]); - tagMap.set(tagKeys[1], tagValues[1]); + + const measureDouble = globalStats.createMeasureDouble( + 'opencensus.io/test/double', + MeasureUnit.UNIT, + 'Measure Double' + ); + const measurement1: Measurement = { measure: measureDouble, value: 25 }; + let stub; before(() => { exporterOptions = { @@ -108,11 +116,14 @@ describe('Single-Value Stats Exporting', () => { logger: mockLogger, }; exporter = new AzureStatsExporter(exporterOptions); + stub = sinon.stub(exporter, "exportSingleMetric"); }); afterEach(() => { exporter.stop(); mockLogger.cleanAll(); + globalStats.clear(); + stub.resetBehavior(); }); it('should not export for empty data', () => { @@ -123,36 +134,38 @@ describe('Single-Value Stats Exporting', () => { it('should export the data', async () => { const METRIC_NAME = 'metric-name'; const METRIC_DESCRIPTION = 'metric-description'; - const UNIT = MeasureUnit.UNIT; const METRIC_OPTIONS = { description: METRIC_DESCRIPTION, - unit: UNIT, labelKeys: [{ key: 'code', description: 'desc' }], }; let views: View[] = [ globalStats.createView( 'test/firstView', - measure, + measureDouble, AggregationType.LAST_VALUE, tagKeys, 'The first view' ), globalStats.createView( 'test/secondView', - measure, + measureDouble, AggregationType.LAST_VALUE, tagKeys, 'The second view' ) ]; - let registeredViews: View[] = []; - let recordedMeasurements: Measurement[] = []; - let map: Map; + let map = new Map(); //Map; + map.set(tagKeys[0], tagValues[0]); + map.set(tagKeys[1], tagValues[1]); const metricRegistry = Metrics.getMetricRegistry(); - exporter.onRecord(views, measurement, map); + const gauge = metricRegistry.addInt64Gauge(METRIC_NAME, METRIC_OPTIONS); + gauge.getDefaultTimeSeries().add(100); + await exporter.onRecord(views, measurement1, map); + // assert.strictEqual(mockLogger.debugBuffer.length, 1); + assert(stub.called,"Application Insights SDk was not called"); }); From f237d8f7c22b9089b0d9c970771b3ecf84b581f6 Mon Sep 17 00:00:00 2001 From: jwlong Date: Fri, 6 Mar 2020 11:51:05 -0500 Subject: [PATCH 40/66] Greatly simplified exporter and tests. --- .../src/azure-stats.ts | 131 +++++++++--------- .../test/test-stats-exporter.ts | 76 +++------- 2 files changed, 79 insertions(+), 128 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 32ab423b0..f321989fa 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -111,10 +111,9 @@ export class AzureStatsExporter implements StatsEventListener { if (!options.instrumentationKey) { this.options.logger.error('You must provide a valid instrumentation key.'); throw new IllegalOptionsError('You must provide a valid instrumentation key.'); - } + } - // Configure the Application Insights SDK to use the Instrumentation Key from our options. - ApplicationInsights.setup(this.options.instrumentationKey).start(); + this.setupAndStartApplicationInsights(); } /** @@ -122,17 +121,6 @@ export class AzureStatsExporter implements StatsEventListener { * @param view The registered view. */ onRegisterView(view: View): void { - // Adds the view to registeredViews array if it doesn't contain yet - if (!this.statsParams.registeredViews.find(v => v.name === view.name)) { - this.statsParams.registeredViews.push(view); - this.options.logger.debug('New view registered: ' + view.name); - } - - // Adds the measure to registeredMeasures array if it doesn't contain yet - if (!this.statsParams.registeredMeasures.find(m => m.name === view.measure.name)) { - this.statsParams.registeredMeasures.push(view.measure); - this.options.logger.debug('New metric registered in ' + view.name + ': ' + view.measure.name); - } } /** @@ -145,36 +133,16 @@ export class AzureStatsExporter implements StatsEventListener { // TODO: Try to break this out into smaller methods so we can clearly see // the inputs and outputs. onRecord(views: View[], measurement: Measurement, tags: Map): void { - const tagValues = [...(tags.values())]; - views.map(view => { - const snapshot = view.getSnapshot(tagValues); - // Check if there is no data for the current view - if (!this.statsParams.recordedData[view.name]) { - this.statsParams.recordedData[view.name] = [snapshot]; - } else if ( - !this.statsParams.recordedData[view.name].find(s => s === snapshot) - ) { - // Push the snapshot if it hasn't recoreded before - this.statsParams.recordedData[view.name].push(snapshot); - } - }); - let newMetric: MetricTelemetry; - newMetric = { + let newMetric: MetricTelemetry = { name: measurement.measure.name, value: measurement.value }; - this.exportSingleMetric(newMetric); // ApplicationInsights.defaultClient.trackMetric(newMetric); // this.options.logger.debug('Tracked metric: ', newMetric); } - exportSingleMetric(metric: MetricTelemetry){ - ApplicationInsights.defaultClient.trackMetric(metric); - this.options.logger.debug('Tracked metric: ',metric); - } - /** * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. */ @@ -182,16 +150,16 @@ export class AzureStatsExporter implements StatsEventListener { // Set a timer using the interval (period) defined in the exporter's options. // Each time the timer ticks, export any data that has been tracked by utilizing // the exporter's export() function. - this.timer = setInterval(async () => { - try { - await this.export(); - } catch (err) { - if (typeof this.options.onMetricUploadError === 'function') { - this.options.onMetricUploadError(err); - } - } - }, this.options.periodInMillis); - this.options.logger.info('Set export interval to ' + this.options.periodInMillis + ' ms.'); + // this.timer = setInterval(async () => { + // try { + // await this.export(); + // } catch (err) { + // if (typeof this.options.onMetricUploadError === 'function') { + // this.options.onMetricUploadError(err); + // } + // } + // }, this.options.periodInMillis); + // this.options.logger.info('Set export interval to ' + this.options.periodInMillis + ' ms.'); } /** @@ -203,36 +171,61 @@ export class AzureStatsExporter implements StatsEventListener { clearInterval(this.timer); this.options.logger.info('Clearing export interval.'); - // Pass the stop signal on to the App Insights SDK. - ApplicationInsights.dispose(); - this.options.logger.info('Disposed App Insights SDK.') + this.disposeApplicationInsights(); } /** * Polls the Metrics library for all registered metrics and uploads these to Azure Monitor. */ - async export() { - this.options.logger.info('Starting export of metric batch.'); - - // Collect all of the metrics that will need to be exported in this batch. - const metricList: Metric[] = []; - const metricProducerManager: MetricProducerManager = Metrics.getMetricProducerManager(); - - for (const metricProducer of metricProducerManager.getAllMetricProducer()) { - for (const metric of metricProducer.getMetrics()) { - if (metric) { - metricList.push(metric); - } - } - } + // async export() { + // this.options.logger.info('Starting export of metric batch.'); + + // // Collect all of the metrics that will need to be exported in this batch. + // const metricList: Metric[] = []; + // const metricProducerManager: MetricProducerManager = Metrics.getMetricProducerManager(); + + // for (const metricProducer of metricProducerManager.getAllMetricProducer()) { + // for (const metric of metricProducer.getMetrics()) { + // if (metric) { + // metricList.push(metric); + // } + // } + // } + + // // Aggregate each metric before sending them to Azure Monitor. + // // TODO: Aggregate metrics. + // for (const metric of metricList) { + // switch (metric.descriptor.type) { + // default: + // } + // } + // } + + /** + * Uses the Application Insights SDK to export a given MetricTelemetry object + * into Azure Monitor. + * @param metric The MetricTelemetry object to export to Azure Monitor. + */ + private exportSingleMetric(metric: MetricTelemetry){ + ApplicationInsights.defaultClient.trackMetric(metric); + this.options.logger.debug('Tracked metric: ',metric); + } - // Aggregate each metric before sending them to Azure Monitor. - // TODO: Aggregate metrics. - for (const metric of metricList) { - switch (metric.descriptor.type) { - default: - } - } + /** + * Configures setup options and starts an Application Insights SDK client. + */ + private setupAndStartApplicationInsights() { + // Configure the Application Insights SDK to use the Instrumentation Key from our options. + ApplicationInsights.setup(this.options.instrumentationKey).start(); + } + + /** + * Disposes of the active Application Insights SDK client. + */ + private disposeApplicationInsights() { + // Pass the stop signal on to the App Insights SDK. + ApplicationInsights.dispose(); + this.options.logger.info('Disposed App Insights SDK.'); } } diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index 017de7253..d1f14edd3 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -1,16 +1,8 @@ import { Logger, MeasureUnit, - Metrics, globalStats, - Measure, - AggregationType, - TagKey, - TagValue, - TagMap, - View, - Measurement, - MeasureType + Measurement } from '@opencensus/core'; import { AzureStatsExporter, @@ -52,6 +44,10 @@ class MockLogger implements Logger { info(...args: any[]) {} } +/** + * Tests construction of the exporter. + * Specifically, that instrumentation keys are valid. + */ describe('Exporter Construction', () => { const INVALID_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide a valid instrumentation key.'; @@ -93,21 +89,21 @@ describe('Exporter Construction', () => { //Sends simple metric to onRecord method //Checks Logger and hopefully telemetry object describe('Single-Value Stats Exporting', () => { + // Define dependencies for the exporter. const mockLogger = new MockLogger(); let exporterOptions: AzureStatsExporterOptions; + + // Define the exporter itself. let exporter: AzureStatsExporter; - let measure: Measure; - let measurement: Measurement; - let aggregationType: AggregationType; - const tagKeys = [{ name: 'testKey1' }, { name: 'testKey2' }]; - const tagValues = [{ value: 'testValue1' }, { value: 'testValue2' }]; - const measureDouble = globalStats.createMeasureDouble( + // Define the test metric. + const measure = globalStats.createMeasureDouble( 'opencensus.io/test/double', MeasureUnit.UNIT, 'Measure Double' - ); - const measurement1: Measurement = { measure: measureDouble, value: 25 }; + ); + const measurement: Measurement = { measure: measure, value: 25 }; + let stub; before(() => { @@ -126,51 +122,13 @@ describe('Single-Value Stats Exporting', () => { stub.resetBehavior(); }); - it('should not export for empty data', () => { - globalStats.registerExporter(exporter); - assert.strictEqual(mockLogger.debugBuffer.length, 0); - }); - - it('should export the data', async () => { - const METRIC_NAME = 'metric-name'; - const METRIC_DESCRIPTION = 'metric-description'; - const METRIC_OPTIONS = { - description: METRIC_DESCRIPTION, - labelKeys: [{ key: 'code', description: 'desc' }], - }; - - let views: View[] = [ - globalStats.createView( - 'test/firstView', - measureDouble, - AggregationType.LAST_VALUE, - tagKeys, - 'The first view' - ), - globalStats.createView( - 'test/secondView', - measureDouble, - AggregationType.LAST_VALUE, - tagKeys, - 'The second view' - ) - ]; - let map = new Map(); //Map; - map.set(tagKeys[0], tagValues[0]); - map.set(tagKeys[1], tagValues[1]); - - const metricRegistry = Metrics.getMetricRegistry(); - const gauge = metricRegistry.addInt64Gauge(METRIC_NAME, METRIC_OPTIONS); - gauge.getDefaultTimeSeries().add(100); - - await exporter.onRecord(views, measurement1, map); - // assert.strictEqual(mockLogger.debugBuffer.length, 1); - assert(stub.called,"Application Insights SDk was not called"); - + it('Should export a simple metric.', async () => { + exporter.onRecord(undefined, measurement, undefined); + assert(stub.called, 'Application Insights SDk was not called'); }); }); describe('Batched Stats Exporter', () => { - + // TODO: Test batch functinoality once it has been implemented. }); From aa0dce612a9bb67536219564cec54fe4d90b531d Mon Sep 17 00:00:00 2001 From: Jimmy Long Date: Fri, 6 Mar 2020 14:56:05 -0500 Subject: [PATCH 41/66] Comment to help remember a resource. --- packages/opencensus-exporter-azure/src/azure-stats.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index b7bb359ea..6885a89cb 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -221,6 +221,7 @@ export class AzureStatsExporter implements StatsEventListener { // Aggregate each metric before sending them to Azure Monitor. // TODO: Aggregate metrics. + // MetricsExporterThread.cs in Opencensus C# will be helpful when implementing this. for (const metric of metricList) { switch (metric.descriptor.type) { default: From 573749b9b0f9c4b849cb8475df61da434944fb7a Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 25 Mar 2020 10:05:24 -0400 Subject: [PATCH 42/66] Added an additional test --- .../opencensus-exporter-azure/test/test-stats-exporter.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index d1f14edd3..622028fd8 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -84,6 +84,14 @@ describe('Exporter Construction', () => { assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); }); + + it('Attempts to start the exporter if a seemingly valid instrumentation key is provided.', () => { + const options: AzureStatsExporterOptions = { + instrumentationKey: 'seemingly-valid', + logger: mockLogger + }; + assert + }); }); //Sends simple metric to onRecord method From 7197507b234206e829aad8de5008fea4a0963ce8 Mon Sep 17 00:00:00 2001 From: ahnivert Date: Fri, 27 Mar 2020 15:07:16 -0400 Subject: [PATCH 43/66] azure-trace init --- .../src/azure-trace.ts | 121 +++++++++++++++++- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts index d7a374db7..1703e95b8 100644 --- a/packages/opencensus-exporter-azure/src/azure-trace.ts +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -1,23 +1,138 @@ import { Exporter, ExporterConfig, - Span + Span, + Logger, + logger, + View, + Measure, + AggregationData, + ExporterBuffer } from '@opencensus/core'; +import * as ApplicationInsights from 'applicationinsights'; + +export interface TraceParams { + registeredViews: View[]; + registeredMeasures: Measure[]; + recordedData: { [key: string]: AggregationData[] }; +} + export interface AzureTraceExporterOptions extends ExporterConfig { + /** + * The Instrumentation Key found in your application's Azure Monitor Application Insights + * Overview page. Required. + */ + instrumentationKey: string; + + /** + * If specified, this will serve as the logger used by the exporter. + * Optional, default to use whatever logger is registered with OpenCensus. + */ + logger?: Logger; + + /** + * Max size of telemetry batch. + * If a batch exceeds this limit, it is immediately sent and a new batch is started + */ + maxBatchSizeInBytes?: number; + + /** + * How long to batch telemetry for before sending (milliseconds) + */ + maxBatchInterval?: number; + + /** + * If specified, this will override the default OpenCensus prefix of an + * Azure Monitor metric. Optional. + */ + prefix?: string; } +export class IllegalOptionsError extends Error { + constructor(message: string) { + super(message); + this.name = 'IllegalOptionsError'; + } +} + +/** + * Configuration defaults for an AzureTraceExporter. + */ +const AZURE_TRACE_EXPORTER_DEFAULTS: AzureTraceExporterOptions = { + instrumentationKey: 'undefined', + maxBatchSizeInBytes: 10000, + maxBatchInterval: 15000, + prefix: 'OpenCensus', + logger: logger.logger() +} + export class AzureTraceExporter implements Exporter { + private options: AzureTraceExporterOptions; + + private buffer: ExporterBuffer; + + // Define all other exporter variables. + private timer: NodeJS.Timer; + + private traceParams: TraceParams = { + registeredViews: [], + registeredMeasures: [], + recordedData: {}, + }; + + /** + * Configures a new Trace Exporter given a set of options. + * @param options Specific configuration information to use when constructing the exporter. + */ + constructor(config: ExporterConfig, options: AzureTraceExporterOptions) { + // Start with the default options, and overwrite the defaults with any options specified + // in the constructor's options parameter. We do this before validating input so that + // the logger gets configured with the user specified logger, if provided. + this.options = { ...AZURE_TRACE_EXPORTER_DEFAULTS, ...options }; + this.buffer = new ExporterBuffer(this, config); + + // Verify that the options passed in have actual values (no undefined values) + // for require parameters. + if (!options.instrumentationKey) { + this.options.logger.error('You must provide a valid instrumentation key.'); + throw new IllegalOptionsError('You must provide a valid instrumentation key.'); + } + + // Configure the Application Insights SDK to use the Instrumentation Key from our options. + ApplicationInsights.setup(this.options.instrumentationKey).start(); + } publish(spans: Span[]): Promise { - throw new Error("Method not implemented."); + // Iterate over all root spans formating the data the way we want + spans.map((root) => { + const ROOT_STR = `RootSpan: {traceId: ${root.traceId}, spanId: ${ + root.id}, name: ${root.name} }`; + + const SPANS_STR: string[] = root.spans.map( + (span) => [`\t\t{spanId: ${span.id}, name: ${span.name}}`].join( + '\n')); + + const result: string[] = []; + result.push( + ROOT_STR + '\n\tChildSpans:\n' + + `${SPANS_STR.join('\n')}`); + // console.log(`${result}`); + }); + + ApplicationInsights.defaultClient.trackTrace({ + message: "Telemtry trace", + severity: ApplicationInsights.Contracts.SeverityLevel.Information, + properties: spans.map.arguments.result + }); + return Promise.resolve(); } onStartSpan(span: Span): void { throw new Error("Method not implemented."); } onEndSpan(span: Span): void { - throw new Error("Method not implemented."); + this.buffer.addToBuffer(span); } } From 3dbdddd64499ea2b89b3bac49bd0f99da78dad75 Mon Sep 17 00:00:00 2001 From: jwlong Date: Fri, 27 Mar 2020 15:28:45 -0400 Subject: [PATCH 44/66] Planned aggregation algorithm. --- .../src/azure-stats.ts | 88 ++++++++++++------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index f321989fa..ba4c0cc39 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -12,6 +12,7 @@ import { Metrics, Measure, AggregationData, + MetricDescriptorType, } from '@opencensus/core'; import * as ApplicationInsights from 'applicationinsights'; @@ -150,16 +151,16 @@ export class AzureStatsExporter implements StatsEventListener { // Set a timer using the interval (period) defined in the exporter's options. // Each time the timer ticks, export any data that has been tracked by utilizing // the exporter's export() function. - // this.timer = setInterval(async () => { - // try { - // await this.export(); - // } catch (err) { - // if (typeof this.options.onMetricUploadError === 'function') { - // this.options.onMetricUploadError(err); - // } - // } - // }, this.options.periodInMillis); - // this.options.logger.info('Set export interval to ' + this.options.periodInMillis + ' ms.'); + this.timer = setInterval(async () => { + try { + await this.export(); + } catch (err) { + if (typeof this.options.onMetricUploadError === 'function') { + this.options.onMetricUploadError(err); + } + } + }, this.options.periodInMillis); + this.options.logger.info('Set export interval to ' + this.options.periodInMillis + ' ms.'); } /** @@ -177,29 +178,50 @@ export class AzureStatsExporter implements StatsEventListener { /** * Polls the Metrics library for all registered metrics and uploads these to Azure Monitor. */ - // async export() { - // this.options.logger.info('Starting export of metric batch.'); - - // // Collect all of the metrics that will need to be exported in this batch. - // const metricList: Metric[] = []; - // const metricProducerManager: MetricProducerManager = Metrics.getMetricProducerManager(); - - // for (const metricProducer of metricProducerManager.getAllMetricProducer()) { - // for (const metric of metricProducer.getMetrics()) { - // if (metric) { - // metricList.push(metric); - // } - // } - // } - - // // Aggregate each metric before sending them to Azure Monitor. - // // TODO: Aggregate metrics. - // for (const metric of metricList) { - // switch (metric.descriptor.type) { - // default: - // } - // } - // } + async export() { + this.options.logger.info('Starting export of metric batch.'); + + // Collect all of the metrics that will need to be exported in this batch. + const metricList: Metric[] = []; + const metricProducerManager: MetricProducerManager = Metrics.getMetricProducerManager(); + + // According to OpenCensus documentation, MetricProducer.getMetrics() returns a list + // of metrics to be exported, therefore we will use that function to retrieve metrics. + for (const metricProducer of metricProducerManager.getAllMetricProducer()) { + for (const metric of metricProducer.getMetrics()) { + if (metric) { + metricList.push(metric); + } + } + } + + // Aggregate each metric before sending them to Azure Monitor. + // TODO: Aggregate metrics. + for (const metric of metricList) { + switch (metric.descriptor.type) { + case MetricDescriptorType.UNSPECIFIED: + // Log a warning as this type should not be used. + break; + case MetricDescriptorType.GAUGE_INT64: + case MetricDescriptorType.GAUGE_DOUBLE: + // Aggregate these by (averaging, mode, etc) and uploading just the average + break; + case MetricDescriptorType.CUMULATIVE_INT64: + case MetricDescriptorType.CUMULATIVE_DOUBLE: + // Likely these will be aggregated the same as above, but for now I am keeping them + // separate. If same aggregation procedures can be used, we will have all Int64/Doubles + // fall through into the same block. + break; + case MetricDescriptorType.GAUGE_DISTRIBUTION: + // Need to look into how Azure monitor accepts distribution values. + break; + case MetricDescriptorType.CUMULATIVE_DISTRIBUTION: + // Need to look into how Azure monitor accepts distribution values. + break; + default: + } + } + } /** * Uses the Application Insights SDK to export a given MetricTelemetry object From 04dd205cd8937730cf5cbc9bcf23d0c8fbfff4a3 Mon Sep 17 00:00:00 2001 From: jwlong Date: Thu, 2 Apr 2020 11:12:10 -0400 Subject: [PATCH 45/66] Import IllegalOptionsError --- packages/opencensus-exporter-azure/src/azure-trace.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts index 1703e95b8..0519f8ed3 100644 --- a/packages/opencensus-exporter-azure/src/azure-trace.ts +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -11,6 +11,7 @@ import { } from '@opencensus/core'; import * as ApplicationInsights from 'applicationinsights'; +import { IllegalOptionsError } from './azure-stats'; export interface TraceParams { registeredViews: View[]; @@ -50,13 +51,6 @@ export interface AzureTraceExporterOptions extends ExporterConfig { } -export class IllegalOptionsError extends Error { - constructor(message: string) { - super(message); - this.name = 'IllegalOptionsError'; - } -} - /** * Configuration defaults for an AzureTraceExporter. */ From fb74e5e5898f4d69705ec7ffb70c1f975e7def1c Mon Sep 17 00:00:00 2001 From: jwlong Date: Thu, 2 Apr 2020 12:01:23 -0400 Subject: [PATCH 46/66] Isolate aggregation logic into a function --- .../src/azure-stats.ts | 119 +++++++++++++----- 1 file changed, 91 insertions(+), 28 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index ba4c0cc39..92a6d288b 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -27,6 +27,19 @@ export interface StatsParams { recordedData: { [key: string]: AggregationData[] }; } +export enum ExportMode { + SINGLE_VALUE = 0, + BATCH = 1 +} + +export enum AggregationMethod { + AVERAGE = 0, + MIN = 1, + MAX = 2, + SUM = 3, + COUNT = 4 +} + /** * Options for Azure Monitor configuration. */ @@ -38,6 +51,12 @@ export interface AzureStatsExporterOptions extends ExporterConfig { */ instrumentationKey: string; + /** + * If specified, dictates the mode the exporter will function in. + * Optional, defaults to ExportMode.SINGLE_VALUE. + */ + exportMode?: ExportMode; + /** * If specified, defines the number of milliseconds between uploading metrics * to Azure Monitor. Optional, defaults to 60,000 (1 minute). @@ -50,6 +69,12 @@ export interface AzureStatsExporterOptions extends ExporterConfig { */ prefix?: string; + /** + * The aggregation method if batch exporting is to be used. + * Optional, defaults to AggregationMethod.AVERAGE. + */ + aggregationMethod?: AggregationMethod; + /** * If specified, this will serve as the logger used by the exporter. * Optional, default to use whatever logger is registered with OpenCensus. @@ -78,6 +103,8 @@ const AZURE_STATS_EXPORTER_DEFAULTS: AzureStatsExporterOptions = { instrumentationKey: 'undefined', periodInMillis: 60000, prefix: 'OpenCensus', + exportMode: ExportMode.SINGLE_VALUE, + aggregationMethod: AggregationMethod.AVERAGE, logger: logger.logger() } @@ -91,12 +118,6 @@ export class AzureStatsExporter implements StatsEventListener { // Define all other exporter variables. private timer: NodeJS.Timer; - private statsParams: StatsParams = { - registeredViews: [], - registeredMeasures: [], - recordedData: {}, - }; - /** * Configures a new Stats Exporter given a set of options. * @param options Specific configuration information to use when constructing the exporter. @@ -122,8 +143,8 @@ export class AzureStatsExporter implements StatsEventListener { * @param view The registered view. */ onRegisterView(view: View): void { - } - + } + /** * Is called whenever a measure is recorded. * @param views The views related to the measurement. @@ -131,23 +152,26 @@ export class AzureStatsExporter implements StatsEventListener { * @param tags The tags to which the value is applied. */ // Use the App Insights SDK to track this measurement. - // TODO: Try to break this out into smaller methods so we can clearly see - // the inputs and outputs. onRecord(views: View[], measurement: Measurement, tags: Map): void { - let newMetric: MetricTelemetry = { - name: measurement.measure.name, - value: measurement.value - }; + if (this.options.exportMode === ExportMode.SINGLE_VALUE) { + let newMetric: MetricTelemetry = { + name: measurement.measure.name, + value: measurement.value + }; - this.exportSingleMetric(newMetric); - // ApplicationInsights.defaultClient.trackMetric(newMetric); - // this.options.logger.debug('Tracked metric: ', newMetric); - } + this.exportSingleMetric(newMetric); + } + } /** * Creates an Azure Monitor Stats exporter with an AzureStatsExporterOptions. */ start(): void { + // Verify that the exporter is running in batch mode. + if (!this.verifyBatchMode()) { + return; + } + // Set a timer using the interval (period) defined in the exporter's options. // Each time the timer ticks, export any data that has been tracked by utilizing // the exporter's export() function. @@ -168,6 +192,11 @@ export class AzureStatsExporter implements StatsEventListener { * whenever the exporter is not needed anymore. */ stop(): void { + // Verify that the exporter is running in batch mode. + if (!this.verifyBatchMode()) { + return; + } + // Stop the timer. clearInterval(this.timer); this.options.logger.info('Clearing export interval.'); @@ -179,6 +208,11 @@ export class AzureStatsExporter implements StatsEventListener { * Polls the Metrics library for all registered metrics and uploads these to Azure Monitor. */ async export() { + // Verify that the exporter is running in batch mode. + if (!this.verifyBatchMode()) { + return; + } + this.options.logger.info('Starting export of metric batch.'); // Collect all of the metrics that will need to be exported in this batch. @@ -198,13 +232,12 @@ export class AzureStatsExporter implements StatsEventListener { // Aggregate each metric before sending them to Azure Monitor. // TODO: Aggregate metrics. for (const metric of metricList) { + let aggregateValue: number; + console.log(metric); switch (metric.descriptor.type) { - case MetricDescriptorType.UNSPECIFIED: - // Log a warning as this type should not be used. - break; case MetricDescriptorType.GAUGE_INT64: case MetricDescriptorType.GAUGE_DOUBLE: - // Aggregate these by (averaging, mode, etc) and uploading just the average + aggregateValue = this.getMetricAggreation(metric); break; case MetricDescriptorType.CUMULATIVE_INT64: case MetricDescriptorType.CUMULATIVE_DOUBLE: @@ -218,19 +251,49 @@ export class AzureStatsExporter implements StatsEventListener { case MetricDescriptorType.CUMULATIVE_DISTRIBUTION: // Need to look into how Azure monitor accepts distribution values. break; + case MetricDescriptorType.UNSPECIFIED: + // Log a warning as this type should not be used. + break; default: } + + this.exportSingleMetric({ + name: metric.descriptor.name, + value: aggregateValue + }); } } - /** - * Uses the Application Insights SDK to export a given MetricTelemetry object - * into Azure Monitor. - * @param metric The MetricTelemetry object to export to Azure Monitor. + private getMetricAggreation(metric: Metric): T { + switch(this.options.aggregationMethod) { + case AggregationMethod.AVERAGE: + // Metric.TimeSeries is an array of TimeSeries + // Each of these has an array of points + // Need to collect all the points from each timeseries and aggregate them + } + return null; + } + + /** + * Verifies that that exporter is running batch mode. If it is not, + * this method will issue a warning log message. */ - private exportSingleMetric(metric: MetricTelemetry){ + private verifyBatchMode() : boolean { + if (this.options.exportMode !== ExportMode.BATCH) { + this.options.logger.warn('This exporter is not configured to run in batch mode.'); + return false; + } + return true; + } + + /** + * Uses the Application Insights SDK to export a given MetricTelemetry object + * into Azure Monitor. + * @param metric The MetricTelemetry object to export to Azure Monitor. + */ + private exportSingleMetric(metric: MetricTelemetry) { ApplicationInsights.defaultClient.trackMetric(metric); - this.options.logger.debug('Tracked metric: ',metric); + this.options.logger.debug('Tracked metric: ', metric); } /** From ecddd052af54e5ba34928ed09888db5663fca748 Mon Sep 17 00:00:00 2001 From: jwlong Date: Thu, 2 Apr 2020 12:03:08 -0400 Subject: [PATCH 47/66] Functionalize the test. --- .../bbtest/blackbox.ts | 140 +++++++++--------- 1 file changed, 72 insertions(+), 68 deletions(-) diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox.ts b/packages/opencensus-exporter-azure/bbtest/blackbox.ts index f45b7c6b3..ee62d9222 100644 --- a/packages/opencensus-exporter-azure/bbtest/blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/blackbox.ts @@ -1,84 +1,88 @@ // Import Core OpenCensus and our Azure Exporter module. -const OpenCensus = require('@opencensus/core'); -const AzureStats = require('../build/src/azure-stats'); +import OpenCensus = require('@opencensus/core'); +import AzureStats = require('../build/src/azure-stats'); -// Construct and register an AzureStatsExporter with the OpenCensus library. -const exporter = new AzureStats.AzureStatsExporter({ - instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', - logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info') -}); -OpenCensus.globalStats.registerExporter(exporter); +function exportSingleMetrics() { + // Construct and register an AzureStatsExporter with the OpenCensus library. + const exporter = new AzureStats.AzureStatsExporter({ + instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', + logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info') + }); + OpenCensus.globalStats.registerExporter(exporter); -// Create a dummy metric. -const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); + // Create a dummy metric. + const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); -// Create some dummy tags. -const dumbTagKey = { name: 'dumb' }; -const dumberTagKey = { name: 'dumber' }; -const evenDumberTagKey = { name: 'evenDumber' }; -const dumbestTagKey = { name: 'dumbest' }; + // Create some dummy tags. + const dumbTagKey = { name: 'dumb' }; + const dumberTagKey = { name: 'dumber' }; + const evenDumberTagKey = { name: 'evenDumber' }; + const dumbestTagKey = { name: 'dumbest' }; -// Create some dummy views. -const sumView = OpenCensus.globalStats.createView( - 'dummy/sumView', - mDummy, - OpenCensus.AggregationType.SUM, - [dumbTagKey], - 'A sum of the dummy measure.' -); -OpenCensus.globalStats.registerView(sumView); + // Create some dummy views. + const sumView = OpenCensus.globalStats.createView( + 'dummy/sumView', + mDummy, + OpenCensus.AggregationType.SUM, + [dumbTagKey], + 'A sum of the dummy measure.' + ); + OpenCensus.globalStats.registerView(sumView); -const distributionView = OpenCensus.globalStats.createView( - 'dummy/distView', - mDummy, - OpenCensus.AggregationType.DISTRIBUTION, - [dumbTagKey, dumberTagKey], - 'A distribution of the dummy measure.', - [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] -); -OpenCensus.globalStats.registerView(distributionView); + const distributionView = OpenCensus.globalStats.createView( + 'dummy/distView', + mDummy, + OpenCensus.AggregationType.DISTRIBUTION, + [dumbTagKey, dumberTagKey], + 'A distribution of the dummy measure.', + [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] + ); + OpenCensus.globalStats.registerView(distributionView); -const countView = OpenCensus.globalStats.createView( - 'dummy/countView', - mDummy, - OpenCensus.AggregationType.COUNT, - [dumbTagKey, dumberTagKey, evenDumberTagKey], - 'A count of the dummy measure.' -); -OpenCensus.globalStats.registerView(countView); + const countView = OpenCensus.globalStats.createView( + 'dummy/countView', + mDummy, + OpenCensus.AggregationType.COUNT, + [dumbTagKey, dumberTagKey, evenDumberTagKey], + 'A count of the dummy measure.' + ); + OpenCensus.globalStats.registerView(countView); -const lastValueView = OpenCensus.globalStats.createView( - 'dummy/lastValueView', - mDummy, - OpenCensus.AggregationType.LAST_VALUE, - [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], - 'The last value of the dummy measure.' -); -OpenCensus.globalStats.registerView(lastValueView); + const lastValueView = OpenCensus.globalStats.createView( + 'dummy/lastValueView', + mDummy, + OpenCensus.AggregationType.LAST_VALUE, + [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], + 'The last value of the dummy measure.' + ); + OpenCensus.globalStats.registerView(lastValueView); -// Loop through an arbitrary amount of numbers, and record them as 'metrics'. -for (let i = 0; i < 42; i++) { - // Create the tag map so we can set values for our dummy tags. - const tags = new OpenCensus.TagMap(); + // Loop through an arbitrary amount of numbers, and record them as 'metrics'. + for (let i = 0; i < 42; i++) { + // Create the tag map so we can set values for our dummy tags. + const tags = new OpenCensus.TagMap(); - // Set a value for each. - tags.set(dumbTagKey, { value: 'dumb' }); - tags.set(dumberTagKey, { value: 'dumber' }); - tags.set(evenDumberTagKey, { value: 'evenDumber' }); - tags.set(dumbestTagKey, { value: 'dumbest' }); + // Set a value for each. + tags.set(dumbTagKey, { value: 'dumb' }); + tags.set(dumberTagKey, { value: 'dumber' }); + tags.set(evenDumberTagKey, { value: 'evenDumber' }); + tags.set(dumbestTagKey, { value: 'dumbest' }); - OpenCensus.globalStats.record([{ - measure: mDummy, - value: i - }], tags); - - // Do something special if i is greater than 30 so we have extra things to look for in - // AppInsights. - if (i > 30) { - tags.set(dumbTagKey, { value: 'dumb but over 30' }); OpenCensus.globalStats.record([{ measure: mDummy, value: i }], tags); + + // Do something special if i is greater than 30 so we have extra things to look for in + // AppInsights. + if (i > 30) { + tags.set(dumbTagKey, { value: 'dumb but over 30' }); + OpenCensus.globalStats.record([{ + measure: mDummy, + value: i + }], tags); + } } -} \ No newline at end of file +} + +exportSingleMetrics(); From 2312a457c15f0434dacb3627d66e728b51ed66d8 Mon Sep 17 00:00:00 2001 From: jwlong Date: Thu, 2 Apr 2020 12:03:37 -0400 Subject: [PATCH 48/66] Generate several batches of numbers to export. --- .../bbtest/batch_blackbox.ts | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts diff --git a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts new file mode 100644 index 000000000..9b8e21c14 --- /dev/null +++ b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts @@ -0,0 +1,84 @@ +// Import Core OpenCensus and our Azure Exporter module. +import OpenCensus = require('@opencensus/core'); +import AzureStats = require('../src/azure-stats') + +function exportSingleMetrics() { + // Construct and register an AzureStatsExporter with the OpenCensus library. + const exporter = new AzureStats.AzureStatsExporter({ + instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', + logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info'), + periodInMillis: 15000, + exportMode: AzureStats.ExportMode.BATCH + }); + exporter.start(); + OpenCensus.globalStats.registerExporter(exporter); + + // Create a dummy metric. + const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); + + // Create some dummy tags. + const dumbTagKey = { name: 'dumb' }; + const dumberTagKey = { name: 'dumber' }; + const evenDumberTagKey = { name: 'evenDumber' }; + const dumbestTagKey = { name: 'dumbest' }; + + // Create some dummy views. + const sumView = OpenCensus.globalStats.createView( + 'dummy/sumView', + mDummy, + OpenCensus.AggregationType.SUM, + [dumbTagKey], + 'A sum of the dummy measure.' + ); + OpenCensus.globalStats.registerView(sumView); + + const distributionView = OpenCensus.globalStats.createView( + 'dummy/distView', + mDummy, + OpenCensus.AggregationType.DISTRIBUTION, + [dumbTagKey, dumberTagKey], + 'A distribution of the dummy measure.', + [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] + ); + OpenCensus.globalStats.registerView(distributionView); + + const countView = OpenCensus.globalStats.createView( + 'dummy/countView', + mDummy, + OpenCensus.AggregationType.COUNT, + [dumbTagKey, dumberTagKey, evenDumberTagKey], + 'A count of the dummy measure.' + ); + OpenCensus.globalStats.registerView(countView); + + const lastValueView = OpenCensus.globalStats.createView( + 'dummy/lastValueView', + mDummy, + OpenCensus.AggregationType.LAST_VALUE, + [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], + 'The last value of the dummy measure.' + ); + OpenCensus.globalStats.registerView(lastValueView); + + // Loop through an arbitrary amount of numbers, and record them as 'metrics'. + setInterval(() => { + for (let i = 0; i < 50; i++) { + // Create the tag map so we can set values for our dummy tags. + const tags = new OpenCensus.TagMap(); + + // Set a value for each. + tags.set(dumbTagKey, { value: 'dumb' }); + tags.set(dumberTagKey, { value: 'dumber' }); + tags.set(evenDumberTagKey, { value: 'evenDumber' }); + tags.set(dumbestTagKey, { value: 'dumbest' }); + + OpenCensus.globalStats.record([{ + measure: mDummy, + value: Math.floor(Math.random() * Math.floor(45)) + }], tags); + } + }, 5000); + +} + +exportSingleMetrics(); From fdfbfab33956428a4e06642ce3241e7f1ac01dbd Mon Sep 17 00:00:00 2001 From: jwlong Date: Thu, 2 Apr 2020 12:03:37 -0400 Subject: [PATCH 49/66] Testing started on Trace Exporter --- .../bbtest/batch_blackbox.ts | 84 + .../bbtest/blackbox-trace.ts | 90 + .../package-lock.json | 2286 +++++++++++++++++ .../src/azure-trace.ts | 9 +- 4 files changed, 2466 insertions(+), 3 deletions(-) create mode 100644 packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts create mode 100644 packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts diff --git a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts new file mode 100644 index 000000000..9b8e21c14 --- /dev/null +++ b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts @@ -0,0 +1,84 @@ +// Import Core OpenCensus and our Azure Exporter module. +import OpenCensus = require('@opencensus/core'); +import AzureStats = require('../src/azure-stats') + +function exportSingleMetrics() { + // Construct and register an AzureStatsExporter with the OpenCensus library. + const exporter = new AzureStats.AzureStatsExporter({ + instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', + logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info'), + periodInMillis: 15000, + exportMode: AzureStats.ExportMode.BATCH + }); + exporter.start(); + OpenCensus.globalStats.registerExporter(exporter); + + // Create a dummy metric. + const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); + + // Create some dummy tags. + const dumbTagKey = { name: 'dumb' }; + const dumberTagKey = { name: 'dumber' }; + const evenDumberTagKey = { name: 'evenDumber' }; + const dumbestTagKey = { name: 'dumbest' }; + + // Create some dummy views. + const sumView = OpenCensus.globalStats.createView( + 'dummy/sumView', + mDummy, + OpenCensus.AggregationType.SUM, + [dumbTagKey], + 'A sum of the dummy measure.' + ); + OpenCensus.globalStats.registerView(sumView); + + const distributionView = OpenCensus.globalStats.createView( + 'dummy/distView', + mDummy, + OpenCensus.AggregationType.DISTRIBUTION, + [dumbTagKey, dumberTagKey], + 'A distribution of the dummy measure.', + [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] + ); + OpenCensus.globalStats.registerView(distributionView); + + const countView = OpenCensus.globalStats.createView( + 'dummy/countView', + mDummy, + OpenCensus.AggregationType.COUNT, + [dumbTagKey, dumberTagKey, evenDumberTagKey], + 'A count of the dummy measure.' + ); + OpenCensus.globalStats.registerView(countView); + + const lastValueView = OpenCensus.globalStats.createView( + 'dummy/lastValueView', + mDummy, + OpenCensus.AggregationType.LAST_VALUE, + [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], + 'The last value of the dummy measure.' + ); + OpenCensus.globalStats.registerView(lastValueView); + + // Loop through an arbitrary amount of numbers, and record them as 'metrics'. + setInterval(() => { + for (let i = 0; i < 50; i++) { + // Create the tag map so we can set values for our dummy tags. + const tags = new OpenCensus.TagMap(); + + // Set a value for each. + tags.set(dumbTagKey, { value: 'dumb' }); + tags.set(dumberTagKey, { value: 'dumber' }); + tags.set(evenDumberTagKey, { value: 'evenDumber' }); + tags.set(dumbestTagKey, { value: 'dumbest' }); + + OpenCensus.globalStats.record([{ + measure: mDummy, + value: Math.floor(Math.random() * Math.floor(45)) + }], tags); + } + }, 5000); + +} + +exportSingleMetrics(); diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts b/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts new file mode 100644 index 000000000..35489a83e --- /dev/null +++ b/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts @@ -0,0 +1,90 @@ +// Import Core OpenCensus and our Azure Exporter module. +import OpenCensus = require('@opencensus/core'); +import AzureTrace = require('../build/src/azure-trace'); + +function exportSingleMetrics() { + // Construct and register an AzureStatsExporter with the OpenCensus library. + const exporter = new AzureTrace.AzureTraceExporter({ + instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', + logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info') + }); + OpenCensus.globalStats.registerExporter(exporter); + + // Create a dummy metric. + const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); + + // Create some dummy tags. + const dumbTagKey = { name: 'dumb' }; + const dumberTagKey = { name: 'dumber' }; + const evenDumberTagKey = { name: 'evenDumber' }; + const dumbestTagKey = { name: 'dumbest' }; + + const newTrace = OpenCensus.TraceParamsBuilder + + // Create some dummy views. + const sumView = OpenCensus.globalStats.createView( + 'dummy/sumView', + mDummy, + OpenCensus.AggregationType.SUM, + [dumbTagKey], + 'A sum of the dummy measure.' + ); + OpenCensus.globalStats.registerView(sumView); + + const distributionView = OpenCensus.globalStats.createView( + 'dummy/distView', + mDummy, + OpenCensus.AggregationType.DISTRIBUTION, + [dumbTagKey, dumberTagKey], + 'A distribution of the dummy measure.', + [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] + ); + OpenCensus.globalStats.registerView(distributionView); + + const countView = OpenCensus.globalStats.createView( + 'dummy/countView', + mDummy, + OpenCensus.AggregationType.COUNT, + [dumbTagKey, dumberTagKey, evenDumberTagKey], + 'A count of the dummy measure.' + ); + OpenCensus.globalStats.registerView(countView); + + const lastValueView = OpenCensus.globalStats.createView( + 'dummy/lastValueView', + mDummy, + OpenCensus.AggregationType.LAST_VALUE, + [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], + 'The last value of the dummy measure.' + ); + OpenCensus.globalStats.registerView(lastValueView); + + // Loop through an arbitrary amount of numbers, and record them as 'metrics'. + for (let i = 0; i < 42; i++) { + // Create the tag map so we can set values for our dummy tags. + const tags = new OpenCensus.TagMap(); + + // Set a value for each. + tags.set(dumbTagKey, { value: 'dumb' }); + tags.set(dumberTagKey, { value: 'dumber' }); + tags.set(evenDumberTagKey, { value: 'evenDumber' }); + tags.set(dumbestTagKey, { value: 'dumbest' }); + + OpenCensus.globalStats.record([{ + measure: mDummy, + value: i + }], tags); + + // Do something special if i is greater than 30 so we have extra things to look for in + // AppInsights. + if (i > 30) { + tags.set(dumbTagKey, { value: 'dumb but over 30' }); + OpenCensus.globalStats.record([{ + measure: mDummy, + value: i + }], tags); + } + } +} + +exportSingleMetrics(); diff --git a/packages/opencensus-exporter-azure/package-lock.json b/packages/opencensus-exporter-azure/package-lock.json index 79d688192..020e4764d 100644 --- a/packages/opencensus-exporter-azure/package-lock.json +++ b/packages/opencensus-exporter-azure/package-lock.json @@ -4,6 +4,228 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/core": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz", + "integrity": "sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helpers": "^7.8.4", + "@babel/parser": "^7.8.4", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helpers": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", + "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", + "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, "@opencensus/core": { "version": "0.0.19", "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.19.tgz", @@ -16,6 +238,187 @@ "uuid": "^3.2.1" } }, + "@sinonjs/commons": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", + "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.0.tgz", + "integrity": "sha512-atR1J/jRXvQAb47gfzSK8zavXy7BcpnYq21ALon0U99etu99vsir0trzIO3wpeLtW+LLVY6X7EkfVTbjGSH8Ww==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.2.tgz", + "integrity": "sha512-p3yrEVB5F/1wI+835n+X8llOGRgV8+jw5BHQ/cJoLBUXXZ5U8Tr5ApwPc4L4av/vjla48kVPoN0t6dykQm+Rvg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "@sinonjs/formatio": "^5.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@types/chai": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.9.tgz", + "integrity": "sha512-NeXgZj+MFL4izGqA4sapdYzkzQG+MtGra9vhQ58dnmDY++VgJaRUws+aLVV5zRJCYJl/8s9IjMmhiUw1WsKSmw==", + "dev": true + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/continuation-local-storage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/continuation-local-storage/-/continuation-local-storage-3.2.2.tgz", + "integrity": "sha512-aItm+aYPJ4rT1cHmAxO+OdWjSviQ9iB5UKb5f0Uvgln0N4hS2mcDodHtPiqicYBXViUYhqyBjhA5uyOcT+S34Q==", + "requires": { + "@types/node": "*" + }, + "dependencies": { + "@types/node": { + "version": "13.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.6.tgz", + "integrity": "sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==" + } + } + }, + "@types/mocha": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha512-L/Nw/2e5KUaprNJoRA33oly+M8X8n0K+FwLTbYqwTcR14wdPWeRkigBLfSFpN/Asf9ENZTMZwLxjtjeYucAA4Q==", + "dev": true + }, + "@types/node": { + "version": "10.17.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.16.tgz", + "integrity": "sha512-A4283YSA1OmnIivcpy/4nN86YlnKRiQp8PYwI2KdPCONEBN093QTb0gCtERtkLyVNGKKIGazTZ2nAmVzQU51zA==", + "dev": true + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "applicationinsights": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-1.7.2.tgz", + "integrity": "sha512-AtofsH08vrGTMDwXVK6+1wITd8ou9gksFV95JLZo7lVL0wX7/W1qeAZ13DK/6P3VJVsSMJ0sjdVNn98C4XxGvw==", + "requires": { + "cls-hooked": "^4.2.2", + "continuation-local-storage": "^3.2.1", + "diagnostic-channel": "0.2.0", + "diagnostic-channel-publishers": "^0.3.3" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "async-hook-jl": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", + "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "requires": { + "stack-chain": "^1.3.7" + } + }, "async-listener": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", @@ -32,6 +435,214 @@ } } }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "requires": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, "continuation-local-storage": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", @@ -41,6 +652,105 @@ "emitter-listener": "^1.1.1" } }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diagnostic-channel": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz", + "integrity": "sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=", + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "diagnostic-channel-publishers": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.3.tgz", + "integrity": "sha512-qIocRYU5TrGUkBlDDxaziAK1+squ8Yf2Ls4HldL3xxb/jzmWO2Enux7CvevNKYmF2kDXZ9HiRqwjPsjk8L+i2Q==" + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, "emitter-listener": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", @@ -49,25 +759,1601 @@ "shimmer": "^1.2.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-cache-dir": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.0.tgz", + "integrity": "sha512-PtXtQb7IrD8O+h6Cq1dbpJH5NzD8+9keN1zZ0YlpDzl1PwXEJEBj6u1Xa92t1Hwluoozd9TNKul5Hi2iqpsWwg==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "fromentries": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", + "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "dev": true + }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "hasha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", + "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "html-escaper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", + "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "make-dir": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.0.tgz", + "integrity": "sha512-MymHK8UkU0K15Q/zX7uflZgVoRWiTjy0fXE/QjKts6mowUvGxOdPhZ2qj3b0iZdUrNZlW9LAIMFHB4IW+2b3EQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "nise": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.2.tgz", + "integrity": "sha512-ALDnm0pTTyeGdbg5FCpWGd58Nmp3qO8d8x+dU2Fw8lApeJTEBSjkBZZM4S8t6GpKh+czxkfM/TKxpRMroZzwOg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nyc": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.0.tgz", + "integrity": "sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.0", + "js-yaml": "^3.13.1", + "make-dir": "^3.0.0", + "node-preload": "^0.2.0", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "uuid": "^3.3.3", + "yargs": "^15.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz", + "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^16.1.0" + } + }, + "yargs-parser": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=", + "dev": true + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sinon": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.0.tgz", + "integrity": "sha512-c4bREcvuK5VuEGyMW/Oim9I3Rq49Vzb0aMdxouFaA44QCFpilc5LJOugrX+mkrvikbqCimxuK+4cnHVNnLR41g==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/formatio": "^5.0.0", + "@sinonjs/samsam": "^5.0.1", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-chain": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", + "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-node": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz", + "integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", + "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", + "dev": true + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts index 0519f8ed3..ef2ff0cc2 100644 --- a/packages/opencensus-exporter-azure/src/azure-trace.ts +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -68,6 +68,8 @@ export class AzureTraceExporter implements Exporter { private buffer: ExporterBuffer; + private config: ExporterConfig; + // Define all other exporter variables. private timer: NodeJS.Timer; @@ -81,12 +83,13 @@ export class AzureTraceExporter implements Exporter { * Configures a new Trace Exporter given a set of options. * @param options Specific configuration information to use when constructing the exporter. */ - constructor(config: ExporterConfig, options: AzureTraceExporterOptions) { + constructor(options: AzureTraceExporterOptions, config: ExporterConfig) { // Start with the default options, and overwrite the defaults with any options specified // in the constructor's options parameter. We do this before validating input so that // the logger gets configured with the user specified logger, if provided. this.options = { ...AZURE_TRACE_EXPORTER_DEFAULTS, ...options }; this.buffer = new ExporterBuffer(this, config); + this.config = config; // Verify that the options passed in have actual values (no undefined values) // for require parameters. @@ -116,7 +119,7 @@ export class AzureTraceExporter implements Exporter { }); ApplicationInsights.defaultClient.trackTrace({ - message: "Telemtry trace", + message: "Telemetry trace", severity: ApplicationInsights.Contracts.SeverityLevel.Information, properties: spans.map.arguments.result }); @@ -124,7 +127,7 @@ export class AzureTraceExporter implements Exporter { } onStartSpan(span: Span): void { - throw new Error("Method not implemented."); + this.buffer = new ExporterBuffer(this, this.config); } onEndSpan(span: Span): void { this.buffer.addToBuffer(span); From 5079ef3fbfd0760e4392e68ac88cf7b6259e35e3 Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 6 Apr 2020 11:07:21 -0400 Subject: [PATCH 50/66] Fixed imports --- .../bbtest/batch_blackbox.ts | 88 ++++++------------- .../bbtest/blackbox.ts | 4 +- 2 files changed, 28 insertions(+), 64 deletions(-) diff --git a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts index 9b8e21c14..8b4c6cd2c 100644 --- a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts @@ -1,84 +1,48 @@ -// Import Core OpenCensus and our Azure Exporter module. -import OpenCensus = require('@opencensus/core'); -import AzureStats = require('../src/azure-stats') +const AS = require('../build/src/azure-stats'); +const OC = require('@opencensus/core'); -function exportSingleMetrics() { +function exportSingleMetric() { // Construct and register an AzureStatsExporter with the OpenCensus library. - const exporter = new AzureStats.AzureStatsExporter({ + const exporter = new AS.AzureStatsExporter({ instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', - logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info'), - periodInMillis: 15000, - exportMode: AzureStats.ExportMode.BATCH + logger: new OC.logger.ConsoleLogger(process.argv[2] || 'info'), + periodInMillis: 5010, + exportMode: AS.ExportMode.BATCH, + aggregationMethod: AS.AggregationMethod.AVERAGE }); - exporter.start(); - OpenCensus.globalStats.registerExporter(exporter); + OC.globalStats.registerExporter(exporter); // Create a dummy metric. - const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); - - // Create some dummy tags. + const mDummy2 = OC.globalStats.createMeasureInt64('test/dummy2', OC.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); const dumbTagKey = { name: 'dumb' }; - const dumberTagKey = { name: 'dumber' }; - const evenDumberTagKey = { name: 'evenDumber' }; - const dumbestTagKey = { name: 'dumbest' }; - // Create some dummy views. - const sumView = OpenCensus.globalStats.createView( - 'dummy/sumView', - mDummy, - OpenCensus.AggregationType.SUM, + const view = OC.globalStats.createView( + 'dummy/view2', + mDummy2, + OC.AggregationType.SUM, [dumbTagKey], - 'A sum of the dummy measure.' + 'An average of the dummy measure.' ); - OpenCensus.globalStats.registerView(sumView); + OC.globalStats.registerView(view); - const distributionView = OpenCensus.globalStats.createView( - 'dummy/distView', - mDummy, - OpenCensus.AggregationType.DISTRIBUTION, - [dumbTagKey, dumberTagKey], - 'A distribution of the dummy measure.', - [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] - ); - OpenCensus.globalStats.registerView(distributionView); + // Create the tag map so we can set values for our dummy tags. + const tags = new OC.TagMap(); - const countView = OpenCensus.globalStats.createView( - 'dummy/countView', - mDummy, - OpenCensus.AggregationType.COUNT, - [dumbTagKey, dumberTagKey, evenDumberTagKey], - 'A count of the dummy measure.' - ); - OpenCensus.globalStats.registerView(countView); - - const lastValueView = OpenCensus.globalStats.createView( - 'dummy/lastValueView', - mDummy, - OpenCensus.AggregationType.LAST_VALUE, - [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], - 'The last value of the dummy measure.' - ); - OpenCensus.globalStats.registerView(lastValueView); + // Set a value for each. + tags.set(dumbTagKey, { value: 'dumb' }); // Loop through an arbitrary amount of numbers, and record them as 'metrics'. + let counter = 1; setInterval(() => { for (let i = 0; i < 50; i++) { - // Create the tag map so we can set values for our dummy tags. - const tags = new OpenCensus.TagMap(); - - // Set a value for each. - tags.set(dumbTagKey, { value: 'dumb' }); - tags.set(dumberTagKey, { value: 'dumber' }); - tags.set(evenDumberTagKey, { value: 'evenDumber' }); - tags.set(dumbestTagKey, { value: 'dumbest' }); - - OpenCensus.globalStats.record([{ - measure: mDummy, - value: Math.floor(Math.random() * Math.floor(45)) + OC.globalStats.record([{ + measure: mDummy2, + value: i * counter }], tags); } + counter++; }, 5000); } -exportSingleMetrics(); +exportSingleMetric(); diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox.ts b/packages/opencensus-exporter-azure/bbtest/blackbox.ts index ee62d9222..f433e29c2 100644 --- a/packages/opencensus-exporter-azure/bbtest/blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/blackbox.ts @@ -1,6 +1,6 @@ // Import Core OpenCensus and our Azure Exporter module. -import OpenCensus = require('@opencensus/core'); -import AzureStats = require('../build/src/azure-stats'); +const OpenCensus = require('@opencensus/core'); +const AzureStats = require('../build/src/azure-stats'); function exportSingleMetrics() { // Construct and register an AzureStatsExporter with the OpenCensus library. From 1a5ea7ac1e6caeb4fe072ef9325d51a9946f66da Mon Sep 17 00:00:00 2001 From: jwlong Date: Mon, 6 Apr 2020 11:07:44 -0400 Subject: [PATCH 51/66] Added debugging log statements --- .../src/azure-stats.ts | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 92a6d288b..2af61f3ec 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -221,9 +221,17 @@ export class AzureStatsExporter implements StatsEventListener { // According to OpenCensus documentation, MetricProducer.getMetrics() returns a list // of metrics to be exported, therefore we will use that function to retrieve metrics. - for (const metricProducer of metricProducerManager.getAllMetricProducer()) { + const metricProducers = metricProducerManager.getAllMetricProducer() + this.options.logger.debug('There are ' + metricProducers.size.toString() + ' metric producers.') + for (const metricProducer of metricProducers) { + this.options.logger.debug('Processing metrics from: ' + JSON.stringify(metricProducer)); + + const metrics = metricProducer.getMetrics(); + this.options.logger.debug('Metric Producer [' + Object.keys(metricProducer)[0] +'] has ' + metrics.length + ' metrics.'); for (const metric of metricProducer.getMetrics()) { if (metric) { + this.options.logger.debug("Adding metric [" + metric.descriptor.name + "] to metricList."); + this.options.logger.debug(metric.descriptor.name.toUpperCase() + ': ' + JSON.stringify(metric)) metricList.push(metric); } } @@ -232,12 +240,13 @@ export class AzureStatsExporter implements StatsEventListener { // Aggregate each metric before sending them to Azure Monitor. // TODO: Aggregate metrics. for (const metric of metricList) { + this.options.logger.info('Metric: ' + JSON.stringify(metric)); let aggregateValue: number; - console.log(metric); switch (metric.descriptor.type) { case MetricDescriptorType.GAUGE_INT64: case MetricDescriptorType.GAUGE_DOUBLE: - aggregateValue = this.getMetricAggreation(metric); + aggregateValue = this.getMetricAggreation(metric); + this.options.logger.info(aggregateValue); break; case MetricDescriptorType.CUMULATIVE_INT64: case MetricDescriptorType.CUMULATIVE_DOUBLE: @@ -264,13 +273,16 @@ export class AzureStatsExporter implements StatsEventListener { } } - private getMetricAggreation(metric: Metric): T { + private getMetricAggreation(metric: Metric) { switch(this.options.aggregationMethod) { case AggregationMethod.AVERAGE: - // Metric.TimeSeries is an array of TimeSeries - // Each of these has an array of points - // Need to collect all the points from each timeseries and aggregate them - } + const allPoints = metric.timeseries.map(timeseries => timeseries.points).reduce((a, b) => [...a, ...b]); + const allValues : number[] = allPoints.map(point => point.value); + + this.options.logger.debug('Points being logged: ' + allValues); + + return allValues.reduce((a, b) => a + b) / allValues.length; + } return null; } From f48a504f909d07719ef1c01509abda0c85a34284 Mon Sep 17 00:00:00 2001 From: jwlong Date: Tue, 7 Apr 2020 09:50:16 -0400 Subject: [PATCH 52/66] Added dependencies --- .../package-lock.json | 2344 +++++++++++++++++ 1 file changed, 2344 insertions(+) diff --git a/packages/opencensus-exporter-azure/package-lock.json b/packages/opencensus-exporter-azure/package-lock.json index 79d688192..10e3ee7f0 100644 --- a/packages/opencensus-exporter-azure/package-lock.json +++ b/packages/opencensus-exporter-azure/package-lock.json @@ -4,6 +4,206 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/core": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz", + "integrity": "sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helpers": "^7.8.4", + "@babel/parser": "^7.8.4", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helpers": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", + "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.4", + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", + "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, "@opencensus/core": { "version": "0.0.19", "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.19.tgz", @@ -16,6 +216,179 @@ "uuid": "^3.2.1" } }, + "@sinonjs/commons": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", + "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.0.tgz", + "integrity": "sha512-atR1J/jRXvQAb47gfzSK8zavXy7BcpnYq21ALon0U99etu99vsir0trzIO3wpeLtW+LLVY6X7EkfVTbjGSH8Ww==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.2.tgz", + "integrity": "sha512-p3yrEVB5F/1wI+835n+X8llOGRgV8+jw5BHQ/cJoLBUXXZ5U8Tr5ApwPc4L4av/vjla48kVPoN0t6dykQm+Rvg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "@sinonjs/formatio": "^5.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@types/chai": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.9.tgz", + "integrity": "sha512-NeXgZj+MFL4izGqA4sapdYzkzQG+MtGra9vhQ58dnmDY++VgJaRUws+aLVV5zRJCYJl/8s9IjMmhiUw1WsKSmw==", + "dev": true + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/continuation-local-storage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/continuation-local-storage/-/continuation-local-storage-3.2.2.tgz", + "integrity": "sha512-aItm+aYPJ4rT1cHmAxO+OdWjSviQ9iB5UKb5f0Uvgln0N4hS2mcDodHtPiqicYBXViUYhqyBjhA5uyOcT+S34Q==", + "requires": { + "@types/node": "*" + } + }, + "@types/mocha": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha512-L/Nw/2e5KUaprNJoRA33oly+M8X8n0K+FwLTbYqwTcR14wdPWeRkigBLfSFpN/Asf9ENZTMZwLxjtjeYucAA4Q==", + "dev": true + }, + "@types/node": { + "version": "10.17.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.16.tgz", + "integrity": "sha512-A4283YSA1OmnIivcpy/4nN86YlnKRiQp8PYwI2KdPCONEBN093QTb0gCtERtkLyVNGKKIGazTZ2nAmVzQU51zA==" + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "applicationinsights": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-1.7.2.tgz", + "integrity": "sha512-AtofsH08vrGTMDwXVK6+1wITd8ou9gksFV95JLZo7lVL0wX7/W1qeAZ13DK/6P3VJVsSMJ0sjdVNn98C4XxGvw==", + "requires": { + "cls-hooked": "^4.2.2", + "continuation-local-storage": "^3.2.1", + "diagnostic-channel": "0.2.0", + "diagnostic-channel-publishers": "^0.3.3" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "async-hook-jl": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", + "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "requires": { + "stack-chain": "^1.3.7" + } + }, "async-listener": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", @@ -32,6 +405,217 @@ } } }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "requires": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, "continuation-local-storage": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", @@ -41,6 +625,105 @@ "emitter-listener": "^1.1.1" } }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diagnostic-channel": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz", + "integrity": "sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=", + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "diagnostic-channel-publishers": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.3.tgz", + "integrity": "sha512-qIocRYU5TrGUkBlDDxaziAK1+squ8Yf2Ls4HldL3xxb/jzmWO2Enux7CvevNKYmF2kDXZ9HiRqwjPsjk8L+i2Q==" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, "emitter-listener": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", @@ -49,25 +732,1686 @@ "shimmer": "^1.2.0" } }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-cache-dir": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.0.tgz", + "integrity": "sha512-PtXtQb7IrD8O+h6Cq1dbpJH5NzD8+9keN1zZ0YlpDzl1PwXEJEBj6u1Xa92t1Hwluoozd9TNKul5Hi2iqpsWwg==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "dependencies": { + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "fromentries": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", + "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "dev": true + }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "hasha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", + "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "html-escaper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", + "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "istanbul-reports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "make-dir": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "nise": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.2.tgz", + "integrity": "sha512-ALDnm0pTTyeGdbg5FCpWGd58Nmp3qO8d8x+dU2Fw8lApeJTEBSjkBZZM4S8t6GpKh+czxkfM/TKxpRMroZzwOg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nyc": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.0.tgz", + "integrity": "sha512-qcLBlNCKMDVuKb7d1fpxjPR8sHeMVX0CHarXAVzrVWoFrigCkYR8xcrjfXSPi5HXM7EU78L6ywO7w1c5rZNCNg==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.0", + "js-yaml": "^3.13.1", + "make-dir": "^3.0.0", + "node-preload": "^0.2.0", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "uuid": "^3.3.3", + "yargs": "^15.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz", + "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^16.1.0" + } + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=", + "dev": true + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sinon": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.0.tgz", + "integrity": "sha512-c4bREcvuK5VuEGyMW/Oim9I3Rq49Vzb0aMdxouFaA44QCFpilc5LJOugrX+mkrvikbqCimxuK+4cnHVNnLR41g==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/formatio": "^5.0.0", + "@sinonjs/samsam": "^5.0.1", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-chain": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", + "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-node": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz", + "integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "3.1.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", + "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", + "dev": true + }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yargs-parser": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } From f87dde3608343e64a81ea5f0761c4c8f79c48a77 Mon Sep 17 00:00:00 2001 From: jwlong Date: Wed, 8 Apr 2020 09:15:20 -0400 Subject: [PATCH 53/66] Changed method of aggregation --- .../bbtest/batch_blackbox.ts | 17 +-- .../src/azure-stats.ts | 111 +++++++----------- 2 files changed, 51 insertions(+), 77 deletions(-) diff --git a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts index 8b4c6cd2c..ecc55b69c 100644 --- a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts @@ -6,7 +6,7 @@ function exportSingleMetric() { const exporter = new AS.AzureStatsExporter({ instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', logger: new OC.logger.ConsoleLogger(process.argv[2] || 'info'), - periodInMillis: 5010, + periodInMillis: 15000, exportMode: AS.ExportMode.BATCH, aggregationMethod: AS.AggregationMethod.AVERAGE }); @@ -32,17 +32,18 @@ function exportSingleMetric() { tags.set(dumbTagKey, { value: 'dumb' }); // Loop through an arbitrary amount of numbers, and record them as 'metrics'. - let counter = 1; setInterval(() => { - for (let i = 0; i < 50; i++) { + let randomCap = Math.floor(Math.random() * 901) + 100; + let randomFloor = Math.floor(Math.random() * randomCap); + for (let i = 0; i < 100; i++) { + let randomNum = Math.floor(Math.random() * (randomCap + 1)) + randomFloor; OC.globalStats.record([{ measure: mDummy2, - value: i * counter - }], tags); + value: randomNum + }], tags); } - counter++; - }, 5000); - + }, 6000); + } exportSingleMetric(); diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 2af61f3ec..3c0ecc7be 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -118,6 +118,8 @@ export class AzureStatsExporter implements StatsEventListener { // Define all other exporter variables. private timer: NodeJS.Timer; + private trackedMeasures: Map; + /** * Configures a new Stats Exporter given a set of options. * @param options Specific configuration information to use when constructing the exporter. @@ -136,6 +138,8 @@ export class AzureStatsExporter implements StatsEventListener { } this.setupAndStartApplicationInsights(); + + this.trackedMeasures = new Map(); } /** @@ -143,6 +147,12 @@ export class AzureStatsExporter implements StatsEventListener { * @param view The registered view. */ onRegisterView(view: View): void { + const measure = view.measure.name; + + if (!this.trackedMeasures.has(measure)) { + this.trackedMeasures.set(measure, []); + this.options.logger.info('Now tracking measure: ' + measure); + } } /** @@ -154,12 +164,19 @@ export class AzureStatsExporter implements StatsEventListener { // Use the App Insights SDK to track this measurement. onRecord(views: View[], measurement: Measurement, tags: Map): void { if (this.options.exportMode === ExportMode.SINGLE_VALUE) { + this.options.logger.info('Preparing to export single value [' + measurement.value + '] for ' + + 'measure: [' + measurement.measure.name + ']'); let newMetric: MetricTelemetry = { name: measurement.measure.name, value: measurement.value }; this.exportSingleMetric(newMetric); + } else { + // Get the name of the measure and track it's value so we can export it with the next batch. + const measure = measurement.measure.name; + + this.trackedMeasures.get(measure).push(measurement.value); } } @@ -213,79 +230,31 @@ export class AzureStatsExporter implements StatsEventListener { return; } - this.options.logger.info('Starting export of metric batch.'); - - // Collect all of the metrics that will need to be exported in this batch. - const metricList: Metric[] = []; - const metricProducerManager: MetricProducerManager = Metrics.getMetricProducerManager(); - - // According to OpenCensus documentation, MetricProducer.getMetrics() returns a list - // of metrics to be exported, therefore we will use that function to retrieve metrics. - const metricProducers = metricProducerManager.getAllMetricProducer() - this.options.logger.debug('There are ' + metricProducers.size.toString() + ' metric producers.') - for (const metricProducer of metricProducers) { - this.options.logger.debug('Processing metrics from: ' + JSON.stringify(metricProducer)); - - const metrics = metricProducer.getMetrics(); - this.options.logger.debug('Metric Producer [' + Object.keys(metricProducer)[0] +'] has ' + metrics.length + ' metrics.'); - for (const metric of metricProducer.getMetrics()) { - if (metric) { - this.options.logger.debug("Adding metric [" + metric.descriptor.name + "] to metricList."); - this.options.logger.debug(metric.descriptor.name.toUpperCase() + ': ' + JSON.stringify(metric)) - metricList.push(metric); - } - } - } - - // Aggregate each metric before sending them to Azure Monitor. - // TODO: Aggregate metrics. - for (const metric of metricList) { - this.options.logger.info('Metric: ' + JSON.stringify(metric)); - let aggregateValue: number; - switch (metric.descriptor.type) { - case MetricDescriptorType.GAUGE_INT64: - case MetricDescriptorType.GAUGE_DOUBLE: - aggregateValue = this.getMetricAggreation(metric); - this.options.logger.info(aggregateValue); - break; - case MetricDescriptorType.CUMULATIVE_INT64: - case MetricDescriptorType.CUMULATIVE_DOUBLE: - // Likely these will be aggregated the same as above, but for now I am keeping them - // separate. If same aggregation procedures can be used, we will have all Int64/Doubles - // fall through into the same block. - break; - case MetricDescriptorType.GAUGE_DISTRIBUTION: - // Need to look into how Azure monitor accepts distribution values. - break; - case MetricDescriptorType.CUMULATIVE_DISTRIBUTION: - // Need to look into how Azure monitor accepts distribution values. - break; - case MetricDescriptorType.UNSPECIFIED: - // Log a warning as this type should not be used. - break; - default: - } + let trackedMetricsCount = this.trackedMeasures.size; + this.options.logger.debug('Currently tracking ' + trackedMetricsCount + ' metric' + + (trackedMetricsCount > 1 ? 's.' : '.')); + + // Go through each measure, aggregate it, and export it. + for (let measure of this.trackedMeasures.keys()) { + let valuesCount = this.trackedMeasures.get(measure).length; + // Get the aggregated value. + let aggregatedValue = this.getAggregation(this.trackedMeasures.get(measure)); + + // Construct the MetricTelemetry object expected by the App Insights SDK. + // Export this as if it were a single metric. + this.options.logger.info('Preparing to export batch value [' + aggregatedValue+ '] for ' + + 'measure: [' + measure + '] based on ' + valuesCount + ' values.'); + let metricToExport: MetricTelemetry = { + name: measure, + value: aggregatedValue + }; + this.exportSingleMetric(metricToExport); - this.exportSingleMetric({ - name: metric.descriptor.name, - value: aggregateValue - }); + // Clear the tracked values so we don't handle a single value more than once. + this.trackedMeasures.set(measure, []); } } - private getMetricAggreation(metric: Metric) { - switch(this.options.aggregationMethod) { - case AggregationMethod.AVERAGE: - const allPoints = metric.timeseries.map(timeseries => timeseries.points).reduce((a, b) => [...a, ...b]); - const allValues : number[] = allPoints.map(point => point.value); - - this.options.logger.debug('Points being logged: ' + allValues); - - return allValues.reduce((a, b) => a + b) / allValues.length; - } - return null; - } - /** * Verifies that that exporter is running batch mode. If it is not, * this method will issue a warning log message. @@ -298,6 +267,10 @@ export class AzureStatsExporter implements StatsEventListener { return true; } + private getAggregation(values: number[]) : number { + return values.reduce((a, b) => a + b) / values.length; + } + /** * Uses the Application Insights SDK to export a given MetricTelemetry object * into Azure Monitor. From fa6732acc110163d060df26ce495a9cf2c9b8565 Mon Sep 17 00:00:00 2001 From: jwlong Date: Sat, 11 Apr 2020 10:13:03 -0400 Subject: [PATCH 54/66] Added todo --- packages/opencensus-exporter-azure/src/azure-stats.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 3c0ecc7be..21387addf 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -251,6 +251,7 @@ export class AzureStatsExporter implements StatsEventListener { this.exportSingleMetric(metricToExport); // Clear the tracked values so we don't handle a single value more than once. + // Make sure this is most efficent way to clear. this.trackedMeasures.set(measure, []); } } From feedcc1c1d02a25daac414057a09deabab16d2d4 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 17 Apr 2020 12:52:36 -0400 Subject: [PATCH 55/66] Started adding tests for batch functionality. --- .../test/test-stats-exporter.ts | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index 622028fd8..35799d5c8 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -2,7 +2,8 @@ import { Logger, MeasureUnit, globalStats, - Measurement + Measurement, + AggregationType } from '@opencensus/core'; import { AzureStatsExporter, @@ -23,6 +24,7 @@ class MockLogger implements Logger { // tslint:disable-next-line:no-any debugBuffer: any[] = []; errorMessagesBuffer: any[] = []; + infoBuffer: any[] = []; cleanAll() { this.debugBuffer = []; @@ -41,7 +43,9 @@ class MockLogger implements Logger { // tslint:disable-next-line:no-any warn(...args: any[]) {} // tslint:disable-next-line:no-any - info(...args: any[]) {} + info(message: string, ...args: any[]) { + this.infoBuffer.push(message); + } } /** @@ -130,13 +134,50 @@ describe('Single-Value Stats Exporting', () => { stub.resetBehavior(); }); - it('Should export a simple metric.', async () => { + it('Should export a simple metric.', () => { exporter.onRecord(undefined, measurement, undefined); assert(stub.called, 'Application Insights SDk was not called'); }); }); -describe('Batched Stats Exporter', () => { - // TODO: Test batch functinoality once it has been implemented. -}); +describe('Batch Functionality', () => { + const mockLogger = new MockLogger(); + let exporterOptions: AzureStatsExporterOptions; + + let exporter: AzureStatsExporter; + + const measure = globalStats.createMeasureDouble( + 'opencensus.io/test/doule', + MeasureUnit.UNIT, + 'Measure Double' + ); + + const view = globalStats.createView( + 'test/view', + measure, + AggregationType.COUNT, + null, + 'This is a test view.' + ); + + before(() => { + exporterOptions = { + instrumentationKey: 'fake-instrumentation-key', + logger: mockLogger + }; + exporter = new AzureStatsExporter(exporterOptions); + }); + + afterEach(() => { + exporter.stop(); + mockLogger.cleanAll(); + globalStats.clear(); + }); + + it('Should register the metric contained within a view, when a new view is registered.', () => { + exporter.onRegisterView(view); + assert(mockLogger.infoBuffer.length === 1, 'There was not an info log message.'); + assert(mockLogger.infoBuffer[0] === 'Now tracking measure: ' + measure.name) + }); +}); \ No newline at end of file From 1ff13b5af15830e8c756e1bcee188e237ef686ab Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 12:06:43 -0400 Subject: [PATCH 56/66] Removed unecessary dependency --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index 0cb9ef809..b50d9a21a 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,5 @@ "lerna": "^2.11.0", "typedoc": "^0.17.0", "typescript": "^3.0.0" - }, - "dependencies": { - "applicationinsights": "^1.7.2" } } From 0249ea38bbe6b55cbfb2b8614f1e5e894f153af7 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 12:07:41 -0400 Subject: [PATCH 57/66] Version bump --- packages/opencensus-exporter-azure/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencensus-exporter-azure/package.json b/packages/opencensus-exporter-azure/package.json index c950d2f0f..03f240550 100644 --- a/packages/opencensus-exporter-azure/package.json +++ b/packages/opencensus-exporter-azure/package.json @@ -1,6 +1,6 @@ { "name": "@opencensus/exporter-azure", - "version": "0.0.19", + "version": "0.0.21", "description": "OpenCensus Azure Exporter allows the user to send stats and traces collected with OpenCensus Node.js to Azure Monitor.", "type": "module", "main": "index.ts", From 449aee6d728d8dcef09cd0e000bb8810d879ea69 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 12:10:17 -0400 Subject: [PATCH 58/66] Added license header --- .../bbtest/batch_blackbox.ts | 16 ++++++++++++++++ .../bbtest/blackbox-trace.ts | 16 ++++++++++++++++ .../opencensus-exporter-azure/bbtest/blackbox.ts | 16 ++++++++++++++++ .../opencensus-exporter-azure/src/azure-stats.ts | 16 ++++++++++++++++ .../opencensus-exporter-azure/src/azure-trace.ts | 16 ++++++++++++++++ packages/opencensus-exporter-azure/src/index.ts | 16 ++++++++++++++++ .../test/test-stats-exporter.ts | 16 ++++++++++++++++ 7 files changed, 112 insertions(+) diff --git a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts index ecc55b69c..4ef0ee2ec 100644 --- a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2020 OpenCensus Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + const AS = require('../build/src/azure-stats'); const OC = require('@opencensus/core'); diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts b/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts index 35489a83e..18797cc25 100644 --- a/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts +++ b/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2020 OpenCensus Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // Import Core OpenCensus and our Azure Exporter module. import OpenCensus = require('@opencensus/core'); import AzureTrace = require('../build/src/azure-trace'); diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox.ts b/packages/opencensus-exporter-azure/bbtest/blackbox.ts index f433e29c2..40a80788e 100644 --- a/packages/opencensus-exporter-azure/bbtest/blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/blackbox.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2020 OpenCensus Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // Import Core OpenCensus and our Azure Exporter module. const OpenCensus = require('@opencensus/core'); const AzureStats = require('../build/src/azure-stats'); diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index 21387addf..f90d9d381 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2018 OpenCensus Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { ExporterConfig, StatsEventListener, diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts index ef2ff0cc2..552e6f2c7 100644 --- a/packages/opencensus-exporter-azure/src/azure-trace.ts +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2018 OpenCensus Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Exporter, ExporterConfig, diff --git a/packages/opencensus-exporter-azure/src/index.ts b/packages/opencensus-exporter-azure/src/index.ts index 4fd23f72a..eed951c8d 100644 --- a/packages/opencensus-exporter-azure/src/index.ts +++ b/packages/opencensus-exporter-azure/src/index.ts @@ -1,2 +1,18 @@ +/** + * Copyright 2018 OpenCensus Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + export * from './azure-stats'; export * from './azure-trace'; diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index 35799d5c8..37e5345e3 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2018 OpenCensus Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Logger, MeasureUnit, From c02be2396fed7a04547805588560841f1bd2c9ea Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 13:03:11 -0400 Subject: [PATCH 59/66] Moved type definitions to their own file --- .../src/azure-stats.ts | 90 +------------ .../src/azure-trace.ts | 48 +------ .../opencensus-exporter-azure/src/index.ts | 1 + .../opencensus-exporter-azure/src/types.ts | 120 ++++++++++++++++++ 4 files changed, 133 insertions(+), 126 deletions(-) create mode 100644 packages/opencensus-exporter-azure/src/types.ts diff --git a/packages/opencensus-exporter-azure/src/azure-stats.ts b/packages/opencensus-exporter-azure/src/azure-stats.ts index f90d9d381..588616f8d 100644 --- a/packages/opencensus-exporter-azure/src/azure-stats.ts +++ b/packages/opencensus-exporter-azure/src/azure-stats.ts @@ -15,103 +15,27 @@ */ import { - ExporterConfig, StatsEventListener, View, Measurement, TagKey, TagValue, logger, - Logger, - Metric, - MetricProducerManager, - Metrics, - Measure, - AggregationData, - MetricDescriptorType, } from '@opencensus/core'; +import { + AzureStatsExporterOptions, + ExportMode, + AggregationMethod, + IllegalOptionsError +} from './types'; + import * as ApplicationInsights from 'applicationinsights'; import { MetricTelemetry } from 'applicationinsights/out/Declarations/Contracts'; -export interface StatsParams { - registeredViews: View[]; - registeredMeasures: Measure[]; - recordedData: { [key: string]: AggregationData[] }; -} - -export enum ExportMode { - SINGLE_VALUE = 0, - BATCH = 1 -} - -export enum AggregationMethod { - AVERAGE = 0, - MIN = 1, - MAX = 2, - SUM = 3, - COUNT = 4 -} - -/** - * Options for Azure Monitor configuration. - */ -export interface AzureStatsExporterOptions extends ExporterConfig { - - /** - * The Instrumentation Key found in your application's Azure Monitor Application Insights - * Overview page. Required. - */ - instrumentationKey: string; - - /** - * If specified, dictates the mode the exporter will function in. - * Optional, defaults to ExportMode.SINGLE_VALUE. - */ - exportMode?: ExportMode; - - /** - * If specified, defines the number of milliseconds between uploading metrics - * to Azure Monitor. Optional, defaults to 60,000 (1 minute). - */ - periodInMillis?: number; - - /** - * If specified, this will override the default OpenCensus prefix of an - * Azure Monitor metric. Optional. - */ - prefix?: string; - - /** - * The aggregation method if batch exporting is to be used. - * Optional, defaults to AggregationMethod.AVERAGE. - */ - aggregationMethod?: AggregationMethod; - - /** - * If specified, this will serve as the logger used by the exporter. - * Optional, default to use whatever logger is registered with OpenCensus. - */ - logger?: Logger; - - /** - * If specified, this function will be called whenever an error occurs uploading - * stats to Azure monitor. Optional. - */ - onMetricUploadError?: (err: Error) => void; - -} - -export class IllegalOptionsError extends Error { - constructor(message: string) { - super(message); - this.name = 'IllegalOptionsError'; - } -} - /** * Configuration defaults for an AzureStatsExporter. */ diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts index 552e6f2c7..24f6d7b26 100644 --- a/packages/opencensus-exporter-azure/src/azure-trace.ts +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -18,54 +18,16 @@ import { Exporter, ExporterConfig, Span, - Logger, logger, - View, - Measure, - AggregationData, ExporterBuffer } from '@opencensus/core'; import * as ApplicationInsights from 'applicationinsights'; -import { IllegalOptionsError } from './azure-stats'; - -export interface TraceParams { - registeredViews: View[]; - registeredMeasures: Measure[]; - recordedData: { [key: string]: AggregationData[] }; -} - -export interface AzureTraceExporterOptions extends ExporterConfig { - /** - * The Instrumentation Key found in your application's Azure Monitor Application Insights - * Overview page. Required. - */ - instrumentationKey: string; - - /** - * If specified, this will serve as the logger used by the exporter. - * Optional, default to use whatever logger is registered with OpenCensus. - */ - logger?: Logger; - - /** - * Max size of telemetry batch. - * If a batch exceeds this limit, it is immediately sent and a new batch is started - */ - maxBatchSizeInBytes?: number; - - /** - * How long to batch telemetry for before sending (milliseconds) - */ - maxBatchInterval?: number; - - /** - * If specified, this will override the default OpenCensus prefix of an - * Azure Monitor metric. Optional. - */ - prefix?: string; - -} +import { + IllegalOptionsError, + AzureTraceExporterOptions, + TraceParams +} from './types'; /** * Configuration defaults for an AzureTraceExporter. diff --git a/packages/opencensus-exporter-azure/src/index.ts b/packages/opencensus-exporter-azure/src/index.ts index eed951c8d..3b6dc82d3 100644 --- a/packages/opencensus-exporter-azure/src/index.ts +++ b/packages/opencensus-exporter-azure/src/index.ts @@ -16,3 +16,4 @@ export * from './azure-stats'; export * from './azure-trace'; +export * from './types'; diff --git a/packages/opencensus-exporter-azure/src/types.ts b/packages/opencensus-exporter-azure/src/types.ts new file mode 100644 index 000000000..972e35c79 --- /dev/null +++ b/packages/opencensus-exporter-azure/src/types.ts @@ -0,0 +1,120 @@ +import { + Logger, + View, + Measure, + AggregationData, + ExporterConfig +} from '@opencensus/core'; + +export interface StatsParams { + registeredViews: View[]; + registeredMeasures: Measure[]; + recordedData: { [key: string]: AggregationData[] }; +} + +export enum ExportMode { + SINGLE_VALUE = 0, + BATCH = 1 +} + +export enum AggregationMethod { + AVERAGE = 0, + MIN = 1, + MAX = 2, + SUM = 3, + COUNT = 4 +} + +/** + * Options for Azure Monitor configuration. + */ +export interface AzureStatsExporterOptions extends ExporterConfig { + + /** + * The Instrumentation Key found in your application's Azure Monitor Application Insights + * Overview page. Required. + */ + instrumentationKey: string; + + /** + * If specified, dictates the mode the exporter will function in. + * Optional, defaults to ExportMode.SINGLE_VALUE. + */ + exportMode?: ExportMode; + + /** + * If specified, defines the number of milliseconds between uploading metrics + * to Azure Monitor. Optional, defaults to 60,000 (1 minute). + */ + periodInMillis?: number; + + /** + * If specified, this will override the default OpenCensus prefix of an + * Azure Monitor metric. Optional. + */ + prefix?: string; + + /** + * The aggregation method if batch exporting is to be used. + * Optional, defaults to AggregationMethod.AVERAGE. + */ + aggregationMethod?: AggregationMethod; + + /** + * If specified, this will serve as the logger used by the exporter. + * Optional, default to use whatever logger is registered with OpenCensus. + */ + logger?: Logger; + + /** + * If specified, this function will be called whenever an error occurs uploading + * stats to Azure monitor. Optional. + */ + onMetricUploadError?: (err: Error) => void; + +} + +export class IllegalOptionsError extends Error { + constructor(message: string) { + super(message); + this.name = 'IllegalOptionsError'; + } +} + +export interface TraceParams { + registeredViews: View[]; + registeredMeasures: Measure[]; + recordedData: { [key: string]: AggregationData[] }; +} + +export interface AzureTraceExporterOptions extends ExporterConfig { + /** + * The Instrumentation Key found in your application's Azure Monitor Application Insights + * Overview page. Required. + */ + instrumentationKey: string; + + /** + * If specified, this will serve as the logger used by the exporter. + * Optional, default to use whatever logger is registered with OpenCensus. + */ + logger?: Logger; + + /** + * Max size of telemetry batch. + * If a batch exceeds this limit, it is immediately sent and a new batch is started + */ + maxBatchSizeInBytes?: number; + + /** + * How long to batch telemetry for before sending (milliseconds) + */ + maxBatchInterval?: number; + + /** + * If specified, this will override the default OpenCensus prefix of an + * Azure Monitor metric. Optional. + */ + prefix?: string; + +} \ No newline at end of file From bc1ebd843c21570eada5f1fd63726ed21ca7a7a0 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 13:12:22 -0400 Subject: [PATCH 60/66] Including changes from Tony --- .../src/azure-trace.ts | 78 ++++++++++++++----- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/packages/opencensus-exporter-azure/src/azure-trace.ts b/packages/opencensus-exporter-azure/src/azure-trace.ts index 24f6d7b26..9c601324c 100644 --- a/packages/opencensus-exporter-azure/src/azure-trace.ts +++ b/packages/opencensus-exporter-azure/src/azure-trace.ts @@ -42,10 +42,13 @@ const AZURE_TRACE_EXPORTER_DEFAULTS: AzureTraceExporterOptions = { export class AzureTraceExporter implements Exporter { + /**Custom options for Trace Exporter */ private options: AzureTraceExporterOptions; + /** Buffer object to store the spans. */ private buffer: ExporterBuffer; + /** Exporter Config Object for Azure Monitor */ private config: ExporterConfig; // Define all other exporter variables. @@ -61,53 +64,86 @@ export class AzureTraceExporter implements Exporter { * Configures a new Trace Exporter given a set of options. * @param options Specific configuration information to use when constructing the exporter. */ - constructor(options: AzureTraceExporterOptions, config: ExporterConfig) { + constructor(options: AzureTraceExporterOptions) { // Start with the default options, and overwrite the defaults with any options specified // in the constructor's options parameter. We do this before validating input so that // the logger gets configured with the user specified logger, if provided. this.options = { ...AZURE_TRACE_EXPORTER_DEFAULTS, ...options }; - this.buffer = new ExporterBuffer(this, config); - this.config = config; + + // Init ExporterConfig + this.config = { + bufferSize: this.options.maxBatchSizeInBytes, + bufferTimeout: this.options.maxBatchInterval, + logger: this.options.logger + } + this.buffer = new ExporterBuffer(this, this.config); // Verify that the options passed in have actual values (no undefined values) // for require parameters. if (!options.instrumentationKey) { this.options.logger.error('You must provide a valid instrumentation key.'); throw new IllegalOptionsError('You must provide a valid instrumentation key.'); - } + } // Configure the Application Insights SDK to use the Instrumentation Key from our options. ApplicationInsights.setup(this.options.instrumentationKey).start(); } + + /** + * Sends the spans information to the console. + * @param spans The stored spans + */ publish(spans: Span[]): Promise { // Iterate over all root spans formating the data the way we want + this.options.logger.debug(spans.length); + let ROOT_NAME = ""; + let children : { [key: string]: string} = {}; spans.map((root) => { - const ROOT_STR = `RootSpan: {traceId: ${root.traceId}, spanId: ${ - root.id}, name: ${root.name} }`; - - const SPANS_STR: string[] = root.spans.map( - (span) => [`\t\t{spanId: ${span.id}, name: ${span.name}}`].join( - '\n')); - - const result: string[] = []; - result.push( - ROOT_STR + '\n\tChildSpans:\n' + - `${SPANS_STR.join('\n')}`); - // console.log(`${result}`); + const ROOT_STR = `RootSpan: {traceId: ${root.traceId}, spanId: ${ + root.id}, name: ${root.name} }`; + + const SPANS_STR: string[] = root.spans.map( + (span) => [`\t\t{spanId: ${span.id}, name: ${span.name}}`].join( + '\n')); + + root.spans.map( + (span) => children[span.id] = span.name + ); + const result: string[] = []; + result.push( + ROOT_STR + '\n\tChildSpans:\n' + + `${SPANS_STR.join('\n')}`); + this.options.logger.debug('Result string : ' + result[0]); + + ROOT_NAME = root.name; + }); - + ApplicationInsights.defaultClient.trackTrace({ - message: "Telemetry trace", + message: ROOT_NAME, severity: ApplicationInsights.Contracts.SeverityLevel.Information, - properties: spans.map.arguments.result + properties: children }); + return Promise.resolve(); } - + + /** + * Our onStartSpan will do nothing. The exporting logic will be concentrated + * at the onEndSpan event. + */ onStartSpan(span: Span): void { - this.buffer = new ExporterBuffer(this, this.config); } + + /** + * Called whenever a span is ended. + * @param span Ended span. + */ onEndSpan(span: Span): void { + // We will just add the ended span to the buffer and wait for it to call + // the exporter back giving all the stored spans. + if (!span.isRootSpan()) return; this.buffer.addToBuffer(span); + this.options.logger.debug('Added to buffer: ' + span.name); } } From f110577d903c8366bf77b677d7ec834a0f434214 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 13:16:00 -0400 Subject: [PATCH 61/66] Added test from Tony @ahnivert --- .../test/test-trace-exporter.ts | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 packages/opencensus-exporter-azure/test/test-trace-exporter.ts diff --git a/packages/opencensus-exporter-azure/test/test-trace-exporter.ts b/packages/opencensus-exporter-azure/test/test-trace-exporter.ts new file mode 100644 index 000000000..dbc5517bb --- /dev/null +++ b/packages/opencensus-exporter-azure/test/test-trace-exporter.ts @@ -0,0 +1,93 @@ +import { + Logger + } from '@opencensus/core'; + import { + AzureTraceExporter, + AzureTraceExporterOptions, + } from '../src/azure-trace'; + import { + IllegalOptionsError + } from '../src/azure-stats' + import { + describe, + it, + afterEach + } from 'mocha'; + import { + assert + } from 'chai'; + + class MockLogger implements Logger { + level?: string; + // tslint:disable-next-line:no-any + debugBuffer: any[] = []; + errorMessagesBuffer: any[] = []; + + cleanAll() { + this.debugBuffer = []; + this.errorMessagesBuffer = []; + } + + // tslint:disable-next-line:no-any + debug(message: string, ...args: any[]) { + this.debugBuffer.push(...args); + } + + // tslint:disable-next-line:no-any + error(message: string, ...args: any[]) { + this.errorMessagesBuffer.push(message); + } + // tslint:disable-next-line:no-any + warn(...args: any[]) {} + // tslint:disable-next-line:no-any + info(...args: any[]) {} + } + + /** + * Tests construction of the exporter. + * Specifically, that instrumentation keys are valid. + */ + describe('Exporter Construction', () => { + const INVALID_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide a valid instrumentation key.'; + + let exporter: AzureTraceExporter; + const mockLogger = new MockLogger(); + + afterEach(() => { + mockLogger.cleanAll(); + }); + + it('Throws an error if no instrumentation key is provided.', () => { + const options: AzureTraceExporterOptions = { + instrumentationKey: undefined, + logger: mockLogger + }; + assert.throws(() => { + // This should throw an error. + exporter = new AzureTraceExporter(options); + }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG) + assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); + assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); + }); + + it('Throws an error if the provided instrumentation key is an empty string.', () => { + const options: AzureTraceExporterOptions = { + instrumentationKey: '', + logger: mockLogger + }; + assert.throws(() => { + // This should throw an error. + exporter = new AzureTraceExporter(options); + }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG); + assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); + assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); + }); + + it('Attempts to start the exporter if a seemingly valid instrumentation key is provided.', () => { + const options: AzureTraceExporterOptions = { + instrumentationKey: 'seemingly-valid', + logger: mockLogger + }; + assert + }); + }); \ No newline at end of file From 1ee93760aef1c9ad644cbd23bf35a4ccfd5cb007 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 13:17:07 -0400 Subject: [PATCH 62/66] Added blackbox test from Tony. Removed key --- .../bbtest/blackbox-trace.ts | 121 +++++++----------- 1 file changed, 44 insertions(+), 77 deletions(-) diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts b/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts index 18797cc25..7a9917dfc 100644 --- a/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts +++ b/packages/opencensus-exporter-azure/bbtest/blackbox-trace.ts @@ -15,92 +15,59 @@ */ // Import Core OpenCensus and our Azure Exporter module. -import OpenCensus = require('@opencensus/core'); -import AzureTrace = require('../build/src/azure-trace'); +const OpenCensus = require('@opencensus/core'); +const tracing = require('@opencensus/nodejs'); +const AzureTrace = require('../build/src/azure-trace'); +const ApplicationInsights = require('applicationinsights'); -function exportSingleMetrics() { - // Construct and register an AzureStatsExporter with the OpenCensus library. - const exporter = new AzureTrace.AzureTraceExporter({ - instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', - logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info') - }); - OpenCensus.globalStats.registerExporter(exporter); - - // Create a dummy metric. - const mDummy = OpenCensus.globalStats.createMeasureInt64('test/dummy', OpenCensus.MeasureUnit.UNIT, 'This variable has absolutely no meaning.'); +// Start the global tracing object +const tracer = tracing.start({samplingRate: 1}).tracer; - // Create some dummy tags. - const dumbTagKey = { name: 'dumb' }; - const dumberTagKey = { name: 'dumber' }; - const evenDumberTagKey = { name: 'evenDumber' }; - const dumbestTagKey = { name: 'dumbest' }; +function doWork() { + for (let i = 0; i < 10; i++) { + const span = tracer.startChildSpan('doWork'); + span.start(); - const newTrace = OpenCensus.TraceParamsBuilder - - // Create some dummy views. - const sumView = OpenCensus.globalStats.createView( - 'dummy/sumView', - mDummy, - OpenCensus.AggregationType.SUM, - [dumbTagKey], - 'A sum of the dummy measure.' - ); - OpenCensus.globalStats.registerView(sumView); - - const distributionView = OpenCensus.globalStats.createView( - 'dummy/distView', - mDummy, - OpenCensus.AggregationType.DISTRIBUTION, - [dumbTagKey, dumberTagKey], - 'A distribution of the dummy measure.', - [0, 5, 10, 15, 20, 25, 30, 35, 40, 45] - ); - OpenCensus.globalStats.registerView(distributionView); + for (let j = 0; j < 100000; j++); + span.addAnnotation('Invoking doWork'); + for (let j = 0; j < 20000000; j++); + span.end(); + } +} - const countView = OpenCensus.globalStats.createView( - 'dummy/countView', - mDummy, - OpenCensus.AggregationType.COUNT, - [dumbTagKey, dumberTagKey, evenDumberTagKey], - 'A count of the dummy measure.' - ); - OpenCensus.globalStats.registerView(countView); +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} - const lastValueView = OpenCensus.globalStats.createView( - 'dummy/lastValueView', - mDummy, - OpenCensus.AggregationType.LAST_VALUE, - [dumbTagKey, dumberTagKey, evenDumberTagKey, dumbestTagKey], - 'The last value of the dummy measure.' - ); - OpenCensus.globalStats.registerView(lastValueView); +async function exportSingleTrace() { + // Construct and register an AzureStatsExporter with the OpenCensus library. - // Loop through an arbitrary amount of numbers, and record them as 'metrics'. - for (let i = 0; i < 42; i++) { - // Create the tag map so we can set values for our dummy tags. - const tags = new OpenCensus.TagMap(); + const exporterOptions = { + instrumentationKey: 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info'), + maxBatchInterval: 1 + }; - // Set a value for each. - tags.set(dumbTagKey, { value: 'dumb' }); - tags.set(dumberTagKey, { value: 'dumber' }); - tags.set(evenDumberTagKey, { value: 'evenDumber' }); - tags.set(dumbestTagKey, { value: 'dumbest' }); + const exporter = new AzureTrace.AzureTraceExporter(exporterOptions); + // OpenCensus.globalStats.registerExporter(exporter); - OpenCensus.globalStats.record([{ - measure: mDummy, - value: i - }], tags); + // Register the Azure trace exporter so that the global object will utilize + // the Azure exporter to push traces + tracer.registerSpanEventListener(exporter); - // Do something special if i is greater than 30 so we have extra things to look for in - // AppInsights. - if (i > 30) { - tags.set(dumbTagKey, { value: 'dumb but over 30' }); - OpenCensus.globalStats.record([{ - measure: mDummy, - value: i - }], tags); + // Start an arbitrary root span + tracer.startRootSpan({ name: 'root-s01'}, rootSpan => { + // Do some arbitrary work, and create children spans while we are at it. + for(let i = 0; i < 10; i++) { + doWork(); } - } + // End the root span, triggering the publishing of it. + rootSpan.end(); + }); + + // Pause execution of the script for 20 seconds, to allow the ExportBuffer that controls + // the publish() method within the Trace Exporter time to complete logging + await delay(20 * 1000); } -exportSingleMetrics(); +exportSingleTrace(); \ No newline at end of file From 46a763194d325814a5a05117fc8f4ce1c5d37cb5 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 13:17:46 -0400 Subject: [PATCH 63/66] Removed instrumentation keys --- packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts | 2 +- packages/opencensus-exporter-azure/bbtest/blackbox.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts index 4ef0ee2ec..5cf30f32d 100644 --- a/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/batch_blackbox.ts @@ -20,7 +20,7 @@ const OC = require('@opencensus/core'); function exportSingleMetric() { // Construct and register an AzureStatsExporter with the OpenCensus library. const exporter = new AS.AzureStatsExporter({ - instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', + instrumentationKey: 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', logger: new OC.logger.ConsoleLogger(process.argv[2] || 'info'), periodInMillis: 15000, exportMode: AS.ExportMode.BATCH, diff --git a/packages/opencensus-exporter-azure/bbtest/blackbox.ts b/packages/opencensus-exporter-azure/bbtest/blackbox.ts index 40a80788e..36e157da2 100644 --- a/packages/opencensus-exporter-azure/bbtest/blackbox.ts +++ b/packages/opencensus-exporter-azure/bbtest/blackbox.ts @@ -21,7 +21,7 @@ const AzureStats = require('../build/src/azure-stats'); function exportSingleMetrics() { // Construct and register an AzureStatsExporter with the OpenCensus library. const exporter = new AzureStats.AzureStatsExporter({ - instrumentationKey: 'fa3cb2ed-0f0d-463d-a8f2-0c0c382fa9fc', + instrumentationKey: 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', logger: new OpenCensus.logger.ConsoleLogger(process.argv[2] || 'info') }); OpenCensus.globalStats.registerExporter(exporter); From 0f9033ab107a7dc3544b4e5629b3fb6a9115f65a Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 13:35:00 -0400 Subject: [PATCH 64/66] Refactored imports --- .../opencensus-exporter-azure/test/test-stats-exporter.ts | 4 +++- .../opencensus-exporter-azure/test/test-trace-exporter.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts index 37e5345e3..4f6a43a89 100644 --- a/packages/opencensus-exporter-azure/test/test-stats-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-stats-exporter.ts @@ -23,9 +23,11 @@ import { } from '@opencensus/core'; import { AzureStatsExporter, +} from '../src/azure-stats'; +import { AzureStatsExporterOptions, IllegalOptionsError -} from '../src/azure-stats'; +} from '../src/types'; import { describe, it diff --git a/packages/opencensus-exporter-azure/test/test-trace-exporter.ts b/packages/opencensus-exporter-azure/test/test-trace-exporter.ts index dbc5517bb..36ca37850 100644 --- a/packages/opencensus-exporter-azure/test/test-trace-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-trace-exporter.ts @@ -3,11 +3,11 @@ import { } from '@opencensus/core'; import { AzureTraceExporter, - AzureTraceExporterOptions, } from '../src/azure-trace'; import { + AzureTraceExporterOptions, IllegalOptionsError - } from '../src/azure-stats' + } from '../src/types'; import { describe, it, From 467268edbe46000f07f41309cbda00779937f2ac Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 14:28:52 -0400 Subject: [PATCH 65/66] Formatting --- .../test/test-trace-exporter.ts | 182 +++++++++--------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/packages/opencensus-exporter-azure/test/test-trace-exporter.ts b/packages/opencensus-exporter-azure/test/test-trace-exporter.ts index 36ca37850..9191ae68d 100644 --- a/packages/opencensus-exporter-azure/test/test-trace-exporter.ts +++ b/packages/opencensus-exporter-azure/test/test-trace-exporter.ts @@ -1,93 +1,93 @@ import { - Logger - } from '@opencensus/core'; - import { - AzureTraceExporter, - } from '../src/azure-trace'; - import { - AzureTraceExporterOptions, - IllegalOptionsError - } from '../src/types'; - import { - describe, - it, - afterEach - } from 'mocha'; - import { - assert - } from 'chai'; - - class MockLogger implements Logger { - level?: string; - // tslint:disable-next-line:no-any - debugBuffer: any[] = []; - errorMessagesBuffer: any[] = []; - - cleanAll() { - this.debugBuffer = []; - this.errorMessagesBuffer = []; - } - - // tslint:disable-next-line:no-any - debug(message: string, ...args: any[]) { - this.debugBuffer.push(...args); - } - - // tslint:disable-next-line:no-any - error(message: string, ...args: any[]) { - this.errorMessagesBuffer.push(message); - } - // tslint:disable-next-line:no-any - warn(...args: any[]) {} - // tslint:disable-next-line:no-any - info(...args: any[]) {} + Logger +} from '@opencensus/core'; +import { + AzureTraceExporter, +} from '../src/azure-trace'; +import { + AzureTraceExporterOptions, + IllegalOptionsError +} from '../src/types'; +import { + describe, + it, + afterEach +} from 'mocha'; +import { + assert +} from 'chai'; + +class MockLogger implements Logger { + level?: string; + // tslint:disable-next-line:no-any + debugBuffer: any[] = []; + errorMessagesBuffer: any[] = []; + + cleanAll() { + this.debugBuffer = []; + this.errorMessagesBuffer = []; + } + + // tslint:disable-next-line:no-any + debug(message: string, ...args: any[]) { + this.debugBuffer.push(...args); } - - /** - * Tests construction of the exporter. - * Specifically, that instrumentation keys are valid. - */ - describe('Exporter Construction', () => { - const INVALID_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide a valid instrumentation key.'; - - let exporter: AzureTraceExporter; - const mockLogger = new MockLogger(); - - afterEach(() => { - mockLogger.cleanAll(); - }); - - it('Throws an error if no instrumentation key is provided.', () => { - const options: AzureTraceExporterOptions = { - instrumentationKey: undefined, - logger: mockLogger - }; - assert.throws(() => { - // This should throw an error. - exporter = new AzureTraceExporter(options); - }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG) - assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); - assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); - }); - - it('Throws an error if the provided instrumentation key is an empty string.', () => { - const options: AzureTraceExporterOptions = { - instrumentationKey: '', - logger: mockLogger - }; - assert.throws(() => { - // This should throw an error. - exporter = new AzureTraceExporter(options); - }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG); - assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); - assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); - }); - - it('Attempts to start the exporter if a seemingly valid instrumentation key is provided.', () => { - const options: AzureTraceExporterOptions = { - instrumentationKey: 'seemingly-valid', - logger: mockLogger - }; - assert - }); - }); \ No newline at end of file + + // tslint:disable-next-line:no-any + error(message: string, ...args: any[]) { + this.errorMessagesBuffer.push(message); + } + // tslint:disable-next-line:no-any + warn(...args: any[]) { } + // tslint:disable-next-line:no-any + info(...args: any[]) { } +} + +/** +* Tests construction of the exporter. +* Specifically, that instrumentation keys are valid. +*/ +describe('Exporter Construction', () => { + const INVALID_INSTRUMENTATION_KEY_ERROR_MSG = 'You must provide a valid instrumentation key.'; + + let exporter: AzureTraceExporter; + const mockLogger = new MockLogger(); + + afterEach(() => { + mockLogger.cleanAll(); + }); + + it('Throws an error if no instrumentation key is provided.', () => { + const options: AzureTraceExporterOptions = { + instrumentationKey: undefined, + logger: mockLogger + }; + assert.throws(() => { + // This should throw an error. + exporter = new AzureTraceExporter(options); + }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG) + assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); + assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); + }); + + it('Throws an error if the provided instrumentation key is an empty string.', () => { + const options: AzureTraceExporterOptions = { + instrumentationKey: '', + logger: mockLogger + }; + assert.throws(() => { + // This should throw an error. + exporter = new AzureTraceExporter(options); + }, IllegalOptionsError, INVALID_INSTRUMENTATION_KEY_ERROR_MSG); + assert(mockLogger.errorMessagesBuffer.length === 1, 'There was not exactly one error log.'); + assert(mockLogger.errorMessagesBuffer[0] === INVALID_INSTRUMENTATION_KEY_ERROR_MSG, 'Incorrect message given.'); + }); + + it('Attempts to start the exporter if a seemingly valid instrumentation key is provided.', () => { + const options: AzureTraceExporterOptions = { + instrumentationKey: 'seemingly-valid', + logger: mockLogger + }; + assert + }); +}); \ No newline at end of file From 01fa6ae5f3f42fc83d9c56784c38612503d1b0d9 Mon Sep 17 00:00:00 2001 From: jimmy-long Date: Fri, 1 May 2020 14:49:04 -0400 Subject: [PATCH 66/66] JSDoc comments --- .../opencensus-exporter-azure/src/types.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/opencensus-exporter-azure/src/types.ts b/packages/opencensus-exporter-azure/src/types.ts index 972e35c79..14b2d5340 100644 --- a/packages/opencensus-exporter-azure/src/types.ts +++ b/packages/opencensus-exporter-azure/src/types.ts @@ -6,17 +6,26 @@ import { ExporterConfig } from '@opencensus/core'; +/** + * Parameters needed to annotate a stat with OpenCensus metadata. + */ export interface StatsParams { registeredViews: View[]; registeredMeasures: Measure[]; recordedData: { [key: string]: AggregationData[] }; } +/** + * Enumeration to differentiate between single value and batch exporting. + */ export enum ExportMode { SINGLE_VALUE = 0, BATCH = 1 } +/** + * Aggregation method enumerations for use by ExporterOptions. + */ export enum AggregationMethod { AVERAGE = 0, MIN = 1, @@ -74,6 +83,9 @@ export interface AzureStatsExporterOptions extends ExporterConfig { } +/** + * Custom error for use when an exporter is supplied with bad options. + */ export class IllegalOptionsError extends Error { constructor(message: string) { super(message); @@ -81,12 +93,18 @@ export class IllegalOptionsError extends Error { } } +/** + * Params needed to annotate a trace. + */ export interface TraceParams { registeredViews: View[]; registeredMeasures: Measure[]; recordedData: { [key: string]: AggregationData[] }; } +/** + * Options used to configure an AzureTraceExporter. + */ export interface AzureTraceExporterOptions extends ExporterConfig { /** * The Instrumentation Key found in your application's Azure Monitor Application Insights