@fluidframework/telemetry-utils 1.2.7 → 2.0.0-dev.1.3.0.96595
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.js +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -7
- package/dist/config.js.map +1 -1
- package/dist/errorLogging.d.ts +10 -1
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js +75 -31
- package/dist/errorLogging.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +1 -6
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -8
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +2 -0
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +12 -0
- package/dist/mockLogger.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/sampledTelemetryHelper.d.ts +53 -0
- package/dist/sampledTelemetryHelper.d.ts.map +1 -0
- package/dist/sampledTelemetryHelper.js +92 -0
- package/dist/sampledTelemetryHelper.js.map +1 -0
- package/dist/thresholdCounter.d.ts +1 -1
- package/dist/thresholdCounter.js +1 -1
- package/dist/thresholdCounter.js.map +1 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +2 -7
- package/lib/config.js.map +1 -1
- package/lib/errorLogging.d.ts +10 -1
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js +74 -30
- package/lib/errorLogging.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/logger.d.ts +1 -6
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js +4 -8
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +2 -0
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +12 -0
- package/lib/mockLogger.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/sampledTelemetryHelper.d.ts +53 -0
- package/lib/sampledTelemetryHelper.d.ts.map +1 -0
- package/lib/sampledTelemetryHelper.js +88 -0
- package/lib/sampledTelemetryHelper.js.map +1 -0
- package/lib/thresholdCounter.d.ts +1 -1
- package/lib/thresholdCounter.js +1 -1
- package/lib/thresholdCounter.js.map +1 -1
- package/package.json +21 -10
- package/src/config.ts +2 -4
- package/src/errorLogging.ts +77 -30
- package/src/index.ts +1 -0
- package/src/logger.ts +4 -8
- package/src/mockLogger.ts +13 -0
- package/src/packageVersion.ts +1 -1
- package/src/sampledTelemetryHelper.ts +142 -0
- package/src/thresholdCounter.ts +1 -1
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/telemetry-utils";
|
|
8
|
-
export declare const pkgVersion = "1.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-dev.1.3.0.96595";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,oCAAoC,CAAC;AACzD,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,oCAAoC,CAAC;AACzD,eAAO,MAAM,UAAU,0BAA0B,CAAC"}
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,iCAAiC,CAAC;AACzD,MAAM,CAAC,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,iCAAiC,CAAC;AACzD,MAAM,CAAC,MAAM,UAAU,GAAG,uBAAuB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/telemetry-utils\";\nexport const pkgVersion = \"2.0.0-dev.1.3.0.96595\";\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { IDisposable, ITelemetryGenericEvent, ITelemetryLogger, ITelemetryProperties } from "@fluidframework/common-definitions";
|
|
6
|
+
/**
|
|
7
|
+
* Helper class that executes a specified code block and writes an
|
|
8
|
+
* {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified
|
|
9
|
+
* number of executions is reached (or when the class is disposed). The `duration` field in the telemetry event is
|
|
10
|
+
* the duration of the latest execution (sample) of the specified function. See the documentation of the
|
|
11
|
+
* `includeAggregateMetrics` parameter for additional details that can be included.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SampledTelemetryHelper implements IDisposable {
|
|
14
|
+
private readonly eventBase;
|
|
15
|
+
private readonly logger;
|
|
16
|
+
private readonly sampleThreshold;
|
|
17
|
+
private readonly includeAggregateMetrics;
|
|
18
|
+
private readonly perBucketProperties;
|
|
19
|
+
disposed: boolean;
|
|
20
|
+
private readonly measurementsMap;
|
|
21
|
+
/**
|
|
22
|
+
* @param eventBase -
|
|
23
|
+
* Custom properties to include in the telemetry performance event when it is written.
|
|
24
|
+
* @param logger -
|
|
25
|
+
* The logger to use to write the telemetry performance event.
|
|
26
|
+
* @param sampleThreshold -
|
|
27
|
+
* Telemetry performance events will be generated every time we hit this many executions of the code block.
|
|
28
|
+
* @param includeAggregateMetrics -
|
|
29
|
+
* If set to `true`, the telemetry performance event will include aggregated metrics (total duration, min duration,
|
|
30
|
+
* max duration) for all the executions in between generated events.
|
|
31
|
+
* @param perBucketProperties -
|
|
32
|
+
* Map of strings that represent different buckets (which can be specified when calling the 'measure' method), to
|
|
33
|
+
* properties which should be added to the telemetry event for that bucket. If a bucket being measured does not
|
|
34
|
+
* have an entry in this map, no additional properties will be added to its telemetry events. The following keys are
|
|
35
|
+
* reserved for use by this class: "duration", "count", "totalDuration", "minDuration", "maxDuration". If any of
|
|
36
|
+
* them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be
|
|
37
|
+
* ignored.
|
|
38
|
+
*/
|
|
39
|
+
constructor(eventBase: ITelemetryGenericEvent, logger: ITelemetryLogger, sampleThreshold: number, includeAggregateMetrics?: boolean, perBucketProperties?: Map<string, ITelemetryProperties>);
|
|
40
|
+
/**
|
|
41
|
+
* @param codeToMeasure -
|
|
42
|
+
* The code to be executed and measured.
|
|
43
|
+
* @param bucket -
|
|
44
|
+
* A key to track executions of the code block separately. Each different value of this parameter has a separate
|
|
45
|
+
* set of executions and metrics tracked by the class. If no such distinction needs to be made, do not provide a
|
|
46
|
+
* value.
|
|
47
|
+
* @returns Whatever the passed-in code block returns.
|
|
48
|
+
*/
|
|
49
|
+
measure<T>(codeToMeasure: () => T, bucket?: string): T;
|
|
50
|
+
private flushBucket;
|
|
51
|
+
dispose(error?: Error | undefined): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=sampledTelemetryHelper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampledTelemetryHelper.d.ts","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,WAAW,EACX,sBAAsB,EACtB,gBAAgB,EAEhB,oBAAoB,EACvB,MAAM,oCAAoC,CAAC;AAkC5C;;;;;;GAMG;AACF,qBAAa,sBAAuB,YAAW,WAAW;IAwBnD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IA3BxC,QAAQ,EAAE,OAAO,CAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IAEnE;;;;;;;;;;;;;;;;;OAiBG;gBAEkB,SAAS,EAAE,sBAAsB,EACjC,MAAM,EAAE,gBAAgB,EACxB,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,oCAA0C;IAGlF;;;;;;;;OAQG;IACI,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,GAAE,MAAW,GAAG,CAAC;IA0BjE,OAAO,CAAC,WAAW;IAoBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAGlD"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { performance } from "@fluidframework/common-utils";
|
|
6
|
+
/**
|
|
7
|
+
* Helper class that executes a specified code block and writes an
|
|
8
|
+
* {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified
|
|
9
|
+
* number of executions is reached (or when the class is disposed). The `duration` field in the telemetry event is
|
|
10
|
+
* the duration of the latest execution (sample) of the specified function. See the documentation of the
|
|
11
|
+
* `includeAggregateMetrics` parameter for additional details that can be included.
|
|
12
|
+
*/
|
|
13
|
+
export class SampledTelemetryHelper {
|
|
14
|
+
/**
|
|
15
|
+
* @param eventBase -
|
|
16
|
+
* Custom properties to include in the telemetry performance event when it is written.
|
|
17
|
+
* @param logger -
|
|
18
|
+
* The logger to use to write the telemetry performance event.
|
|
19
|
+
* @param sampleThreshold -
|
|
20
|
+
* Telemetry performance events will be generated every time we hit this many executions of the code block.
|
|
21
|
+
* @param includeAggregateMetrics -
|
|
22
|
+
* If set to `true`, the telemetry performance event will include aggregated metrics (total duration, min duration,
|
|
23
|
+
* max duration) for all the executions in between generated events.
|
|
24
|
+
* @param perBucketProperties -
|
|
25
|
+
* Map of strings that represent different buckets (which can be specified when calling the 'measure' method), to
|
|
26
|
+
* properties which should be added to the telemetry event for that bucket. If a bucket being measured does not
|
|
27
|
+
* have an entry in this map, no additional properties will be added to its telemetry events. The following keys are
|
|
28
|
+
* reserved for use by this class: "duration", "count", "totalDuration", "minDuration", "maxDuration". If any of
|
|
29
|
+
* them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be
|
|
30
|
+
* ignored.
|
|
31
|
+
*/
|
|
32
|
+
constructor(eventBase, logger, sampleThreshold, includeAggregateMetrics = false, perBucketProperties = new Map()) {
|
|
33
|
+
this.eventBase = eventBase;
|
|
34
|
+
this.logger = logger;
|
|
35
|
+
this.sampleThreshold = sampleThreshold;
|
|
36
|
+
this.includeAggregateMetrics = includeAggregateMetrics;
|
|
37
|
+
this.perBucketProperties = perBucketProperties;
|
|
38
|
+
this.disposed = false;
|
|
39
|
+
this.measurementsMap = new Map();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* @param codeToMeasure -
|
|
43
|
+
* The code to be executed and measured.
|
|
44
|
+
* @param bucket -
|
|
45
|
+
* A key to track executions of the code block separately. Each different value of this parameter has a separate
|
|
46
|
+
* set of executions and metrics tracked by the class. If no such distinction needs to be made, do not provide a
|
|
47
|
+
* value.
|
|
48
|
+
* @returns Whatever the passed-in code block returns.
|
|
49
|
+
*/
|
|
50
|
+
measure(codeToMeasure, bucket = "") {
|
|
51
|
+
var _a, _b, _c;
|
|
52
|
+
const start = performance.now();
|
|
53
|
+
const returnValue = codeToMeasure();
|
|
54
|
+
const duration = performance.now() - start;
|
|
55
|
+
let m = this.measurementsMap.get(bucket);
|
|
56
|
+
if (m === undefined) {
|
|
57
|
+
m = { count: 0, duration: -1 };
|
|
58
|
+
this.measurementsMap.set(bucket, m);
|
|
59
|
+
}
|
|
60
|
+
m.count++;
|
|
61
|
+
m.duration = duration;
|
|
62
|
+
if (this.includeAggregateMetrics) {
|
|
63
|
+
m.totalDuration = ((_a = m.totalDuration) !== null && _a !== void 0 ? _a : 0) + duration;
|
|
64
|
+
m.minDuration = Math.min((_b = m.minDuration) !== null && _b !== void 0 ? _b : duration, duration);
|
|
65
|
+
m.maxDuration = Math.max((_c = m.maxDuration) !== null && _c !== void 0 ? _c : 0, duration);
|
|
66
|
+
}
|
|
67
|
+
if (m.count >= this.sampleThreshold) {
|
|
68
|
+
this.flushBucket(bucket);
|
|
69
|
+
}
|
|
70
|
+
return returnValue;
|
|
71
|
+
}
|
|
72
|
+
flushBucket(bucket) {
|
|
73
|
+
const measurements = this.measurementsMap.get(bucket);
|
|
74
|
+
if (measurements === undefined) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (measurements.count !== 0) {
|
|
78
|
+
const bucketProperties = this.perBucketProperties.get(bucket);
|
|
79
|
+
const telemetryEvent = Object.assign(Object.assign(Object.assign({}, this.eventBase), bucketProperties), measurements);
|
|
80
|
+
this.logger.sendPerformanceEvent(telemetryEvent);
|
|
81
|
+
this.measurementsMap.delete(bucket);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
dispose(error) {
|
|
85
|
+
this.measurementsMap.forEach((_, k) => this.flushBucket(k));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=sampledTelemetryHelper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAiC3D;;;;;;GAMG;AACF,MAAM,OAAO,sBAAsB;IAKhC;;;;;;;;;;;;;;;;;OAiBG;IACH,YACqB,SAAiC,EACjC,MAAwB,EACxB,eAAuB,EACvB,0BAAmC,KAAK,EACxC,sBAAsB,IAAI,GAAG,EAAgC;QAJ7D,cAAS,GAAT,SAAS,CAAwB;QACjC,WAAM,GAAN,MAAM,CAAkB;QACxB,oBAAe,GAAf,eAAe,CAAQ;QACvB,4BAAuB,GAAvB,uBAAuB,CAAiB;QACxC,wBAAmB,GAAnB,mBAAmB,CAA0C;QA3BlF,aAAQ,GAAY,KAAK,CAAC;QAET,oBAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;IA0BnE,CAAC;IAED;;;;;;;;OAQG;IACI,OAAO,CAAI,aAAsB,EAAE,SAAiB,EAAE;;QACzD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAE3C,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,SAAS,EAAE;YACjB,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;SACvC;QACD,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEtB,IAAI,IAAI,CAAC,uBAAuB,EAAE;YAC9B,CAAC,CAAC,aAAa,GAAG,CAAC,MAAA,CAAC,CAAC,aAAa,mCAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YACpD,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAA,CAAC,CAAC,WAAW,mCAAI,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9D,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAA,CAAC,CAAC,WAAW,mCAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;SAC1D;QAED,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACjC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;SAC5B;QAED,OAAO,WAAW,CAAC;IACvB,CAAC;IAEO,WAAW,CAAC,MAAc;QAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,YAAY,KAAK,SAAS,EAAE;YAC5B,OAAO;SACV;QAED,IAAI,YAAY,CAAC,KAAK,KAAK,CAAC,EAAE;YAC1B,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAE9D,MAAM,cAAc,iDACb,IAAI,CAAC,SAAS,GACd,gBAAgB,GAChB,YAAY,CAClB,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SACvC;IACL,CAAC;IAEM,OAAO,CAAC,KAAyB;QACpC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;CACJ","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n IDisposable,\n ITelemetryGenericEvent,\n ITelemetryLogger,\n ITelemetryPerformanceEvent,\n ITelemetryProperties,\n} from \"@fluidframework/common-definitions\";\nimport { performance } from \"@fluidframework/common-utils\";\n\ninterface Measurements {\n // The names of the properties in this interface are the ones that will get stamped in the\n // telemetry event, changes should be considered carefully. The optional properties should\n // only be populated if 'includeAggregateMetrics' is true.\n\n /**\n * The duration of the latest execution.\n */\n duration: number;\n\n /**\n * The number of executions since the last time an event was generated.\n */\n count: number;\n\n /**\n * Total duration across all the executions since the last event was generated.\n */\n totalDuration?: number;\n\n /**\n * Min duration across all the executions since the last event was generated.\n */\n minDuration?: number;\n\n /**\n * Max duration across all the executions since the last event was generated.\n */\n maxDuration?: number;\n}\n\n/**\n * Helper class that executes a specified code block and writes an\n * {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified\n * number of executions is reached (or when the class is disposed). The `duration` field in the telemetry event is\n * the duration of the latest execution (sample) of the specified function. See the documentation of the\n * `includeAggregateMetrics` parameter for additional details that can be included.\n */\n export class SampledTelemetryHelper implements IDisposable {\n disposed: boolean = false;\n\n private readonly measurementsMap = new Map<string, Measurements>();\n\n /**\n * @param eventBase -\n * Custom properties to include in the telemetry performance event when it is written.\n * @param logger -\n * The logger to use to write the telemetry performance event.\n * @param sampleThreshold -\n * Telemetry performance events will be generated every time we hit this many executions of the code block.\n * @param includeAggregateMetrics -\n * If set to `true`, the telemetry performance event will include aggregated metrics (total duration, min duration,\n * max duration) for all the executions in between generated events.\n * @param perBucketProperties -\n * Map of strings that represent different buckets (which can be specified when calling the 'measure' method), to\n * properties which should be added to the telemetry event for that bucket. If a bucket being measured does not\n * have an entry in this map, no additional properties will be added to its telemetry events. The following keys are\n * reserved for use by this class: \"duration\", \"count\", \"totalDuration\", \"minDuration\", \"maxDuration\". If any of\n * them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be\n * ignored.\n */\n public constructor(\n private readonly eventBase: ITelemetryGenericEvent,\n private readonly logger: ITelemetryLogger,\n private readonly sampleThreshold: number,\n private readonly includeAggregateMetrics: boolean = false,\n private readonly perBucketProperties = new Map<string, ITelemetryProperties>()) {\n }\n\n /**\n * @param codeToMeasure -\n * The code to be executed and measured.\n * @param bucket -\n * A key to track executions of the code block separately. Each different value of this parameter has a separate\n * set of executions and metrics tracked by the class. If no such distinction needs to be made, do not provide a\n * value.\n * @returns Whatever the passed-in code block returns.\n */\n public measure<T>(codeToMeasure: () => T, bucket: string = \"\"): T {\n const start = performance.now();\n const returnValue = codeToMeasure();\n const duration = performance.now() - start;\n\n let m = this.measurementsMap.get(bucket);\n if (m === undefined) {\n m = { count: 0, duration: -1 };\n this.measurementsMap.set(bucket, m);\n }\n m.count++;\n m.duration = duration;\n\n if (this.includeAggregateMetrics) {\n m.totalDuration = (m.totalDuration ?? 0) + duration;\n m.minDuration = Math.min(m.minDuration ?? duration, duration);\n m.maxDuration = Math.max(m.maxDuration ?? 0, duration);\n }\n\n if (m.count >= this.sampleThreshold) {\n this.flushBucket(bucket);\n }\n\n return returnValue;\n }\n\n private flushBucket(bucket: string) {\n const measurements = this.measurementsMap.get(bucket);\n if (measurements === undefined) {\n return;\n }\n\n if (measurements.count !== 0) {\n const bucketProperties = this.perBucketProperties.get(bucket);\n\n const telemetryEvent: ITelemetryPerformanceEvent = {\n ...this.eventBase,\n ...bucketProperties, // If the bucket doesn't exist and this is undefined, things work as expected\n ...measurements,\n };\n\n this.logger.sendPerformanceEvent(telemetryEvent);\n this.measurementsMap.delete(bucket);\n }\n }\n\n public dispose(error?: Error | undefined): void {\n this.measurementsMap.forEach((_, k) => this.flushBucket(k));\n }\n}\n"]}
|
|
@@ -17,7 +17,7 @@ export declare class ThresholdCounter {
|
|
|
17
17
|
*/
|
|
18
18
|
send(eventName: string, value: number): void;
|
|
19
19
|
/**
|
|
20
|
-
* Sends the value if it's above the
|
|
20
|
+
* Sends the value if it's above the threshold
|
|
21
21
|
* and a multiple of the threshold.
|
|
22
22
|
*
|
|
23
23
|
* To be used in scenarios where we'd like to record a
|
package/lib/thresholdCounter.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IACzB,YACqB,SAAiB,EACjB,MAAwB,EACjC,oBAAoB,SAAS;QAFpB,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAkB;QACjC,sBAAiB,GAAjB,iBAAiB,CAAY;IACtC,CAAC;IAEJ;;OAEG;IACI,IAAI,CAAC,SAAiB,EAAE,KAAa;QACxC,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;YACxB,OAAO;SACV;QACD,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAC7B,SAAS;YACT,KAAK;SACR,CAAC,CAAC;IACP,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,SAAiB,EAAE,KAAa;QAClD,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB,EAAE;YAClC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAC7B,SAAS;gBACT,KAAK;aACR,CAAC,CAAC;YACH,sCAAsC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;SACvD;IACL,CAAC;CACJ","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\n\n/**\n * Utility counter which will send event only if the provided value\n * is above a configured threshold\n */\nexport class ThresholdCounter {\n public constructor(\n private readonly threshold: number,\n private readonly logger: ITelemetryLogger,\n private thresholdMultiple = threshold,\n ) {}\n\n /**\n * Sends the value if it's above the treshold.\n */\n public send(eventName: string, value: number) {\n if (value < this.threshold) {\n return;\n }\n this.logger.sendPerformanceEvent({\n eventName,\n value,\n });\n }\n\n /**\n * Sends the value if it's above the
|
|
1
|
+
{"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IACzB,YACqB,SAAiB,EACjB,MAAwB,EACjC,oBAAoB,SAAS;QAFpB,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAkB;QACjC,sBAAiB,GAAjB,iBAAiB,CAAY;IACtC,CAAC;IAEJ;;OAEG;IACI,IAAI,CAAC,SAAiB,EAAE,KAAa;QACxC,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;YACxB,OAAO;SACV;QACD,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAC7B,SAAS;YACT,KAAK;SACR,CAAC,CAAC;IACP,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,SAAiB,EAAE,KAAa;QAClD,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB,EAAE;YAClC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAC7B,SAAS;gBACT,KAAK;aACR,CAAC,CAAC;YACH,sCAAsC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;SACvD;IACL,CAAC;CACJ","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\n\n/**\n * Utility counter which will send event only if the provided value\n * is above a configured threshold\n */\nexport class ThresholdCounter {\n public constructor(\n private readonly threshold: number,\n private readonly logger: ITelemetryLogger,\n private thresholdMultiple = threshold,\n ) {}\n\n /**\n * Sends the value if it's above the treshold.\n */\n public send(eventName: string, value: number) {\n if (value < this.threshold) {\n return;\n }\n this.logger.sendPerformanceEvent({\n eventName,\n value,\n });\n }\n\n /**\n * Sends the value if it's above the threshold\n * and a multiple of the threshold.\n *\n * To be used in scenarios where we'd like to record a\n * threshold violation while reducing telemetry noise.\n */\n public sendIfMultiple(eventName: string, value: number) {\n if (value === this.thresholdMultiple) {\n this.logger.sendPerformanceEvent({\n eventName,\n value,\n });\n // reduce number of \"multiple\" events.\n this.thresholdMultiple = this.thresholdMultiple * 2;\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/telemetry-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.0.0-dev.1.3.0.96595",
|
|
4
4
|
"description": "Collection of telemetry relates utilities for Fluid",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -65,17 +65,17 @@
|
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
68
|
-
"@fluidframework/common-utils": "^0.
|
|
68
|
+
"@fluidframework/common-utils": "^1.0.0",
|
|
69
69
|
"debug": "^4.1.1",
|
|
70
70
|
"events": "^3.1.0",
|
|
71
71
|
"uuid": "^8.3.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@fluidframework/build-common": "^0.
|
|
75
|
-
"@fluidframework/build-tools": "^0.
|
|
76
|
-
"@fluidframework/eslint-config-fluid": "^0.
|
|
77
|
-
"@fluidframework/mocha-test-setup": "
|
|
78
|
-
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils
|
|
74
|
+
"@fluidframework/build-common": "^1.0.0",
|
|
75
|
+
"@fluidframework/build-tools": "^0.4.6000",
|
|
76
|
+
"@fluidframework/eslint-config-fluid": "^1.0.0",
|
|
77
|
+
"@fluidframework/mocha-test-setup": "2.0.0-dev.1.3.0.96595",
|
|
78
|
+
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@^1.0.0",
|
|
79
79
|
"@microsoft/api-extractor": "^7.22.2",
|
|
80
80
|
"@rushstack/eslint-config": "^2.5.1",
|
|
81
81
|
"@types/debug": "^4.1.5",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"@types/mocha": "^9.1.1",
|
|
84
84
|
"@types/node": "^14.18.0",
|
|
85
85
|
"concurrently": "^6.2.0",
|
|
86
|
-
"copyfiles": "^2.1
|
|
86
|
+
"copyfiles": "^2.4.1",
|
|
87
87
|
"cross-env": "^7.0.2",
|
|
88
88
|
"eslint": "~8.6.0",
|
|
89
89
|
"mocha": "^10.0.0",
|
|
@@ -93,7 +93,18 @@
|
|
|
93
93
|
"typescript": "~4.5.5"
|
|
94
94
|
},
|
|
95
95
|
"typeValidation": {
|
|
96
|
-
"version": "
|
|
97
|
-
"broken": {
|
|
96
|
+
"version": "2.0.0",
|
|
97
|
+
"broken": {
|
|
98
|
+
"RemovedFunctionDeclaration_originatedAsExternalError": {
|
|
99
|
+
"forwardCompat": false,
|
|
100
|
+
"backCompat": false
|
|
101
|
+
},
|
|
102
|
+
"EnumDeclaration_TelemetryDataTag": {
|
|
103
|
+
"forwardCompat": false
|
|
104
|
+
},
|
|
105
|
+
"ClassDeclaration_MockLogger": {
|
|
106
|
+
"forwardCompat": false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
98
109
|
}
|
|
99
110
|
}
|
package/src/config.ts
CHANGED
|
@@ -142,11 +142,9 @@ function stronglyTypedParse(input: ConfigTypes): StronglyTypedValue | undefined
|
|
|
142
142
|
return defaultReturn;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
/**
|
|
145
|
+
/** `sessionStorage` is undefined in some environments such as Node */
|
|
146
146
|
const safeSessionStorage = (): Storage | undefined => {
|
|
147
|
-
|
|
148
|
-
return sessionStorage !== null ? sessionStorage : undefined;
|
|
149
|
-
} catch { return undefined; }
|
|
147
|
+
return globalThis.sessionStorage;
|
|
150
148
|
};
|
|
151
149
|
|
|
152
150
|
/**
|
package/src/errorLogging.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ITaggedTelemetryPropertyType,
|
|
9
9
|
ITelemetryLogger,
|
|
10
10
|
ITelemetryProperties,
|
|
11
|
+
TelemetryEventPropertyType,
|
|
11
12
|
} from "@fluidframework/common-definitions";
|
|
12
13
|
import { v4 as uuid } from "uuid";
|
|
13
14
|
import {
|
|
@@ -111,7 +112,7 @@ export function normalizeError(
|
|
|
111
112
|
|
|
112
113
|
// We have to construct a new Fluid Error, copying safe properties over
|
|
113
114
|
const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);
|
|
114
|
-
const fluidError: IFluidErrorBase = new
|
|
115
|
+
const fluidError: IFluidErrorBase = new NormalizedLoggingError({
|
|
115
116
|
message,
|
|
116
117
|
stack,
|
|
117
118
|
});
|
|
@@ -129,11 +130,13 @@ export function normalizeError(
|
|
|
129
130
|
fluidError.addTelemetryProperties({ typeofError: typeof (error) });
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
const
|
|
133
|
+
const errorTelemetryProps = LoggingError.typeCheck(error)
|
|
134
|
+
? error.getTelemetryProperties()
|
|
135
|
+
: { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase
|
|
136
|
+
|
|
133
137
|
fluidError.addTelemetryProperties({
|
|
134
|
-
...
|
|
138
|
+
...errorTelemetryProps,
|
|
135
139
|
...annotations.props,
|
|
136
|
-
untrustedOrigin: 1, // This will let us filter to errors not originated by our own code
|
|
137
140
|
});
|
|
138
141
|
|
|
139
142
|
return fluidError;
|
|
@@ -150,7 +153,7 @@ let stackPopulatedOnCreation: boolean | undefined;
|
|
|
150
153
|
* Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.
|
|
151
154
|
* @returns Error object that has stack populated.
|
|
152
155
|
*/
|
|
153
|
-
|
|
156
|
+
export function generateErrorWithStack(): Error {
|
|
154
157
|
const err = new Error("<<generated stack>>");
|
|
155
158
|
|
|
156
159
|
if (stackPopulatedOnCreation === undefined) {
|
|
@@ -250,21 +253,59 @@ function overwriteStack(error: IFluidErrorBase | LoggingError, stack: string) {
|
|
|
250
253
|
|
|
251
254
|
/**
|
|
252
255
|
* True for any error object that is an (optionally normalized) external error
|
|
253
|
-
* False for any error we created and raised within the FF codebase
|
|
256
|
+
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
257
|
+
* or wrapped in a well-known error type
|
|
254
258
|
*/
|
|
255
259
|
export function isExternalError(e: any): boolean {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
260
|
+
// LoggingErrors are an internal FF error type. However, an external error can be converted
|
|
261
|
+
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
|
|
262
|
+
// determine whether the original error was infact external.
|
|
263
|
+
if (LoggingError.typeCheck(e)) {
|
|
264
|
+
if ((e as NormalizedLoggingError).errorType === NORMALIZED_ERROR_TYPE) {
|
|
265
|
+
return e.getTelemetryProperties().untrustedOrigin === 1;
|
|
266
|
+
}
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
return !isValidLegacyError(e);
|
|
259
270
|
}
|
|
260
271
|
|
|
261
272
|
/**
|
|
262
273
|
* Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property
|
|
263
274
|
*/
|
|
264
275
|
export function isTaggedTelemetryPropertyValue(x: any): x is ITaggedTelemetryPropertyType {
|
|
265
|
-
return
|
|
276
|
+
return typeof (x?.tag) === "string";
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Filter serializable telemetry properties
|
|
281
|
+
* @param x - any telemetry prop
|
|
282
|
+
* @returns - as-is if x is primitive. returns stringified if x is an array of primitive.
|
|
283
|
+
* otherwise returns null since this is what we support at the moment.
|
|
284
|
+
*/
|
|
285
|
+
function filterValidTelemetryProps(x: any, key: string): TelemetryEventPropertyType {
|
|
286
|
+
if (Array.isArray(x) && x.every((val) => isTelemetryEventPropertyValue(val))) {
|
|
287
|
+
return JSON.stringify(x);
|
|
288
|
+
}
|
|
289
|
+
if (isTelemetryEventPropertyValue(x)) {
|
|
290
|
+
return x;
|
|
291
|
+
}
|
|
292
|
+
// We don't support logging arbitrary objects
|
|
293
|
+
console.error(`UnSupported Format of Logging Error Property for key ${key}:`, x);
|
|
294
|
+
return "REDACTED (arbitrary object)";
|
|
266
295
|
}
|
|
267
296
|
|
|
297
|
+
// checking type of x, returns false if x is null
|
|
298
|
+
function isTelemetryEventPropertyValue(x: any): x is TelemetryEventPropertyType {
|
|
299
|
+
switch (typeof x) {
|
|
300
|
+
case "string":
|
|
301
|
+
case "number":
|
|
302
|
+
case "boolean":
|
|
303
|
+
case "undefined":
|
|
304
|
+
return true;
|
|
305
|
+
default:
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
268
309
|
/**
|
|
269
310
|
* Walk an object's enumerable properties to find those fit for telemetry.
|
|
270
311
|
*/
|
|
@@ -275,22 +316,15 @@ function getValidTelemetryProps(obj: any, keysToOmit: Set<string>): ITelemetryPr
|
|
|
275
316
|
continue;
|
|
276
317
|
}
|
|
277
318
|
const val = obj[key];
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
props[key] = val;
|
|
288
|
-
} else {
|
|
289
|
-
// We don't support logging arbitrary objects
|
|
290
|
-
props[key] = "REDACTED (arbitrary object)";
|
|
291
|
-
}
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
319
|
+
|
|
320
|
+
// ensure only valid props get logged, since props of logging error could be in any shape
|
|
321
|
+
if (isTaggedTelemetryPropertyValue(val)) {
|
|
322
|
+
props[key] = {
|
|
323
|
+
value: filterValidTelemetryProps(val.value, key),
|
|
324
|
+
tag: val.tag,
|
|
325
|
+
};
|
|
326
|
+
} else {
|
|
327
|
+
props[key] = filterValidTelemetryProps(val, key);
|
|
294
328
|
}
|
|
295
329
|
}
|
|
296
330
|
return props;
|
|
@@ -354,6 +388,20 @@ export class LoggingError extends Error implements ILoggingError, Omit<IFluidErr
|
|
|
354
388
|
}
|
|
355
389
|
}
|
|
356
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Determines if a given object is an instance of a LoggingError
|
|
393
|
+
* @param object - any object
|
|
394
|
+
* @returns - true if the object is an instance of a LoggingError, false if not.
|
|
395
|
+
*/
|
|
396
|
+
public static typeCheck(object: unknown): object is LoggingError {
|
|
397
|
+
if (typeof object === "object" && object !== null) {
|
|
398
|
+
return typeof (object as LoggingError).addTelemetryProperties === "function"
|
|
399
|
+
&& typeof (object as LoggingError).getTelemetryProperties === "function"
|
|
400
|
+
&& typeof (object as LoggingError).errorInstanceId === "string";
|
|
401
|
+
}
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
|
|
357
405
|
/**
|
|
358
406
|
* Add additional properties to be logged
|
|
359
407
|
*/
|
|
@@ -377,12 +425,11 @@ export class LoggingError extends Error implements ILoggingError, Omit<IFluidErr
|
|
|
377
425
|
}
|
|
378
426
|
|
|
379
427
|
/** The Error class used when normalizing an external error */
|
|
380
|
-
|
|
428
|
+
export const NORMALIZED_ERROR_TYPE = "genericError";
|
|
429
|
+
class NormalizedLoggingError extends LoggingError {
|
|
381
430
|
// errorType "genericError" is used as a default value throughout the code.
|
|
382
431
|
// Note that this matches ContainerErrorType/DriverErrorType's genericError
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
errorType = NormalizedExternalError.normalizedErrorType;
|
|
432
|
+
errorType = NORMALIZED_ERROR_TYPE;
|
|
386
433
|
|
|
387
434
|
constructor(
|
|
388
435
|
errorProps: Pick<IFluidErrorBase,
|
package/src/index.ts
CHANGED
package/src/logger.ts
CHANGED
|
@@ -32,11 +32,6 @@ import {
|
|
|
32
32
|
* Please do not modify existing entries for backwards compatibility.
|
|
33
33
|
*/
|
|
34
34
|
export enum TelemetryDataTag {
|
|
35
|
-
/**
|
|
36
|
-
* Data containing terms from code packages that may have been dynamically loaded
|
|
37
|
-
* @deprecated 1.0, will be removed in next release (see issue #6603). Use `TelemetryDataTag.CodeArtifact` instead.
|
|
38
|
-
*/
|
|
39
|
-
PackageData = "PackageData",
|
|
40
35
|
/** Data containing terms or IDs from code packages that may have been dynamically loaded */
|
|
41
36
|
CodeArtifact = "CodeArtifact",
|
|
42
37
|
/** Personal data of a variety of classifications that pertains to the user */
|
|
@@ -249,8 +244,9 @@ export abstract class TelemetryLogger implements ITelemetryLogger {
|
|
|
249
244
|
// No tag means we can log plainly
|
|
250
245
|
newEvent[key] = value;
|
|
251
246
|
break;
|
|
252
|
-
case
|
|
253
|
-
|
|
247
|
+
case "PackageData": // For back-compat
|
|
248
|
+
case TelemetryDataTag.CodeArtifact:
|
|
249
|
+
// For Microsoft applications, CodeArtifact is safe for now
|
|
254
250
|
// (we don't load 3P code in 1P apps)
|
|
255
251
|
newEvent[key] = value;
|
|
256
252
|
break;
|
|
@@ -279,7 +275,7 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
279
275
|
/**
|
|
280
276
|
* Create child logger
|
|
281
277
|
* @param baseLogger - Base logger to use to output events. If undefined, proper child logger
|
|
282
|
-
* is created, but it does not
|
|
278
|
+
* is created, but it does not send telemetry events anywhere.
|
|
283
279
|
* @param namespace - Telemetry event name prefix to add to all events
|
|
284
280
|
* @param properties - Base properties to add to all events
|
|
285
281
|
* @param propertyGetters - Getters to add additional properties to all events
|
package/src/mockLogger.ts
CHANGED
|
@@ -71,6 +71,19 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
71
71
|
expected:
|
|
72
72
|
${JSON.stringify(expectedEvents)}
|
|
73
73
|
|
|
74
|
+
actual:
|
|
75
|
+
${JSON.stringify(actualEvents)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
|
|
80
|
+
assertMatchNone(disallowedEvents: Omit<ITelemetryBaseEvent, "category">[], message?: string) {
|
|
81
|
+
const actualEvents = this.events;
|
|
82
|
+
if (this.matchAnyEvent(disallowedEvents)) {
|
|
83
|
+
throw new Error(`${message}
|
|
84
|
+
disallowed events:
|
|
85
|
+
${JSON.stringify(disallowedEvents)}
|
|
86
|
+
|
|
74
87
|
actual:
|
|
75
88
|
${JSON.stringify(actualEvents)}`);
|
|
76
89
|
}
|
package/src/packageVersion.ts
CHANGED