@fluidframework/telemetry-utils 2.0.0-dev.5.2.0.169897 → 2.0.0-dev.6.4.0.191258
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 +126 -0
- package/README.md +4 -3
- package/dist/config.d.ts +4 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +36 -38
- 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 +49 -16
- 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 +9 -8
- 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 +3 -3
- 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 +4 -2
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +34 -37
- 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 +49 -16
- 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 +9 -8
- 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 +3 -3
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +2 -2
- package/lib/utils.js.map +1 -1
- package/package.json +21 -44
- package/src/config.ts +25 -15
- package/src/error.ts +202 -0
- package/src/errorLogging.ts +102 -57
- package/src/eventEmitterWithErrorHandling.ts +5 -3
- package/src/events.ts +3 -3
- package/src/fluidErrorBase.ts +63 -27
- package/src/index.ts +17 -6
- package/src/logger.ts +291 -121
- package/src/mockLogger.ts +65 -24
- package/src/sampledTelemetryHelper.ts +20 -16
- package/src/telemetryTypes.ts +29 -6
- package/src/thresholdCounter.ts +2 -2
- package/src/utils.ts +3 -3
- 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
package/src/errorLogging.ts
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
ILoggingError,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "@fluidframework/
|
|
8
|
+
ITelemetryBaseProperties,
|
|
9
|
+
TelemetryBaseEventPropertyType,
|
|
10
|
+
Tagged,
|
|
11
|
+
} from "@fluidframework/core-interfaces";
|
|
12
12
|
import { v4 as uuid } from "uuid";
|
|
13
13
|
import {
|
|
14
14
|
hasErrorInstanceId,
|
|
@@ -16,20 +16,27 @@ import {
|
|
|
16
16
|
isFluidError,
|
|
17
17
|
isValidLegacyError,
|
|
18
18
|
} from "./fluidErrorBase";
|
|
19
|
-
import {
|
|
20
|
-
ITaggedTelemetryPropertyTypeExt,
|
|
21
|
-
ITelemetryLoggerExt,
|
|
22
|
-
TelemetryEventPropertyTypeExt,
|
|
23
|
-
} from "./telemetryTypes";
|
|
19
|
+
import { ITelemetryLoggerExt, TelemetryEventPropertyTypeExt } from "./telemetryTypes";
|
|
24
20
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Determines if the provided value is an object but neither null nor an array.
|
|
23
|
+
*/
|
|
24
|
+
const isRegularObject = (value: unknown): boolean => {
|
|
27
25
|
return value !== null && !Array.isArray(value) && typeof value === "object";
|
|
28
26
|
};
|
|
29
27
|
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Inspect the given error for common "safe" props and return them.
|
|
30
|
+
*/
|
|
31
|
+
export function extractLogSafeErrorProperties(
|
|
32
|
+
error: unknown,
|
|
33
|
+
sanitizeStack: boolean,
|
|
34
|
+
): {
|
|
35
|
+
message: string;
|
|
36
|
+
errorType?: string | undefined;
|
|
37
|
+
stack?: string | undefined;
|
|
38
|
+
} {
|
|
39
|
+
const removeMessageFromStack = (stack: string, errorName?: string): string => {
|
|
33
40
|
if (!sanitizeStack) {
|
|
34
41
|
return stack;
|
|
35
42
|
}
|
|
@@ -41,14 +48,17 @@ export function extractLogSafeErrorProperties(error: any, sanitizeStack: boolean
|
|
|
41
48
|
return stackFrames.join("\n");
|
|
42
49
|
};
|
|
43
50
|
|
|
44
|
-
const message =
|
|
51
|
+
const message =
|
|
52
|
+
typeof (error as Partial<Error>)?.message === "string"
|
|
53
|
+
? (error as Error).message
|
|
54
|
+
: String(error);
|
|
45
55
|
|
|
46
56
|
const safeProps: { message: string; errorType?: string; stack?: string } = {
|
|
47
57
|
message,
|
|
48
58
|
};
|
|
49
59
|
|
|
50
60
|
if (isRegularObject(error)) {
|
|
51
|
-
const { errorType, stack, name } = error
|
|
61
|
+
const { errorType, stack, name } = error as Partial<IFluidErrorBase>;
|
|
52
62
|
|
|
53
63
|
if (typeof errorType === "string") {
|
|
54
64
|
safeProps.errorType = errorType;
|
|
@@ -63,12 +73,19 @@ export function extractLogSafeErrorProperties(error: any, sanitizeStack: boolean
|
|
|
63
73
|
return safeProps;
|
|
64
74
|
}
|
|
65
75
|
|
|
66
|
-
/**
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
/**
|
|
77
|
+
* type guard for ILoggingError interface
|
|
78
|
+
*/
|
|
79
|
+
export const isILoggingError = (x: unknown): x is ILoggingError =>
|
|
80
|
+
typeof (x as Partial<ILoggingError>)?.getTelemetryProperties === "function";
|
|
69
81
|
|
|
70
|
-
/**
|
|
71
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Copy props from source onto target, but do not overwrite an existing prop that matches
|
|
84
|
+
*/
|
|
85
|
+
function copyProps(
|
|
86
|
+
target: ITelemetryBaseProperties | LoggingError,
|
|
87
|
+
source: ITelemetryBaseProperties,
|
|
88
|
+
): void {
|
|
72
89
|
for (const key of Object.keys(source)) {
|
|
73
90
|
if (target[key] === undefined) {
|
|
74
91
|
target[key] = source[key];
|
|
@@ -76,16 +93,23 @@ function copyProps(target: ITelemetryProperties | LoggingError, source: ITelemet
|
|
|
76
93
|
}
|
|
77
94
|
}
|
|
78
95
|
|
|
79
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Metadata to annotate an error object when annotating or normalizing it
|
|
98
|
+
*/
|
|
80
99
|
export interface IFluidErrorAnnotations {
|
|
81
|
-
/**
|
|
82
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Telemetry props to log with the error
|
|
102
|
+
*/
|
|
103
|
+
props?: ITelemetryBaseProperties;
|
|
83
104
|
}
|
|
84
105
|
|
|
85
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* For backwards compatibility with pre-errorInstanceId valid errors
|
|
108
|
+
*/
|
|
86
109
|
function patchLegacyError(
|
|
87
110
|
legacyError: Omit<IFluidErrorBase, "errorInstanceId">,
|
|
88
111
|
): asserts legacyError is IFluidErrorBase {
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
|
89
113
|
const patchMe: { -readonly [P in "errorInstanceId"]?: IFluidErrorBase[P] } = legacyError as any;
|
|
90
114
|
if (patchMe.errorInstanceId === undefined) {
|
|
91
115
|
patchMe.errorInstanceId = uuid();
|
|
@@ -180,8 +204,8 @@ export function generateErrorWithStack(): Error {
|
|
|
180
204
|
|
|
181
205
|
try {
|
|
182
206
|
throw err;
|
|
183
|
-
} catch (
|
|
184
|
-
return
|
|
207
|
+
} catch (error) {
|
|
208
|
+
return error as Error;
|
|
185
209
|
}
|
|
186
210
|
}
|
|
187
211
|
|
|
@@ -230,12 +254,16 @@ export function wrapError<T extends LoggingError>(
|
|
|
230
254
|
return newError;
|
|
231
255
|
}
|
|
232
256
|
|
|
233
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
* The same as wrapError, but also logs the innerError, including the wrapping error's instance ID.
|
|
259
|
+
*
|
|
260
|
+
* @typeParam T - The kind of wrapper error to create.
|
|
261
|
+
*/
|
|
234
262
|
export function wrapErrorAndLog<T extends LoggingError>(
|
|
235
263
|
innerError: unknown,
|
|
236
264
|
newErrorFn: (message: string) => T,
|
|
237
265
|
logger: ITelemetryLoggerExt,
|
|
238
|
-
) {
|
|
266
|
+
): T {
|
|
239
267
|
const newError = wrapError(innerError, newErrorFn);
|
|
240
268
|
|
|
241
269
|
// This will match innerError.errorInstanceId if present (see wrapError)
|
|
@@ -256,11 +284,18 @@ export function wrapErrorAndLog<T extends LoggingError>(
|
|
|
256
284
|
return newError;
|
|
257
285
|
}
|
|
258
286
|
|
|
259
|
-
|
|
260
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Attempts to overwrite the error's stack
|
|
289
|
+
*
|
|
290
|
+
* There have been reports of certain JS environments where overwriting stack will throw.
|
|
291
|
+
* If that happens, this adds the given stack as the telemetry property "stack2"
|
|
292
|
+
*
|
|
293
|
+
* @internal
|
|
294
|
+
*/
|
|
295
|
+
export function overwriteStack(error: IFluidErrorBase | LoggingError, stack: string): void {
|
|
261
296
|
try {
|
|
262
297
|
Object.assign(error, { stack });
|
|
263
|
-
} catch
|
|
298
|
+
} catch {
|
|
264
299
|
error.addTelemetryProperties({ stack2: stack });
|
|
265
300
|
}
|
|
266
301
|
}
|
|
@@ -270,35 +305,35 @@ function overwriteStack(error: IFluidErrorBase | LoggingError, stack: string) {
|
|
|
270
305
|
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
271
306
|
* or wrapped in a well-known error type
|
|
272
307
|
*/
|
|
273
|
-
export function isExternalError(
|
|
308
|
+
export function isExternalError(error: unknown): boolean {
|
|
274
309
|
// LoggingErrors are an internal FF error type. However, an external error can be converted
|
|
275
310
|
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
|
|
276
311
|
// determine whether the original error was infact external.
|
|
277
|
-
if (LoggingError.typeCheck(
|
|
278
|
-
if ((
|
|
279
|
-
return
|
|
312
|
+
if (LoggingError.typeCheck(error)) {
|
|
313
|
+
if ((error as NormalizedLoggingError).errorType === NORMALIZED_ERROR_TYPE) {
|
|
314
|
+
return error.getTelemetryProperties().untrustedOrigin === 1;
|
|
280
315
|
}
|
|
281
316
|
return false;
|
|
282
317
|
}
|
|
283
|
-
return !isValidLegacyError(
|
|
318
|
+
return !isValidLegacyError(error);
|
|
284
319
|
}
|
|
285
320
|
|
|
286
321
|
/**
|
|
287
322
|
* Type guard to identify if a particular telemetry property appears to be a tagged telemetry property
|
|
288
323
|
*/
|
|
289
324
|
export function isTaggedTelemetryPropertyValue(
|
|
290
|
-
x:
|
|
291
|
-
): x is
|
|
292
|
-
return typeof (x as
|
|
325
|
+
x: Tagged<TelemetryEventPropertyTypeExt> | TelemetryEventPropertyTypeExt,
|
|
326
|
+
): x is Tagged<TelemetryEventPropertyTypeExt> {
|
|
327
|
+
return typeof (x as Partial<Tagged<unknown>>)?.tag === "string";
|
|
293
328
|
}
|
|
294
329
|
|
|
295
330
|
/**
|
|
296
331
|
* Filter serializable telemetry properties
|
|
297
|
-
* @param x -
|
|
298
|
-
* @returns -
|
|
332
|
+
* @param x - Any telemetry prop
|
|
333
|
+
* @returns As-is if x is primitive. returns stringified if x is an array of primitive.
|
|
299
334
|
* otherwise returns null since this is what we support at the moment.
|
|
300
335
|
*/
|
|
301
|
-
function filterValidTelemetryProps(x:
|
|
336
|
+
function filterValidTelemetryProps(x: unknown, key: string): TelemetryBaseEventPropertyType {
|
|
302
337
|
if (Array.isArray(x) && x.every((val) => isTelemetryEventPropertyValue(val))) {
|
|
303
338
|
return JSON.stringify(x);
|
|
304
339
|
}
|
|
@@ -311,7 +346,7 @@ function filterValidTelemetryProps(x: any, key: string): TelemetryEventPropertyT
|
|
|
311
346
|
}
|
|
312
347
|
|
|
313
348
|
// checking type of x, returns false if x is null
|
|
314
|
-
function isTelemetryEventPropertyValue(x:
|
|
349
|
+
function isTelemetryEventPropertyValue(x: unknown): x is TelemetryBaseEventPropertyType {
|
|
315
350
|
switch (typeof x) {
|
|
316
351
|
case "string":
|
|
317
352
|
case "number":
|
|
@@ -325,13 +360,15 @@ function isTelemetryEventPropertyValue(x: any): x is TelemetryEventPropertyType
|
|
|
325
360
|
/**
|
|
326
361
|
* Walk an object's enumerable properties to find those fit for telemetry.
|
|
327
362
|
*/
|
|
328
|
-
function getValidTelemetryProps(obj:
|
|
329
|
-
const props:
|
|
363
|
+
function getValidTelemetryProps(obj: object, keysToOmit: Set<string>): ITelemetryBaseProperties {
|
|
364
|
+
const props: ITelemetryBaseProperties = {};
|
|
330
365
|
for (const key of Object.keys(obj)) {
|
|
331
366
|
if (keysToOmit.has(key)) {
|
|
332
367
|
continue;
|
|
333
368
|
}
|
|
334
|
-
const val = obj[key]
|
|
369
|
+
const val = obj[key] as
|
|
370
|
+
| TelemetryEventPropertyTypeExt
|
|
371
|
+
| Tagged<TelemetryEventPropertyTypeExt>;
|
|
335
372
|
|
|
336
373
|
// ensure only valid props get logged, since props of logging error could be in any shape
|
|
337
374
|
if (isTaggedTelemetryPropertyValue(val)) {
|
|
@@ -353,9 +390,11 @@ function getValidTelemetryProps(obj: any, keysToOmit: Set<string>): ITelemetryPr
|
|
|
353
390
|
* Not ideal, as will cut values that are not necessarily circular references.
|
|
354
391
|
* Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)
|
|
355
392
|
*/
|
|
356
|
-
|
|
393
|
+
// TODO: Use `unknown` instead (API breaking change)
|
|
394
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
395
|
+
export const getCircularReplacer = (): ((key: string, value: unknown) => any) => {
|
|
357
396
|
const seen = new WeakSet();
|
|
358
|
-
return (key: string, value:
|
|
397
|
+
return (key: string, value: unknown): any => {
|
|
359
398
|
if (typeof value === "object" && value !== null) {
|
|
360
399
|
if (seen.has(value)) {
|
|
361
400
|
return "<removed/circular>";
|
|
@@ -365,6 +404,7 @@ export const getCircularReplacer = () => {
|
|
|
365
404
|
return value;
|
|
366
405
|
};
|
|
367
406
|
};
|
|
407
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
368
408
|
|
|
369
409
|
/**
|
|
370
410
|
* Base class for "trusted" errors we create, whose properties can generally be logged to telemetry safely.
|
|
@@ -378,15 +418,18 @@ export class LoggingError
|
|
|
378
418
|
implements ILoggingError, Omit<IFluidErrorBase, "errorType">
|
|
379
419
|
{
|
|
380
420
|
private _errorInstanceId = uuid();
|
|
381
|
-
get errorInstanceId() {
|
|
421
|
+
get errorInstanceId(): string {
|
|
382
422
|
return this._errorInstanceId;
|
|
383
423
|
}
|
|
384
|
-
overwriteErrorInstanceId(id: string) {
|
|
424
|
+
overwriteErrorInstanceId(id: string): void {
|
|
385
425
|
this._errorInstanceId = id;
|
|
386
426
|
}
|
|
387
427
|
|
|
388
|
-
/**
|
|
428
|
+
/**
|
|
429
|
+
* Backwards compatibility to appease {@link isFluidError} in old code that may handle this error.
|
|
430
|
+
*/
|
|
389
431
|
// @ts-expect-error - This field shouldn't be referenced in the current version, but needs to exist at runtime.
|
|
432
|
+
// eslint-disable-next-line @typescript-eslint/prefer-as-const
|
|
390
433
|
private readonly fluidErrorCode: "-" = "-";
|
|
391
434
|
|
|
392
435
|
/**
|
|
@@ -397,7 +440,7 @@ export class LoggingError
|
|
|
397
440
|
*/
|
|
398
441
|
constructor(
|
|
399
442
|
message: string,
|
|
400
|
-
props?:
|
|
443
|
+
props?: ITelemetryBaseProperties,
|
|
401
444
|
private readonly omitPropsFromLogging: Set<string> = new Set(),
|
|
402
445
|
) {
|
|
403
446
|
super(message);
|
|
@@ -414,7 +457,7 @@ export class LoggingError
|
|
|
414
457
|
/**
|
|
415
458
|
* Determines if a given object is an instance of a LoggingError
|
|
416
459
|
* @param object - any object
|
|
417
|
-
* @returns
|
|
460
|
+
* @returns true if the object is an instance of a LoggingError, false if not.
|
|
418
461
|
*/
|
|
419
462
|
public static typeCheck(object: unknown): object is LoggingError {
|
|
420
463
|
if (typeof object === "object" && object !== null) {
|
|
@@ -430,14 +473,14 @@ export class LoggingError
|
|
|
430
473
|
/**
|
|
431
474
|
* Add additional properties to be logged
|
|
432
475
|
*/
|
|
433
|
-
public addTelemetryProperties(props:
|
|
476
|
+
public addTelemetryProperties(props: ITelemetryBaseProperties): void {
|
|
434
477
|
copyProps(this, props);
|
|
435
478
|
}
|
|
436
479
|
|
|
437
480
|
/**
|
|
438
481
|
* Get all properties fit to be logged to telemetry for this error
|
|
439
482
|
*/
|
|
440
|
-
public getTelemetryProperties():
|
|
483
|
+
public getTelemetryProperties(): ITelemetryBaseProperties {
|
|
441
484
|
const taggableProps = getValidTelemetryProps(this, this.omitPropsFromLogging);
|
|
442
485
|
// Include non-enumerable props that are not returned by getValidTelemetryProps
|
|
443
486
|
return {
|
|
@@ -449,7 +492,9 @@ export class LoggingError
|
|
|
449
492
|
}
|
|
450
493
|
}
|
|
451
494
|
|
|
452
|
-
/**
|
|
495
|
+
/**
|
|
496
|
+
* The Error class used when normalizing an external error
|
|
497
|
+
*/
|
|
453
498
|
export const NORMALIZED_ERROR_TYPE = "genericError";
|
|
454
499
|
class NormalizedLoggingError extends LoggingError {
|
|
455
500
|
// errorType "genericError" is used as a default value throughout the code.
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { TypedEventEmitter, EventEmitterEventType } from "@fluid-internal/client-utils";
|
|
6
|
+
import { IEvent } from "@fluidframework/core-interfaces";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Event Emitter helper class
|
|
@@ -14,12 +14,14 @@ export class EventEmitterWithErrorHandling<
|
|
|
14
14
|
TEvent extends IEvent = IEvent,
|
|
15
15
|
> extends TypedEventEmitter<TEvent> {
|
|
16
16
|
constructor(
|
|
17
|
+
// TODO: use `unknown` instead (breaking API change)
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
19
|
private readonly errorHandler: (eventName: EventEmitterEventType, error: any) => void,
|
|
18
20
|
) {
|
|
19
21
|
super();
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
public emit(event: EventEmitterEventType, ...args:
|
|
24
|
+
public emit(event: EventEmitterEventType, ...args: unknown[]): boolean {
|
|
23
25
|
try {
|
|
24
26
|
return super.emit(event, ...args);
|
|
25
27
|
} catch (error) {
|
package/src/events.ts
CHANGED
|
@@ -13,8 +13,8 @@ export function safeRaiseEvent(
|
|
|
13
13
|
emitter: EventEmitter,
|
|
14
14
|
logger: ITelemetryLoggerExt,
|
|
15
15
|
event: string,
|
|
16
|
-
...args
|
|
17
|
-
) {
|
|
16
|
+
...args: unknown[]
|
|
17
|
+
): void {
|
|
18
18
|
try {
|
|
19
19
|
emitter.emit(event, ...args);
|
|
20
20
|
} catch (error) {
|
|
@@ -36,7 +36,7 @@ export function raiseConnectedEvent(
|
|
|
36
36
|
connected: boolean,
|
|
37
37
|
clientId?: string,
|
|
38
38
|
disconnectedReason?: string,
|
|
39
|
-
) {
|
|
39
|
+
): void {
|
|
40
40
|
try {
|
|
41
41
|
if (connected) {
|
|
42
42
|
emitter.emit(connectedEventName, clientId);
|
package/src/fluidErrorBase.ts
CHANGED
|
@@ -3,65 +3,101 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { ITelemetryProperties } from "@fluidframework/
|
|
6
|
+
import { ITelemetryProperties } from "@fluidframework/core-interfaces";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
+
* An error emitted by the Fluid Framework.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
*
|
|
9
13
|
* All normalized errors flowing through the Fluid Framework adhere to this readonly interface.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
14
|
+
*
|
|
15
|
+
* It features the members of {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error | Error}
|
|
16
|
+
* made readonly, as well as {@link IFluidErrorBase.errorType} and {@link IFluidErrorBase.errorInstanceId}.
|
|
17
|
+
* It also features getters and setters for telemetry props to be included when the error is logged.
|
|
12
18
|
*/
|
|
13
19
|
export interface IFluidErrorBase extends Error {
|
|
14
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Classification of what type of error this is.
|
|
22
|
+
*
|
|
23
|
+
* @remarks Used programmatically by consumers to interpret the error.
|
|
24
|
+
*/
|
|
15
25
|
readonly errorType: string;
|
|
16
26
|
|
|
17
27
|
/**
|
|
18
28
|
* Error's message property, made readonly.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
*
|
|
32
|
+
* Recommendations:
|
|
33
|
+
*
|
|
34
|
+
* Be specific, but also take care when including variable data to consider suitability for aggregation in telemetry.
|
|
35
|
+
* Also avoid including any data that jeopardizes the user's privacy. Add a tagged telemetry property instead.
|
|
21
36
|
*/
|
|
22
37
|
readonly message: string;
|
|
23
38
|
|
|
24
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack}.
|
|
41
|
+
*/
|
|
25
42
|
readonly stack?: string;
|
|
26
43
|
|
|
27
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/name}.
|
|
46
|
+
*/
|
|
28
47
|
readonly name: string;
|
|
29
48
|
|
|
30
49
|
/**
|
|
31
50
|
* A Guid identifying this error instance.
|
|
32
|
-
*
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
*
|
|
54
|
+
* Useful in telemetry for deduplicating multiple logging events arising from the same error,
|
|
33
55
|
* or correlating an error with an inner error that caused it, in case of error wrapping.
|
|
34
56
|
*/
|
|
35
57
|
readonly errorInstanceId: string;
|
|
36
58
|
|
|
37
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Get the telemetry properties stashed on this error for logging.
|
|
61
|
+
*/
|
|
38
62
|
getTelemetryProperties(): ITelemetryProperties;
|
|
39
|
-
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Add telemetry properties to this error which will be logged with the error
|
|
66
|
+
*/
|
|
40
67
|
addTelemetryProperties: (props: ITelemetryProperties) => void;
|
|
41
68
|
}
|
|
42
69
|
|
|
43
|
-
const hasTelemetryPropFunctions = (x:
|
|
44
|
-
typeof x?.getTelemetryProperties === "function" &&
|
|
45
|
-
typeof x?.addTelemetryProperties === "function";
|
|
70
|
+
const hasTelemetryPropFunctions = (x: unknown): boolean =>
|
|
71
|
+
typeof (x as Partial<IFluidErrorBase>)?.getTelemetryProperties === "function" &&
|
|
72
|
+
typeof (x as Partial<IFluidErrorBase>)?.addTelemetryProperties === "function";
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Type guard for error data containing the {@link IFluidErrorBase.errorInstanceId} property.
|
|
76
|
+
*/
|
|
77
|
+
export const hasErrorInstanceId = (x: unknown): x is { errorInstanceId: string } =>
|
|
78
|
+
typeof (x as Partial<{ errorInstanceId: string }>)?.errorInstanceId === "string";
|
|
49
79
|
|
|
50
|
-
/**
|
|
51
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Type guard for {@link IFluidErrorBase}.
|
|
82
|
+
*/
|
|
83
|
+
export function isFluidError(error: unknown): error is IFluidErrorBase {
|
|
52
84
|
return (
|
|
53
|
-
typeof
|
|
54
|
-
typeof
|
|
55
|
-
hasErrorInstanceId(
|
|
56
|
-
hasTelemetryPropFunctions(
|
|
85
|
+
typeof (error as Partial<IFluidErrorBase>)?.errorType === "string" &&
|
|
86
|
+
typeof (error as Partial<IFluidErrorBase>)?.message === "string" &&
|
|
87
|
+
hasErrorInstanceId(error) &&
|
|
88
|
+
hasTelemetryPropFunctions(error)
|
|
57
89
|
);
|
|
58
90
|
}
|
|
59
91
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Type guard for old standard of valid/known errors.
|
|
94
|
+
*/
|
|
95
|
+
export function isValidLegacyError(
|
|
96
|
+
error: unknown,
|
|
97
|
+
): error is Omit<IFluidErrorBase, "errorInstanceId"> {
|
|
62
98
|
return (
|
|
63
|
-
typeof
|
|
64
|
-
typeof
|
|
65
|
-
hasTelemetryPropFunctions(
|
|
99
|
+
typeof (error as Partial<IFluidErrorBase>)?.errorType === "string" &&
|
|
100
|
+
typeof (error as Partial<IFluidErrorBase>)?.message === "string" &&
|
|
101
|
+
hasTelemetryPropFunctions(error)
|
|
66
102
|
);
|
|
67
103
|
}
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
export {
|
|
6
|
+
createChildMonitoringContext,
|
|
6
7
|
MonitoringContext,
|
|
7
8
|
IConfigProviderBase,
|
|
8
9
|
sessionStorageConfigProvider,
|
|
@@ -11,7 +12,13 @@ export {
|
|
|
11
12
|
ConfigTypes,
|
|
12
13
|
loggerToMonitoringContext,
|
|
13
14
|
} from "./config";
|
|
14
|
-
export {
|
|
15
|
+
export {
|
|
16
|
+
DataCorruptionError,
|
|
17
|
+
DataProcessingError,
|
|
18
|
+
extractSafePropertiesFromMessage,
|
|
19
|
+
GenericError,
|
|
20
|
+
UsageError,
|
|
21
|
+
} from "./error";
|
|
15
22
|
export {
|
|
16
23
|
extractLogSafeErrorProperties,
|
|
17
24
|
generateErrorWithStack,
|
|
@@ -24,6 +31,7 @@ export {
|
|
|
24
31
|
LoggingError,
|
|
25
32
|
NORMALIZED_ERROR_TYPE,
|
|
26
33
|
normalizeError,
|
|
34
|
+
overwriteStack,
|
|
27
35
|
wrapError,
|
|
28
36
|
wrapErrorAndLog,
|
|
29
37
|
} from "./errorLogging";
|
|
@@ -41,19 +49,21 @@ export {
|
|
|
41
49
|
isValidLegacyError,
|
|
42
50
|
} from "./fluidErrorBase";
|
|
43
51
|
export {
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
eventNamespaceSeparator,
|
|
53
|
+
createChildLogger,
|
|
54
|
+
createMultiSinkLogger,
|
|
55
|
+
formatTick,
|
|
46
56
|
IPerformanceEventMarkers,
|
|
47
57
|
ITelemetryLoggerPropertyBag,
|
|
48
58
|
ITelemetryLoggerPropertyBags,
|
|
49
|
-
|
|
59
|
+
numberFromString,
|
|
50
60
|
PerformanceEvent,
|
|
51
61
|
TaggedLoggerAdapter,
|
|
62
|
+
tagData,
|
|
63
|
+
tagCodeArtifacts,
|
|
52
64
|
TelemetryDataTag,
|
|
53
65
|
TelemetryEventPropertyTypes,
|
|
54
|
-
TelemetryLogger,
|
|
55
66
|
TelemetryNullLogger,
|
|
56
|
-
TelemetryUTLogger,
|
|
57
67
|
} from "./logger";
|
|
58
68
|
export { MockLogger } from "./mockLogger";
|
|
59
69
|
export { ThresholdCounter } from "./thresholdCounter";
|
|
@@ -68,4 +78,5 @@ export {
|
|
|
68
78
|
ITelemetryLoggerExt,
|
|
69
79
|
ITaggedTelemetryPropertyTypeExt,
|
|
70
80
|
ITelemetryPropertiesExt,
|
|
81
|
+
TelemetryEventCategory,
|
|
71
82
|
} from "./telemetryTypes";
|