@fluidframework/telemetry-utils 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191457
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/.eslintrc.js +2 -1
- package/CHANGELOG.md +108 -0
- package/README.md +4 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +34 -36
- package/dist/config.js.map +1 -1
- package/dist/error.d.ts +92 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +133 -0
- package/dist/error.js.map +1 -0
- package/dist/errorLogging.d.ts +44 -19
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js +70 -31
- package/dist/errorLogging.js.map +1 -1
- package/dist/eventEmitterWithErrorHandling.d.ts +3 -3
- package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/dist/eventEmitterWithErrorHandling.js +10 -3
- package/dist/eventEmitterWithErrorHandling.js.map +1 -1
- package/dist/events.d.ts +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/fluidErrorBase.d.ts +48 -15
- package/dist/fluidErrorBase.d.ts.map +1 -1
- package/dist/fluidErrorBase.js +21 -14
- package/dist/fluidErrorBase.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -8
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +98 -60
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +193 -124
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +17 -8
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +49 -28
- package/dist/mockLogger.js.map +1 -1
- package/dist/sampledTelemetryHelper.d.ts +8 -7
- package/dist/sampledTelemetryHelper.d.ts.map +1 -1
- package/dist/sampledTelemetryHelper.js +21 -16
- package/dist/sampledTelemetryHelper.js.map +1 -1
- package/dist/telemetryTypes.d.ts +20 -6
- package/dist/telemetryTypes.d.ts.map +1 -1
- package/dist/telemetryTypes.js.map +1 -1
- package/dist/thresholdCounter.d.ts.map +1 -1
- package/dist/thresholdCounter.js.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/lib/config.d.ts +2 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +33 -36
- package/lib/config.js.map +1 -1
- package/lib/error.d.ts +92 -0
- package/lib/error.d.ts.map +1 -0
- package/lib/error.js +125 -0
- package/lib/error.js.map +1 -0
- package/lib/errorLogging.d.ts +44 -19
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js +69 -31
- package/lib/errorLogging.js.map +1 -1
- package/lib/eventEmitterWithErrorHandling.d.ts +3 -3
- package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/lib/eventEmitterWithErrorHandling.js +9 -2
- package/lib/eventEmitterWithErrorHandling.js.map +1 -1
- package/lib/events.d.ts +1 -1
- package/lib/events.d.ts.map +1 -1
- package/lib/events.js.map +1 -1
- package/lib/fluidErrorBase.d.ts +48 -15
- package/lib/fluidErrorBase.d.ts.map +1 -1
- package/lib/fluidErrorBase.js +21 -14
- package/lib/fluidErrorBase.js.map +1 -1
- package/lib/index.d.ts +5 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -4
- package/lib/index.js.map +1 -1
- package/lib/logger.d.ts +98 -60
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js +184 -119
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +17 -8
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +50 -29
- package/lib/mockLogger.js.map +1 -1
- package/lib/sampledTelemetryHelper.d.ts +8 -7
- package/lib/sampledTelemetryHelper.d.ts.map +1 -1
- package/lib/sampledTelemetryHelper.js +19 -14
- package/lib/sampledTelemetryHelper.js.map +1 -1
- package/lib/telemetryTypes.d.ts +20 -6
- package/lib/telemetryTypes.d.ts.map +1 -1
- package/lib/telemetryTypes.js.map +1 -1
- package/lib/thresholdCounter.d.ts.map +1 -1
- package/lib/thresholdCounter.js.map +1 -1
- package/lib/utils.d.ts +2 -2
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +2 -2
- package/lib/utils.js.map +1 -1
- package/package.json +19 -22
- package/src/config.ts +23 -13
- package/src/error.ts +202 -0
- package/src/errorLogging.ts +101 -56
- package/src/eventEmitterWithErrorHandling.ts +5 -3
- package/src/events.ts +3 -3
- package/src/fluidErrorBase.ts +62 -26
- package/src/index.ts +17 -6
- package/src/logger.ts +290 -120
- package/src/mockLogger.ts +65 -24
- package/src/sampledTelemetryHelper.ts +18 -14
- package/src/telemetryTypes.ts +29 -6
- package/src/thresholdCounter.ts +2 -2
- package/src/utils.ts +2 -2
- package/dist/debugLogger.d.ts +0 -39
- package/dist/debugLogger.d.ts.map +0 -1
- package/dist/debugLogger.js +0 -112
- package/dist/debugLogger.js.map +0 -1
- package/lib/debugLogger.d.ts +0 -39
- package/lib/debugLogger.d.ts.map +0 -1
- package/lib/debugLogger.js +0 -108
- package/lib/debugLogger.js.map +0 -1
- package/src/debugLogger.ts +0 -143
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAqC3D;;;;;;GAMG;AACH,MAAM,OAAO,sBAAsB;IAKlC;;;;;;;;;;;;;;;;;OAiBG;IACH,YACkB,SAAiC,EACjC,MAA2B,EAC3B,eAAuB,EACvB,0BAAmC,KAAK,EACxC,sBAAsB,IAAI,GAAG,EAAgC;QAJ7D,cAAS,GAAT,SAAS,CAAwB;QACjC,WAAM,GAAN,MAAM,CAAqB;QAC3B,oBAAe,GAAf,eAAe,CAAQ;QACvB,4BAAuB,GAAvB,uBAAuB,CAAiB;QACxC,wBAAmB,GAAnB,mBAAmB,CAA0C;QA3B/E,aAAQ,GAAY,KAAK,CAAC;QAET,oBAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;IA0BhE,CAAC;IAEJ;;;;;;;;;OASG;IACI,OAAO,CAAI,aAAsB,EAAE,SAAiB,EAAE;QAC5D,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;YACpB,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;SACpC;QACD,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEtB,IAAI,IAAI,CAAC,uBAAuB,EAAE;YACjC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YACpD,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9D,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;SACvD;QAED,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACpC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;SACzB;QAED,OAAO,WAAW,CAAC;IACpB,CAAC;IAEO,WAAW,CAAC,MAAc;QACjC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,YAAY,KAAK,SAAS,EAAE;YAC/B,OAAO;SACP;QAED,IAAI,YAAY,CAAC,KAAK,KAAK,CAAC,EAAE;YAC7B,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAE9D,MAAM,cAAc,GAA+B;gBAClD,GAAG,IAAI,CAAC,SAAS;gBACjB,GAAG,gBAAgB;gBACnB,GAAG,YAAY;aACf,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SACpC;IACF,CAAC;IAEM,OAAO,CAAC,KAAyB;QACvC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE;YAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tITelemetryGenericEvent,\n\tITelemetryPerformanceEvent,\n\tITelemetryProperties,\n\tIDisposable,\n} from \"@fluidframework/core-interfaces\";\nimport { performance } from \"@fluid-internal/client-utils\";\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\n\n/**\n * @privateRemarks\n *\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 */\ninterface Measurements {\n\t/**\n\t * The duration of the latest execution.\n\t */\n\tduration: number;\n\n\t/**\n\t * The number of executions since the last time an event was generated.\n\t */\n\tcount: number;\n\n\t/**\n\t * Total duration across all the executions since the last event was generated.\n\t */\n\ttotalDuration?: number;\n\n\t/**\n\t * Min duration across all the executions since the last event was generated.\n\t */\n\tminDuration?: number;\n\n\t/**\n\t * Max duration across all the executions since the last event was generated.\n\t */\n\tmaxDuration?: number;\n}\n\n/**\n * Helper class that executes a specified code block and writes an\n * {@link @fluidframework/core-interfaces#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 */\nexport class SampledTelemetryHelper implements IDisposable {\n\tdisposed: boolean = false;\n\n\tprivate readonly measurementsMap = new Map<string, Measurements>();\n\n\t/**\n\t * @param eventBase -\n\t * Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger -\n\t * The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold -\n\t * Telemetry performance events will be generated every time we hit this many executions of the code block.\n\t * @param includeAggregateMetrics -\n\t * If set to `true`, the telemetry performance event will include aggregated metrics (total duration, min duration,\n\t * max duration) for all the executions in between generated events.\n\t * @param perBucketProperties -\n\t * Map of strings that represent different buckets (which can be specified when calling the 'measure' method), to\n\t * properties which should be added to the telemetry event for that bucket. If a bucket being measured does not\n\t * have an entry in this map, no additional properties will be added to its telemetry events. The following keys are\n\t * reserved for use by this class: \"duration\", \"count\", \"totalDuration\", \"minDuration\", \"maxDuration\". If any of\n\t * them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be\n\t * ignored.\n\t */\n\tpublic constructor(\n\t\tprivate readonly eventBase: ITelemetryGenericEvent,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly sampleThreshold: number,\n\t\tprivate readonly includeAggregateMetrics: boolean = false,\n\t\tprivate readonly perBucketProperties = new Map<string, ITelemetryProperties>(),\n\t) {}\n\n\t/**\n\t * Executes the specified code and keeps track of execution time statistics.\n\t * If it's been called enough times (the sampleThreshold for the class) then it generates a log message with the necessary information.\n\t *\n\t * @param codeToMeasure - The code to be executed and measured.\n\t * @param bucket - A key to track executions of the code block separately.\n\t * Each different value of this parameter has a separate set of executions and metrics tracked by the class.\n\t * If no such distinction needs to be made, do not provide a value.\n\t * @returns Whatever the passed-in code block returns.\n\t */\n\tpublic measure<T>(codeToMeasure: () => T, bucket: string = \"\"): T {\n\t\tconst start = performance.now();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performance.now() - start;\n\n\t\tlet m = this.measurementsMap.get(bucket);\n\t\tif (m === undefined) {\n\t\t\tm = { count: 0, duration: -1 };\n\t\t\tthis.measurementsMap.set(bucket, m);\n\t\t}\n\t\tm.count++;\n\t\tm.duration = duration;\n\n\t\tif (this.includeAggregateMetrics) {\n\t\t\tm.totalDuration = (m.totalDuration ?? 0) + duration;\n\t\t\tm.minDuration = Math.min(m.minDuration ?? duration, duration);\n\t\t\tm.maxDuration = Math.max(m.maxDuration ?? 0, duration);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate flushBucket(bucket: string): void {\n\t\tconst measurements = this.measurementsMap.get(bucket);\n\t\tif (measurements === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (measurements.count !== 0) {\n\t\t\tconst bucketProperties = this.perBucketProperties.get(bucket);\n\n\t\t\tconst telemetryEvent: ITelemetryPerformanceEvent = {\n\t\t\t\t...this.eventBase,\n\t\t\t\t...bucketProperties, // If the bucket doesn't exist and this is undefined, things work as expected\n\t\t\t\t...measurements,\n\t\t\t};\n\n\t\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\t\t\tthis.measurementsMap.delete(bucket);\n\t\t}\n\t}\n\n\tpublic dispose(error?: Error | undefined): void {\n\t\tfor (const [k] of this.measurementsMap.entries()) this.flushBucket(k);\n\t}\n}\n"]}
|
package/lib/telemetryTypes.d.ts
CHANGED
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { ITelemetryBaseLogger,
|
|
5
|
+
import { ITelemetryBaseLogger, LogLevel, Tagged } from "@fluidframework/core-interfaces";
|
|
6
|
+
/**
|
|
7
|
+
* The categories FF uses when instrumenting the code.
|
|
8
|
+
*
|
|
9
|
+
* generic - Informational log event
|
|
10
|
+
* error - Error log event, ideally 0 of these are logged during a session
|
|
11
|
+
* performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking
|
|
12
|
+
*/
|
|
13
|
+
export declare type TelemetryEventCategory = "generic" | "error" | "performance";
|
|
6
14
|
/**
|
|
7
15
|
* Property types that can be logged.
|
|
8
|
-
* Includes extra types beyond
|
|
16
|
+
* Includes extra types beyond TelemetryBaseEventPropertyType, which must be converted before sending to a base logger
|
|
9
17
|
*/
|
|
10
18
|
export declare type TelemetryEventPropertyTypeExt = string | number | boolean | undefined | (string | number | boolean)[] | {
|
|
11
19
|
[key: string]: // Flat objects can have the same properties as the event itself
|
|
@@ -15,6 +23,8 @@ export declare type TelemetryEventPropertyTypeExt = string | number | boolean |
|
|
|
15
23
|
* A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used
|
|
16
24
|
* to mark pieces of information that should be organized or handled differently by loggers in various first or third
|
|
17
25
|
* party scenarios. For example, tags are used to mark personal information that should not be stored in logs.
|
|
26
|
+
*
|
|
27
|
+
* @deprecated Use Tagged<TelemetryEventPropertyTypeExt>
|
|
18
28
|
*/
|
|
19
29
|
export interface ITaggedTelemetryPropertyTypeExt {
|
|
20
30
|
value: TelemetryEventPropertyTypeExt;
|
|
@@ -24,7 +34,7 @@ export interface ITaggedTelemetryPropertyTypeExt {
|
|
|
24
34
|
* JSON-serializable properties, which will be logged with telemetry.
|
|
25
35
|
*/
|
|
26
36
|
export interface ITelemetryPropertiesExt {
|
|
27
|
-
[index: string]: TelemetryEventPropertyTypeExt |
|
|
37
|
+
[index: string]: TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>;
|
|
28
38
|
}
|
|
29
39
|
/**
|
|
30
40
|
* Interface for logging telemetry statements.
|
|
@@ -68,17 +78,21 @@ export interface ITelemetryLoggerExt extends ITelemetryBaseLogger {
|
|
|
68
78
|
* Send information telemetry event
|
|
69
79
|
* @param event - Event to send
|
|
70
80
|
* @param error - optional error object to log
|
|
81
|
+
* @param logLevel - optional level of the log.
|
|
71
82
|
*/
|
|
72
|
-
sendTelemetryEvent(event: ITelemetryGenericEventExt, error?:
|
|
83
|
+
sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.default): void;
|
|
73
84
|
/**
|
|
74
85
|
* Send error telemetry event
|
|
75
86
|
* @param event - Event to send
|
|
87
|
+
* @param error - optional error object to log
|
|
76
88
|
*/
|
|
77
|
-
sendErrorEvent(event: ITelemetryErrorEventExt, error?:
|
|
89
|
+
sendErrorEvent(event: ITelemetryErrorEventExt, error?: unknown): void;
|
|
78
90
|
/**
|
|
79
91
|
* Send performance telemetry event
|
|
80
92
|
* @param event - Event to send
|
|
93
|
+
* @param error - optional error object to log
|
|
94
|
+
* @param logLevel - optional level of the log.
|
|
81
95
|
*/
|
|
82
|
-
sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?:
|
|
96
|
+
sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.default): void;
|
|
83
97
|
}
|
|
84
98
|
//# sourceMappingURL=telemetryTypes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetryTypes.d.ts","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"telemetryTypes.d.ts","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzF;;;;;;GAMG;AACH,oBAAY,sBAAsB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEzE;;;GAGG;AACH,oBAAY,6BAA6B,GACtC,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,GAC7B;IACA,CAAC,GAAG,EAAE,MAAM,GACZ,AADe,gEAAgE;IAC/E,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;CACrE,CAAC;AAEL;;;;;;GAMG;AACH,MAAM,WAAW,+BAA+B;IAC/C,KAAK,EAAE,6BAA6B,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,CAAC,KAAK,EAAE,MAAM,GAAG,6BAA6B,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;CACvF;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACvE,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,6BAA8B,SAAQ,yBAAyB;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,oBAAoB;IAChE;;;;;OAKG;IACH,kBAAkB,CACjB,KAAK,EAAE,yBAAyB,EAChC,KAAK,CAAC,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,GAC1D,IAAI,CAAC;IAER;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,uBAAuB,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEtE;;;;;OAKG;IACH,oBAAoB,CACnB,KAAK,EAAE,6BAA6B,EACpC,KAAK,CAAC,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,GAC1D,IAAI,CAAC;CACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetryTypes.js","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseLogger,
|
|
1
|
+
{"version":3,"file":"telemetryTypes.js","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseLogger, LogLevel, Tagged } from \"@fluidframework/core-interfaces\";\n\n/**\n * The categories FF uses when instrumenting the code.\n *\n * generic - Informational log event\n * error - Error log event, ideally 0 of these are logged during a session\n * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking\n */\nexport type TelemetryEventCategory = \"generic\" | \"error\" | \"performance\";\n\n/**\n * Property types that can be logged.\n * Includes extra types beyond TelemetryBaseEventPropertyType, which must be converted before sending to a base logger\n */\nexport type TelemetryEventPropertyTypeExt =\n\t| string\n\t| number\n\t| boolean\n\t| undefined\n\t| (string | number | boolean)[]\n\t| {\n\t\t\t[key: string]: // Flat objects can have the same properties as the event itself\n\t\t\tstring | number | boolean | undefined | (string | number | boolean)[];\n\t };\n\n/**\n * A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used\n * to mark pieces of information that should be organized or handled differently by loggers in various first or third\n * party scenarios. For example, tags are used to mark personal information that should not be stored in logs.\n *\n * @deprecated Use Tagged<TelemetryEventPropertyTypeExt>\n */\nexport interface ITaggedTelemetryPropertyTypeExt {\n\tvalue: TelemetryEventPropertyTypeExt;\n\ttag: string;\n}\n\n/**\n * JSON-serializable properties, which will be logged with telemetry.\n */\nexport interface ITelemetryPropertiesExt {\n\t[index: string]: TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>;\n}\n\n/**\n * Interface for logging telemetry statements.\n * Can contain any number of properties that get serialized as json payload.\n * @param category - category of the event, like \"error\", \"performance\", \"generic\", etc.\n * @param eventName - name of the event.\n */\nexport interface ITelemetryEventExt extends ITelemetryPropertiesExt {\n\tcategory: string;\n\teventName: string;\n}\n\n/**\n * Informational (non-error) telemetry event\n * Maps to category = \"generic\"\n */\nexport interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n\tcategory?: TelemetryEventCategory;\n}\n\n/**\n * Error telemetry event.\n * Maps to category = \"error\"\n */\nexport interface ITelemetryErrorEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n}\n\n/**\n * Performance telemetry event.\n * Maps to category = \"performance\"\n */\nexport interface ITelemetryPerformanceEventExt extends ITelemetryGenericEventExt {\n\tduration?: number; // Duration of event (optional)\n}\n\n/**\n * An extended TelemetryLogger interface which allows for more lenient event types.\n * This interface is meant to be used internally within the Fluid Framework,\n * and ITelemetryBaseLogger should be used when loggers are passed between layers.\n */\nexport interface ITelemetryLoggerExt extends ITelemetryBaseLogger {\n\t/**\n\t * Send information telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t * @param logLevel - optional level of the log.\n\t */\n\tsendTelemetryEvent(\n\t\tevent: ITelemetryGenericEventExt,\n\t\terror?: unknown,\n\t\tlogLevel?: typeof LogLevel.verbose | typeof LogLevel.default,\n\t): void;\n\n\t/**\n\t * Send error telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t */\n\tsendErrorEvent(event: ITelemetryErrorEventExt, error?: unknown): void;\n\n\t/**\n\t * Send performance telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t * @param logLevel - optional level of the log.\n\t */\n\tsendPerformanceEvent(\n\t\tevent: ITelemetryPerformanceEventExt,\n\t\terror?: unknown,\n\t\tlogLevel?: typeof LogLevel.verbose | typeof LogLevel.default,\n\t): void;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thresholdCounter.d.ts","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;GAGG;AACH,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,iBAAiB;gBAFR,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,mBAAmB,EACpC,iBAAiB,SAAY;IAGtC;;OAEG;IACI,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"thresholdCounter.d.ts","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;GAGG;AACH,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,iBAAiB;gBAFR,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,mBAAmB,EACpC,iBAAiB,SAAY;IAGtC;;OAEG;IACI,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAUnD;;;;;;OAMG;IACI,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAU7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAC5B,YACkB,SAAiB,EACjB,MAA2B,EACpC,oBAAoB,SAAS;QAFpB,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAqB;QACpC,sBAAiB,GAAjB,iBAAiB,CAAY;IACnC,CAAC;IAEJ;;OAEG;IACI,IAAI,CAAC,SAAiB,EAAE,KAAa;QAC3C,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;YAC3B,OAAO;SACP;QACD,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,SAAS;YACT,KAAK;SACL,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,SAAiB,EAAE,KAAa;QACrD,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB,EAAE;YACrC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS;gBACT,KAAK;aACL,CAAC,CAAC;YACH,sCAAsC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;SACpD;IACF,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\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\tpublic constructor(\n\t\tprivate readonly threshold: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate thresholdMultiple = threshold,\n\t) {}\n\n\t/**\n\t * Sends the value if it's above the treshold.\n\t */\n\tpublic send(eventName: string, value: number) {\n\t\tif (value < this.threshold) {\n\t\t\treturn;\n\t\t}\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName,\n\t\t\tvalue,\n\t\t});\n\t}\n\n\t/**\n\t * Sends the value if it's above the threshold\n\t * and a multiple of the threshold.\n\t *\n\t * To be used in scenarios where we'd like to record a\n\t * threshold violation while reducing telemetry noise.\n\t */\n\tpublic sendIfMultiple(eventName: string, value: number) {\n\t\tif (value === this.thresholdMultiple) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName,\n\t\t\t\tvalue,\n\t\t\t});\n\t\t\t// reduce number of \"multiple\" events.\n\t\t\tthis.thresholdMultiple = this.thresholdMultiple * 2;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAC5B,YACkB,SAAiB,EACjB,MAA2B,EACpC,oBAAoB,SAAS;QAFpB,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAqB;QACpC,sBAAiB,GAAjB,iBAAiB,CAAY;IACnC,CAAC;IAEJ;;OAEG;IACI,IAAI,CAAC,SAAiB,EAAE,KAAa;QAC3C,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;YAC3B,OAAO;SACP;QACD,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,SAAS;YACT,KAAK;SACL,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,SAAiB,EAAE,KAAa;QACrD,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB,EAAE;YACrC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS;gBACT,KAAK;aACL,CAAC,CAAC;YACH,sCAAsC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;SACpD;IACF,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\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\tpublic constructor(\n\t\tprivate readonly threshold: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate thresholdMultiple = threshold,\n\t) {}\n\n\t/**\n\t * Sends the value if it's above the treshold.\n\t */\n\tpublic send(eventName: string, value: number): void {\n\t\tif (value < this.threshold) {\n\t\t\treturn;\n\t\t}\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName,\n\t\t\tvalue,\n\t\t});\n\t}\n\n\t/**\n\t * Sends the value if it's above the threshold\n\t * and a multiple of the threshold.\n\t *\n\t * To be used in scenarios where we'd like to record a\n\t * threshold violation while reducing telemetry noise.\n\t */\n\tpublic sendIfMultiple(eventName: string, value: number): void {\n\t\tif (value === this.thresholdMultiple) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName,\n\t\t\t\tvalue,\n\t\t\t});\n\t\t\t// reduce number of \"multiple\" events.\n\t\t\tthis.thresholdMultiple = this.thresholdMultiple * 2;\n\t\t}\n\t}\n}\n"]}
|
package/lib/utils.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { ITelemetryBaseLogger, ITelemetryGenericEvent } from "@fluidframework/co
|
|
|
8
8
|
* @param condition - The condition to attest too
|
|
9
9
|
* @param logger - The logger to log with
|
|
10
10
|
* @param event - The string or event to log
|
|
11
|
-
* @returns
|
|
11
|
+
* @returns The outcome of the condition
|
|
12
12
|
*/
|
|
13
|
-
export declare function logIfFalse(condition:
|
|
13
|
+
export declare function logIfFalse(condition: unknown, logger: ITelemetryBaseLogger, event: string | ITelemetryGenericEvent): condition is true;
|
|
14
14
|
//# sourceMappingURL=utils.d.ts.map
|
package/lib/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAEN,oBAAoB,EACpB,sBAAsB,EACtB,MAAM,iCAAiC,CAAC;AAEzC;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAEN,oBAAoB,EACpB,sBAAsB,EACtB,MAAM,iCAAiC,CAAC;AAEzC;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,oBAAoB,EAC5B,KAAK,EAAE,MAAM,GAAG,sBAAsB,GACpC,SAAS,IAAI,IAAI,CAUnB"}
|
package/lib/utils.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @param condition - The condition to attest too
|
|
4
4
|
* @param logger - The logger to log with
|
|
5
5
|
* @param event - The string or event to log
|
|
6
|
-
* @returns
|
|
6
|
+
* @returns The outcome of the condition
|
|
7
7
|
*/
|
|
8
8
|
export function logIfFalse(condition, logger, event) {
|
|
9
9
|
if (condition) {
|
|
@@ -11,7 +11,7 @@ export function logIfFalse(condition, logger, event) {
|
|
|
11
11
|
}
|
|
12
12
|
const newEvent = typeof event === "string"
|
|
13
13
|
? { eventName: event, category: "error" }
|
|
14
|
-
:
|
|
14
|
+
: { category: "error", ...event };
|
|
15
15
|
logger.send(newEvent);
|
|
16
16
|
return false;
|
|
17
17
|
}
|
package/lib/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAUA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACzB,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAUA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACzB,SAAkB,EAClB,MAA4B,EAC5B,KAAsC;IAEtC,IAAI,SAAS,EAAE;QACd,OAAO,IAAI,CAAC;KACZ;IACD,MAAM,QAAQ,GACb,OAAO,KAAK,KAAK,QAAQ;QACxB,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACzC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;IACpC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACd,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n\tITelemetryGenericEvent,\n} from \"@fluidframework/core-interfaces\";\n\n/**\n * Like assert, but logs only if the condition is false, rather than throwing\n * @param condition - The condition to attest too\n * @param logger - The logger to log with\n * @param event - The string or event to log\n * @returns The outcome of the condition\n */\nexport function logIfFalse(\n\tcondition: unknown,\n\tlogger: ITelemetryBaseLogger,\n\tevent: string | ITelemetryGenericEvent,\n): condition is true {\n\tif (condition) {\n\t\treturn true;\n\t}\n\tconst newEvent: ITelemetryBaseEvent =\n\t\ttypeof event === \"string\"\n\t\t\t? { eventName: event, category: \"error\" }\n\t\t\t: { category: \"error\", ...event };\n\tlogger.send(newEvent);\n\treturn false;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/telemetry-utils",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.6.4.0.191457",
|
|
4
4
|
"description": "Collection of telemetry relates utilities for Fluid",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"./lib/indexNode.js": "./lib/indexBrowser.js"
|
|
19
19
|
},
|
|
20
20
|
"types": "dist/index.d.ts",
|
|
21
|
-
"
|
|
21
|
+
"c8": {
|
|
22
22
|
"all": true,
|
|
23
23
|
"cache-dir": "nyc/.cache",
|
|
24
24
|
"exclude": [
|
|
@@ -39,28 +39,28 @@
|
|
|
39
39
|
"temp-directory": "nyc/.nyc_output"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"@fluidframework/
|
|
44
|
-
"@fluidframework/core-
|
|
45
|
-
"@fluidframework/
|
|
42
|
+
"@fluid-internal/client-utils": "2.0.0-dev.6.4.0.191457",
|
|
43
|
+
"@fluidframework/core-interfaces": "2.0.0-dev.6.4.0.191457",
|
|
44
|
+
"@fluidframework/core-utils": "2.0.0-dev.6.4.0.191457",
|
|
45
|
+
"@fluidframework/protocol-definitions": "^1.1.0",
|
|
46
46
|
"debug": "^4.1.1",
|
|
47
47
|
"events": "^3.1.0",
|
|
48
|
-
"uuid": "^
|
|
48
|
+
"uuid": "^9.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@fluid-tools/build-cli": "^0.
|
|
52
|
-
"@fluidframework/build-common": "^
|
|
53
|
-
"@fluidframework/build-tools": "^0.
|
|
54
|
-
"@fluidframework/eslint-config-fluid": "^2.
|
|
55
|
-
"@fluidframework/mocha-test-setup": "2.0.0-dev.
|
|
56
|
-
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.0.0-internal.
|
|
51
|
+
"@fluid-tools/build-cli": "^0.22.0",
|
|
52
|
+
"@fluidframework/build-common": "^2.0.0",
|
|
53
|
+
"@fluidframework/build-tools": "^0.22.0",
|
|
54
|
+
"@fluidframework/eslint-config-fluid": "^2.1.0",
|
|
55
|
+
"@fluidframework/mocha-test-setup": "2.0.0-dev.6.4.0.191457",
|
|
56
|
+
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.0.0-internal.6.3.0",
|
|
57
57
|
"@microsoft/api-extractor": "^7.34.4",
|
|
58
58
|
"@types/debug": "^4.1.5",
|
|
59
59
|
"@types/events": "^3.0.0",
|
|
60
60
|
"@types/mocha": "^9.1.1",
|
|
61
|
-
"@types/node": "^
|
|
62
|
-
"@types/uuid": "^
|
|
63
|
-
"
|
|
61
|
+
"@types/node": "^16.18.38",
|
|
62
|
+
"@types/uuid": "^9.0.2",
|
|
63
|
+
"c8": "^7.7.1",
|
|
64
64
|
"copyfiles": "^2.4.1",
|
|
65
65
|
"cross-env": "^7.0.3",
|
|
66
66
|
"eslint": "~8.6.0",
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"mocha-json-output-reporter": "^2.0.1",
|
|
69
69
|
"mocha-multi-reporters": "^1.5.1",
|
|
70
70
|
"moment": "^2.21.0",
|
|
71
|
-
"nyc": "^15.1.0",
|
|
72
71
|
"prettier": "~2.6.2",
|
|
73
72
|
"rimraf": "^4.4.0",
|
|
74
73
|
"sinon": "^7.4.2",
|
|
@@ -86,7 +85,7 @@
|
|
|
86
85
|
"build:test": "tsc --project ./src/test/tsconfig.json",
|
|
87
86
|
"bump-version": "npm version minor --no-push --no-git-tag-version && npm run build:genver",
|
|
88
87
|
"ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
|
|
89
|
-
"clean": "rimraf dist lib *.tsbuildinfo *.build.log",
|
|
88
|
+
"clean": "rimraf --glob 'dist' 'lib' '*.tsbuildinfo' '*.build.log' '_api-extractor-temp' 'nyc'",
|
|
90
89
|
"eslint": "eslint --format stylish src",
|
|
91
90
|
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
92
91
|
"format": "npm run prettier:fix",
|
|
@@ -95,11 +94,9 @@
|
|
|
95
94
|
"prettier": "prettier --check . --ignore-path ../../../.prettierignore",
|
|
96
95
|
"prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
|
|
97
96
|
"test": "npm run test:mocha",
|
|
98
|
-
"test:coverage": "
|
|
99
|
-
"test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup
|
|
100
|
-
"test:mocha:multireport": "cross-env FLUID_TEST_MULTIREPORT=1 npm run test:mocha",
|
|
97
|
+
"test:coverage": "c8 npm test",
|
|
98
|
+
"test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup",
|
|
101
99
|
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
102
|
-
"test:report": "npm test -- -- --reporter xunit --reporter-option output=nyc/mocha-junit-report.xml",
|
|
103
100
|
"tsc": "tsc",
|
|
104
101
|
"typetests:gen": "fluid-type-test-generator",
|
|
105
102
|
"typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
|
package/src/config.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
6
6
|
import { Lazy } from "@fluidframework/core-utils";
|
|
7
|
-
import {
|
|
7
|
+
import { createChildLogger, tagCodeArtifacts } from "./logger";
|
|
8
8
|
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
9
9
|
|
|
10
10
|
export type ConfigTypes = string | number | boolean | number[] | string[] | boolean[] | undefined;
|
|
@@ -50,11 +50,12 @@ const NullConfigProvider: IConfigProviderBase = {
|
|
|
50
50
|
export const inMemoryConfigProvider = (storage: Storage | undefined): IConfigProviderBase => {
|
|
51
51
|
if (storage !== undefined && storage !== null) {
|
|
52
52
|
return new CachedConfigProvider(undefined, {
|
|
53
|
-
getRawConfig: (name: string) => {
|
|
53
|
+
getRawConfig: (name: string): ConfigTypes | undefined => {
|
|
54
54
|
try {
|
|
55
55
|
return stronglyTypedParse(storage.getItem(name) ?? undefined)?.raw;
|
|
56
|
-
} catch {
|
|
57
|
-
|
|
56
|
+
} catch {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
58
59
|
},
|
|
59
60
|
});
|
|
60
61
|
}
|
|
@@ -104,7 +105,7 @@ function stronglyTypedParse(input: ConfigTypes): StronglyTypedValue | undefined
|
|
|
104
105
|
// holds strings
|
|
105
106
|
if (typeof input === "string") {
|
|
106
107
|
try {
|
|
107
|
-
output = JSON.parse(input);
|
|
108
|
+
output = JSON.parse(input) as ConfigTypes;
|
|
108
109
|
// we succeeded in parsing, but we don't support parsing
|
|
109
110
|
// for any object as we can't do it type safely
|
|
110
111
|
// so in this case, the default return will be string
|
|
@@ -113,7 +114,9 @@ function stronglyTypedParse(input: ConfigTypes): StronglyTypedValue | undefined
|
|
|
113
114
|
// a false sense of security by just
|
|
114
115
|
// casting.
|
|
115
116
|
defaultReturn = { raw: input, string: input };
|
|
116
|
-
} catch {
|
|
117
|
+
} catch {
|
|
118
|
+
// No-op
|
|
119
|
+
}
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
if (output === undefined) {
|
|
@@ -144,7 +147,9 @@ function stronglyTypedParse(input: ConfigTypes): StronglyTypedValue | undefined
|
|
|
144
147
|
return defaultReturn;
|
|
145
148
|
}
|
|
146
149
|
|
|
147
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* `sessionStorage` is undefined in some environments such as Node and web pages with session storage disabled.
|
|
152
|
+
*/
|
|
148
153
|
const safeSessionStorage = (): Storage | undefined => {
|
|
149
154
|
// For some configurations accessing "globalThis.sessionStorage" throws
|
|
150
155
|
// "'sessionStorage' property from 'Window': Access is denied for this document" rather than returning undefined.
|
|
@@ -222,11 +227,10 @@ export class CachedConfigProvider implements IConfigProvider {
|
|
|
222
227
|
this.logger?.send({
|
|
223
228
|
category: "generic",
|
|
224
229
|
eventName: "ConfigRead",
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
},
|
|
230
|
+
...tagCodeArtifacts({
|
|
231
|
+
configName: name,
|
|
232
|
+
configValue: JSON.stringify(parsed),
|
|
233
|
+
}),
|
|
230
234
|
});
|
|
231
235
|
return parsed;
|
|
232
236
|
}
|
|
@@ -265,7 +269,7 @@ export function loggerToMonitoringContext<L extends ITelemetryBaseLogger = ITele
|
|
|
265
269
|
export function mixinMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(
|
|
266
270
|
logger: L,
|
|
267
271
|
...configs: (IConfigProviderBase | undefined)[]
|
|
268
|
-
) {
|
|
272
|
+
): MonitoringContext<L> {
|
|
269
273
|
if (loggerIsMonitoringContext<L>(logger)) {
|
|
270
274
|
throw new Error("Logger is already a monitoring context");
|
|
271
275
|
}
|
|
@@ -287,3 +291,9 @@ function isConfigProviderBase(obj: unknown): obj is IConfigProviderBase {
|
|
|
287
291
|
const maybeConfig = obj as Partial<IConfigProviderBase> | undefined;
|
|
288
292
|
return typeof maybeConfig?.getRawConfig === "function";
|
|
289
293
|
}
|
|
294
|
+
|
|
295
|
+
export function createChildMonitoringContext(
|
|
296
|
+
props: Parameters<typeof createChildLogger>[0],
|
|
297
|
+
): MonitoringContext {
|
|
298
|
+
return loggerToMonitoringContext(createChildLogger(props));
|
|
299
|
+
}
|
package/src/error.ts
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
FluidErrorTypes,
|
|
8
|
+
IGenericError,
|
|
9
|
+
IErrorBase,
|
|
10
|
+
ITelemetryBaseProperties,
|
|
11
|
+
IUsageError,
|
|
12
|
+
} from "@fluidframework/core-interfaces";
|
|
13
|
+
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
LoggingError,
|
|
17
|
+
NORMALIZED_ERROR_TYPE,
|
|
18
|
+
isExternalError,
|
|
19
|
+
normalizeError,
|
|
20
|
+
wrapError,
|
|
21
|
+
} from "./errorLogging";
|
|
22
|
+
import { IFluidErrorBase } from "./fluidErrorBase";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generic wrapper for an unrecognized/uncategorized error object
|
|
26
|
+
*/
|
|
27
|
+
export class GenericError extends LoggingError implements IGenericError, IFluidErrorBase {
|
|
28
|
+
readonly errorType = FluidErrorTypes.genericError;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create a new GenericError
|
|
32
|
+
* @param message - Error message
|
|
33
|
+
* @param error - inner error object
|
|
34
|
+
* @param props - Telemetry props to include when the error is logged
|
|
35
|
+
*/
|
|
36
|
+
// TODO: Use `unknown` instead (API breaking change because error is not just an input parameter, but a public member of the class)
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
38
|
+
constructor(message: string, public readonly error?: any, props?: ITelemetryBaseProperties) {
|
|
39
|
+
// Don't try to log the inner error
|
|
40
|
+
super(message, props, new Set(["error"]));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Error indicating an API is being used improperly resulting in an invalid operation.
|
|
46
|
+
*/
|
|
47
|
+
export class UsageError extends LoggingError implements IUsageError, IFluidErrorBase {
|
|
48
|
+
readonly errorType = FluidErrorTypes.usageError;
|
|
49
|
+
|
|
50
|
+
constructor(message: string, props?: ITelemetryBaseProperties) {
|
|
51
|
+
super(message, { ...props, usageError: true });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* DataCorruptionError indicates that we encountered definitive evidence that the data at rest
|
|
57
|
+
* backing this container is corrupted, and this container would never be expected to load properly again
|
|
58
|
+
*/
|
|
59
|
+
export class DataCorruptionError extends LoggingError implements IErrorBase, IFluidErrorBase {
|
|
60
|
+
readonly errorType = FluidErrorTypes.dataCorruptionError;
|
|
61
|
+
readonly canRetry = false;
|
|
62
|
+
|
|
63
|
+
constructor(message: string, props: ITelemetryBaseProperties) {
|
|
64
|
+
super(message, { ...props, dataProcessingError: 1 });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Indicates we hit a fatal error while processing incoming data from the Fluid Service.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
*
|
|
73
|
+
* The error will often originate in the dataStore or DDS implementation that is responding to incoming changes.
|
|
74
|
+
* This differs from {@link DataCorruptionError} in that this may be a transient error that will not repro in another
|
|
75
|
+
* client or session.
|
|
76
|
+
*/
|
|
77
|
+
export class DataProcessingError extends LoggingError implements IErrorBase, IFluidErrorBase {
|
|
78
|
+
/**
|
|
79
|
+
* {@inheritDoc IFluidErrorBase.errorType}
|
|
80
|
+
*/
|
|
81
|
+
public readonly errorType = FluidErrorTypes.dataProcessingError;
|
|
82
|
+
|
|
83
|
+
public readonly canRetry = false;
|
|
84
|
+
|
|
85
|
+
private constructor(errorMessage: string, props?: ITelemetryBaseProperties) {
|
|
86
|
+
super(errorMessage, props);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Create a new `DataProcessingError` detected and raised within the Fluid Framework.
|
|
91
|
+
*/
|
|
92
|
+
public static create(
|
|
93
|
+
errorMessage: string,
|
|
94
|
+
dataProcessingCodepath: string,
|
|
95
|
+
sequencedMessage?: ISequencedDocumentMessage,
|
|
96
|
+
props: ITelemetryBaseProperties = {},
|
|
97
|
+
): IFluidErrorBase {
|
|
98
|
+
const dataProcessingError = DataProcessingError.wrapIfUnrecognized(
|
|
99
|
+
errorMessage,
|
|
100
|
+
dataProcessingCodepath,
|
|
101
|
+
sequencedMessage,
|
|
102
|
+
);
|
|
103
|
+
dataProcessingError.addTelemetryProperties(props);
|
|
104
|
+
|
|
105
|
+
return dataProcessingError;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Wrap the given error in a `DataProcessingError`, unless the error is already of a known type
|
|
110
|
+
* with the exception of a normalized {@link LoggingError}, which will still be wrapped.
|
|
111
|
+
*
|
|
112
|
+
* In either case, the error will have some relevant properties added for telemetry.
|
|
113
|
+
*
|
|
114
|
+
* @remarks
|
|
115
|
+
*
|
|
116
|
+
* We wrap conditionally since known error types represent well-understood failure modes, and ideally
|
|
117
|
+
* one day we will move away from throwing these errors but rather we'll return them.
|
|
118
|
+
* But an unrecognized error needs to be classified as `DataProcessingError`.
|
|
119
|
+
*
|
|
120
|
+
* @param originalError - The error to be converted.
|
|
121
|
+
* @param dataProcessingCodepath - Which code-path failed while processing data.
|
|
122
|
+
* @param messageLike - Message to include info about via telemetry props.
|
|
123
|
+
*
|
|
124
|
+
* @returns Either a new `DataProcessingError`, or (if wrapping is deemed unnecessary) the given error.
|
|
125
|
+
*/
|
|
126
|
+
public static wrapIfUnrecognized(
|
|
127
|
+
originalError: unknown,
|
|
128
|
+
dataProcessingCodepath: string,
|
|
129
|
+
messageLike?: Partial<
|
|
130
|
+
Pick<
|
|
131
|
+
ISequencedDocumentMessage,
|
|
132
|
+
| "clientId"
|
|
133
|
+
| "sequenceNumber"
|
|
134
|
+
| "clientSequenceNumber"
|
|
135
|
+
| "referenceSequenceNumber"
|
|
136
|
+
| "minimumSequenceNumber"
|
|
137
|
+
| "timestamp"
|
|
138
|
+
>
|
|
139
|
+
>,
|
|
140
|
+
): IFluidErrorBase {
|
|
141
|
+
const props = {
|
|
142
|
+
dataProcessingError: 1,
|
|
143
|
+
dataProcessingCodepath,
|
|
144
|
+
...(messageLike === undefined
|
|
145
|
+
? undefined
|
|
146
|
+
: extractSafePropertiesFromMessage(messageLike)),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const normalizedError = normalizeError(originalError, { props });
|
|
150
|
+
// Note that other errors may have the NORMALIZED_ERROR_TYPE errorType,
|
|
151
|
+
// but if so they are still suitable to be wrapped as DataProcessingError.
|
|
152
|
+
if (
|
|
153
|
+
isExternalError(normalizedError) ||
|
|
154
|
+
normalizedError.errorType === NORMALIZED_ERROR_TYPE
|
|
155
|
+
) {
|
|
156
|
+
// Create a new DataProcessingError to wrap this external error
|
|
157
|
+
const dataProcessingError = wrapError(
|
|
158
|
+
normalizedError,
|
|
159
|
+
(message: string) => new DataProcessingError(message),
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Copy over the props above and any others added to this error since first being normalized
|
|
163
|
+
dataProcessingError.addTelemetryProperties(normalizedError.getTelemetryProperties());
|
|
164
|
+
|
|
165
|
+
return dataProcessingError;
|
|
166
|
+
}
|
|
167
|
+
return normalizedError;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Extracts specific properties from the provided message that we know are safe to log.
|
|
173
|
+
*
|
|
174
|
+
* @param messageLike - Message to include info about via telemetry props.
|
|
175
|
+
*/
|
|
176
|
+
export const extractSafePropertiesFromMessage = (
|
|
177
|
+
messageLike: Partial<
|
|
178
|
+
Pick<
|
|
179
|
+
ISequencedDocumentMessage,
|
|
180
|
+
| "clientId"
|
|
181
|
+
| "sequenceNumber"
|
|
182
|
+
| "clientSequenceNumber"
|
|
183
|
+
| "referenceSequenceNumber"
|
|
184
|
+
| "minimumSequenceNumber"
|
|
185
|
+
| "timestamp"
|
|
186
|
+
>
|
|
187
|
+
>,
|
|
188
|
+
): {
|
|
189
|
+
messageClientId: string | undefined;
|
|
190
|
+
messageSequenceNumber: number | undefined;
|
|
191
|
+
messageClientSequenceNumber: number | undefined;
|
|
192
|
+
messageReferenceSequenceNumber: number | undefined;
|
|
193
|
+
messageMinimumSequenceNumber: number | undefined;
|
|
194
|
+
messageTimestamp: number | undefined;
|
|
195
|
+
} => ({
|
|
196
|
+
messageClientId: messageLike.clientId === null ? "null" : messageLike.clientId,
|
|
197
|
+
messageSequenceNumber: messageLike.sequenceNumber,
|
|
198
|
+
messageClientSequenceNumber: messageLike.clientSequenceNumber,
|
|
199
|
+
messageReferenceSequenceNumber: messageLike.referenceSequenceNumber,
|
|
200
|
+
messageMinimumSequenceNumber: messageLike.minimumSequenceNumber,
|
|
201
|
+
messageTimestamp: messageLike.timestamp,
|
|
202
|
+
});
|