@fluidframework/telemetry-utils 2.0.0-dev.5.3.2.178189 → 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 +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
package/lib/error.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { FluidErrorTypes, } from "@fluidframework/core-interfaces";
|
|
6
|
+
import { LoggingError, NORMALIZED_ERROR_TYPE, isExternalError, normalizeError, wrapError, } from "./errorLogging";
|
|
7
|
+
/**
|
|
8
|
+
* Generic wrapper for an unrecognized/uncategorized error object
|
|
9
|
+
*/
|
|
10
|
+
export class GenericError extends LoggingError {
|
|
11
|
+
/**
|
|
12
|
+
* Create a new GenericError
|
|
13
|
+
* @param message - Error message
|
|
14
|
+
* @param error - inner error object
|
|
15
|
+
* @param props - Telemetry props to include when the error is logged
|
|
16
|
+
*/
|
|
17
|
+
// TODO: Use `unknown` instead (API breaking change because error is not just an input parameter, but a public member of the class)
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
19
|
+
constructor(message, error, props) {
|
|
20
|
+
// Don't try to log the inner error
|
|
21
|
+
super(message, props, new Set(["error"]));
|
|
22
|
+
this.error = error;
|
|
23
|
+
this.errorType = FluidErrorTypes.genericError;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Error indicating an API is being used improperly resulting in an invalid operation.
|
|
28
|
+
*/
|
|
29
|
+
export class UsageError extends LoggingError {
|
|
30
|
+
constructor(message, props) {
|
|
31
|
+
super(message, { ...props, usageError: true });
|
|
32
|
+
this.errorType = FluidErrorTypes.usageError;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* DataCorruptionError indicates that we encountered definitive evidence that the data at rest
|
|
37
|
+
* backing this container is corrupted, and this container would never be expected to load properly again
|
|
38
|
+
*/
|
|
39
|
+
export class DataCorruptionError extends LoggingError {
|
|
40
|
+
constructor(message, props) {
|
|
41
|
+
super(message, { ...props, dataProcessingError: 1 });
|
|
42
|
+
this.errorType = FluidErrorTypes.dataCorruptionError;
|
|
43
|
+
this.canRetry = false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Indicates we hit a fatal error while processing incoming data from the Fluid Service.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
*
|
|
51
|
+
* The error will often originate in the dataStore or DDS implementation that is responding to incoming changes.
|
|
52
|
+
* This differs from {@link DataCorruptionError} in that this may be a transient error that will not repro in another
|
|
53
|
+
* client or session.
|
|
54
|
+
*/
|
|
55
|
+
export class DataProcessingError extends LoggingError {
|
|
56
|
+
constructor(errorMessage, props) {
|
|
57
|
+
super(errorMessage, props);
|
|
58
|
+
/**
|
|
59
|
+
* {@inheritDoc IFluidErrorBase.errorType}
|
|
60
|
+
*/
|
|
61
|
+
this.errorType = FluidErrorTypes.dataProcessingError;
|
|
62
|
+
this.canRetry = false;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a new `DataProcessingError` detected and raised within the Fluid Framework.
|
|
66
|
+
*/
|
|
67
|
+
static create(errorMessage, dataProcessingCodepath, sequencedMessage, props = {}) {
|
|
68
|
+
const dataProcessingError = DataProcessingError.wrapIfUnrecognized(errorMessage, dataProcessingCodepath, sequencedMessage);
|
|
69
|
+
dataProcessingError.addTelemetryProperties(props);
|
|
70
|
+
return dataProcessingError;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Wrap the given error in a `DataProcessingError`, unless the error is already of a known type
|
|
74
|
+
* with the exception of a normalized {@link LoggingError}, which will still be wrapped.
|
|
75
|
+
*
|
|
76
|
+
* In either case, the error will have some relevant properties added for telemetry.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
*
|
|
80
|
+
* We wrap conditionally since known error types represent well-understood failure modes, and ideally
|
|
81
|
+
* one day we will move away from throwing these errors but rather we'll return them.
|
|
82
|
+
* But an unrecognized error needs to be classified as `DataProcessingError`.
|
|
83
|
+
*
|
|
84
|
+
* @param originalError - The error to be converted.
|
|
85
|
+
* @param dataProcessingCodepath - Which code-path failed while processing data.
|
|
86
|
+
* @param messageLike - Message to include info about via telemetry props.
|
|
87
|
+
*
|
|
88
|
+
* @returns Either a new `DataProcessingError`, or (if wrapping is deemed unnecessary) the given error.
|
|
89
|
+
*/
|
|
90
|
+
static wrapIfUnrecognized(originalError, dataProcessingCodepath, messageLike) {
|
|
91
|
+
const props = {
|
|
92
|
+
dataProcessingError: 1,
|
|
93
|
+
dataProcessingCodepath,
|
|
94
|
+
...(messageLike === undefined
|
|
95
|
+
? undefined
|
|
96
|
+
: extractSafePropertiesFromMessage(messageLike)),
|
|
97
|
+
};
|
|
98
|
+
const normalizedError = normalizeError(originalError, { props });
|
|
99
|
+
// Note that other errors may have the NORMALIZED_ERROR_TYPE errorType,
|
|
100
|
+
// but if so they are still suitable to be wrapped as DataProcessingError.
|
|
101
|
+
if (isExternalError(normalizedError) ||
|
|
102
|
+
normalizedError.errorType === NORMALIZED_ERROR_TYPE) {
|
|
103
|
+
// Create a new DataProcessingError to wrap this external error
|
|
104
|
+
const dataProcessingError = wrapError(normalizedError, (message) => new DataProcessingError(message));
|
|
105
|
+
// Copy over the props above and any others added to this error since first being normalized
|
|
106
|
+
dataProcessingError.addTelemetryProperties(normalizedError.getTelemetryProperties());
|
|
107
|
+
return dataProcessingError;
|
|
108
|
+
}
|
|
109
|
+
return normalizedError;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extracts specific properties from the provided message that we know are safe to log.
|
|
114
|
+
*
|
|
115
|
+
* @param messageLike - Message to include info about via telemetry props.
|
|
116
|
+
*/
|
|
117
|
+
export const extractSafePropertiesFromMessage = (messageLike) => ({
|
|
118
|
+
messageClientId: messageLike.clientId === null ? "null" : messageLike.clientId,
|
|
119
|
+
messageSequenceNumber: messageLike.sequenceNumber,
|
|
120
|
+
messageClientSequenceNumber: messageLike.clientSequenceNumber,
|
|
121
|
+
messageReferenceSequenceNumber: messageLike.referenceSequenceNumber,
|
|
122
|
+
messageMinimumSequenceNumber: messageLike.minimumSequenceNumber,
|
|
123
|
+
messageTimestamp: messageLike.timestamp,
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=error.js.map
|
package/lib/error.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tFluidErrorTypes,\n\tIGenericError,\n\tIErrorBase,\n\tITelemetryBaseProperties,\n\tIUsageError,\n} from \"@fluidframework/core-interfaces\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\n\nimport {\n\tLoggingError,\n\tNORMALIZED_ERROR_TYPE,\n\tisExternalError,\n\tnormalizeError,\n\twrapError,\n} from \"./errorLogging\";\nimport { IFluidErrorBase } from \"./fluidErrorBase\";\n\n/**\n * Generic wrapper for an unrecognized/uncategorized error object\n */\nexport class GenericError extends LoggingError implements IGenericError, IFluidErrorBase {\n\treadonly errorType = FluidErrorTypes.genericError;\n\n\t/**\n\t * Create a new GenericError\n\t * @param message - Error message\n\t * @param error - inner error object\n\t * @param props - Telemetry props to include when the error is logged\n\t */\n\t// TODO: Use `unknown` instead (API breaking change because error is not just an input parameter, but a public member of the class)\n\t// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any\n\tconstructor(message: string, public readonly error?: any, props?: ITelemetryBaseProperties) {\n\t\t// Don't try to log the inner error\n\t\tsuper(message, props, new Set([\"error\"]));\n\t}\n}\n\n/**\n * Error indicating an API is being used improperly resulting in an invalid operation.\n */\nexport class UsageError extends LoggingError implements IUsageError, IFluidErrorBase {\n\treadonly errorType = FluidErrorTypes.usageError;\n\n\tconstructor(message: string, props?: ITelemetryBaseProperties) {\n\t\tsuper(message, { ...props, usageError: true });\n\t}\n}\n\n/**\n * DataCorruptionError indicates that we encountered definitive evidence that the data at rest\n * backing this container is corrupted, and this container would never be expected to load properly again\n */\nexport class DataCorruptionError extends LoggingError implements IErrorBase, IFluidErrorBase {\n\treadonly errorType = FluidErrorTypes.dataCorruptionError;\n\treadonly canRetry = false;\n\n\tconstructor(message: string, props: ITelemetryBaseProperties) {\n\t\tsuper(message, { ...props, dataProcessingError: 1 });\n\t}\n}\n\n/**\n * Indicates we hit a fatal error while processing incoming data from the Fluid Service.\n *\n * @remarks\n *\n * The error will often originate in the dataStore or DDS implementation that is responding to incoming changes.\n * This differs from {@link DataCorruptionError} in that this may be a transient error that will not repro in another\n * client or session.\n */\nexport class DataProcessingError extends LoggingError implements IErrorBase, IFluidErrorBase {\n\t/**\n\t * {@inheritDoc IFluidErrorBase.errorType}\n\t */\n\tpublic readonly errorType = FluidErrorTypes.dataProcessingError;\n\n\tpublic readonly canRetry = false;\n\n\tprivate constructor(errorMessage: string, props?: ITelemetryBaseProperties) {\n\t\tsuper(errorMessage, props);\n\t}\n\n\t/**\n\t * Create a new `DataProcessingError` detected and raised within the Fluid Framework.\n\t */\n\tpublic static create(\n\t\terrorMessage: string,\n\t\tdataProcessingCodepath: string,\n\t\tsequencedMessage?: ISequencedDocumentMessage,\n\t\tprops: ITelemetryBaseProperties = {},\n\t): IFluidErrorBase {\n\t\tconst dataProcessingError = DataProcessingError.wrapIfUnrecognized(\n\t\t\terrorMessage,\n\t\t\tdataProcessingCodepath,\n\t\t\tsequencedMessage,\n\t\t);\n\t\tdataProcessingError.addTelemetryProperties(props);\n\n\t\treturn dataProcessingError;\n\t}\n\n\t/**\n\t * Wrap the given error in a `DataProcessingError`, unless the error is already of a known type\n\t * with the exception of a normalized {@link LoggingError}, which will still be wrapped.\n\t *\n\t * In either case, the error will have some relevant properties added for telemetry.\n\t *\n\t * @remarks\n\t *\n\t * We wrap conditionally since known error types represent well-understood failure modes, and ideally\n\t * one day we will move away from throwing these errors but rather we'll return them.\n\t * But an unrecognized error needs to be classified as `DataProcessingError`.\n\t *\n\t * @param originalError - The error to be converted.\n\t * @param dataProcessingCodepath - Which code-path failed while processing data.\n\t * @param messageLike - Message to include info about via telemetry props.\n\t *\n\t * @returns Either a new `DataProcessingError`, or (if wrapping is deemed unnecessary) the given error.\n\t */\n\tpublic static wrapIfUnrecognized(\n\t\toriginalError: unknown,\n\t\tdataProcessingCodepath: string,\n\t\tmessageLike?: Partial<\n\t\t\tPick<\n\t\t\t\tISequencedDocumentMessage,\n\t\t\t\t| \"clientId\"\n\t\t\t\t| \"sequenceNumber\"\n\t\t\t\t| \"clientSequenceNumber\"\n\t\t\t\t| \"referenceSequenceNumber\"\n\t\t\t\t| \"minimumSequenceNumber\"\n\t\t\t\t| \"timestamp\"\n\t\t\t>\n\t\t>,\n\t): IFluidErrorBase {\n\t\tconst props = {\n\t\t\tdataProcessingError: 1,\n\t\t\tdataProcessingCodepath,\n\t\t\t...(messageLike === undefined\n\t\t\t\t? undefined\n\t\t\t\t: extractSafePropertiesFromMessage(messageLike)),\n\t\t};\n\n\t\tconst normalizedError = normalizeError(originalError, { props });\n\t\t// Note that other errors may have the NORMALIZED_ERROR_TYPE errorType,\n\t\t// but if so they are still suitable to be wrapped as DataProcessingError.\n\t\tif (\n\t\t\tisExternalError(normalizedError) ||\n\t\t\tnormalizedError.errorType === NORMALIZED_ERROR_TYPE\n\t\t) {\n\t\t\t// Create a new DataProcessingError to wrap this external error\n\t\t\tconst dataProcessingError = wrapError(\n\t\t\t\tnormalizedError,\n\t\t\t\t(message: string) => new DataProcessingError(message),\n\t\t\t);\n\n\t\t\t// Copy over the props above and any others added to this error since first being normalized\n\t\t\tdataProcessingError.addTelemetryProperties(normalizedError.getTelemetryProperties());\n\n\t\t\treturn dataProcessingError;\n\t\t}\n\t\treturn normalizedError;\n\t}\n}\n\n/**\n * Extracts specific properties from the provided message that we know are safe to log.\n *\n * @param messageLike - Message to include info about via telemetry props.\n */\nexport const extractSafePropertiesFromMessage = (\n\tmessageLike: Partial<\n\t\tPick<\n\t\t\tISequencedDocumentMessage,\n\t\t\t| \"clientId\"\n\t\t\t| \"sequenceNumber\"\n\t\t\t| \"clientSequenceNumber\"\n\t\t\t| \"referenceSequenceNumber\"\n\t\t\t| \"minimumSequenceNumber\"\n\t\t\t| \"timestamp\"\n\t\t>\n\t>,\n): {\n\tmessageClientId: string | undefined;\n\tmessageSequenceNumber: number | undefined;\n\tmessageClientSequenceNumber: number | undefined;\n\tmessageReferenceSequenceNumber: number | undefined;\n\tmessageMinimumSequenceNumber: number | undefined;\n\tmessageTimestamp: number | undefined;\n} => ({\n\tmessageClientId: messageLike.clientId === null ? \"null\" : messageLike.clientId,\n\tmessageSequenceNumber: messageLike.sequenceNumber,\n\tmessageClientSequenceNumber: messageLike.clientSequenceNumber,\n\tmessageReferenceSequenceNumber: messageLike.referenceSequenceNumber,\n\tmessageMinimumSequenceNumber: messageLike.minimumSequenceNumber,\n\tmessageTimestamp: messageLike.timestamp,\n});\n"]}
|
package/lib/errorLogging.d.ts
CHANGED
|
@@ -2,21 +2,29 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { ILoggingError,
|
|
5
|
+
import { ILoggingError, ITelemetryBaseProperties, Tagged } from "@fluidframework/core-interfaces";
|
|
6
6
|
import { IFluidErrorBase } from "./fluidErrorBase";
|
|
7
|
-
import {
|
|
8
|
-
/**
|
|
9
|
-
|
|
7
|
+
import { ITelemetryLoggerExt, TelemetryEventPropertyTypeExt } from "./telemetryTypes";
|
|
8
|
+
/**
|
|
9
|
+
* Inspect the given error for common "safe" props and return them.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractLogSafeErrorProperties(error: unknown, sanitizeStack: boolean): {
|
|
10
12
|
message: string;
|
|
11
13
|
errorType?: string | undefined;
|
|
12
14
|
stack?: string | undefined;
|
|
13
15
|
};
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* type guard for ILoggingError interface
|
|
18
|
+
*/
|
|
19
|
+
export declare const isILoggingError: (x: unknown) => x is ILoggingError;
|
|
20
|
+
/**
|
|
21
|
+
* Metadata to annotate an error object when annotating or normalizing it
|
|
22
|
+
*/
|
|
17
23
|
export interface IFluidErrorAnnotations {
|
|
18
|
-
/**
|
|
19
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Telemetry props to log with the error
|
|
26
|
+
*/
|
|
27
|
+
props?: ITelemetryBaseProperties;
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
30
|
* Normalize the given error yielding a valid Fluid Error
|
|
@@ -44,18 +52,31 @@ export declare function generateStack(): string | undefined;
|
|
|
44
52
|
* @returns A new error object "wrapping" the given error
|
|
45
53
|
*/
|
|
46
54
|
export declare function wrapError<T extends LoggingError>(innerError: unknown, newErrorFn: (message: string) => T): T;
|
|
47
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* The same as wrapError, but also logs the innerError, including the wrapping error's instance ID.
|
|
57
|
+
*
|
|
58
|
+
* @typeParam T - The kind of wrapper error to create.
|
|
59
|
+
*/
|
|
48
60
|
export declare function wrapErrorAndLog<T extends LoggingError>(innerError: unknown, newErrorFn: (message: string) => T, logger: ITelemetryLoggerExt): T;
|
|
61
|
+
/**
|
|
62
|
+
* Attempts to overwrite the error's stack
|
|
63
|
+
*
|
|
64
|
+
* There have been reports of certain JS environments where overwriting stack will throw.
|
|
65
|
+
* If that happens, this adds the given stack as the telemetry property "stack2"
|
|
66
|
+
*
|
|
67
|
+
* @internal
|
|
68
|
+
*/
|
|
69
|
+
export declare function overwriteStack(error: IFluidErrorBase | LoggingError, stack: string): void;
|
|
49
70
|
/**
|
|
50
71
|
* True for any error object that is an (optionally normalized) external error
|
|
51
72
|
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
52
73
|
* or wrapped in a well-known error type
|
|
53
74
|
*/
|
|
54
|
-
export declare function isExternalError(
|
|
75
|
+
export declare function isExternalError(error: unknown): boolean;
|
|
55
76
|
/**
|
|
56
77
|
* Type guard to identify if a particular telemetry property appears to be a tagged telemetry property
|
|
57
78
|
*/
|
|
58
|
-
export declare function isTaggedTelemetryPropertyValue(x:
|
|
79
|
+
export declare function isTaggedTelemetryPropertyValue(x: Tagged<TelemetryEventPropertyTypeExt> | TelemetryEventPropertyTypeExt): x is Tagged<TelemetryEventPropertyTypeExt>;
|
|
59
80
|
/**
|
|
60
81
|
* Borrowed from
|
|
61
82
|
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples}
|
|
@@ -63,7 +84,7 @@ export declare function isTaggedTelemetryPropertyValue(x: ITaggedTelemetryProper
|
|
|
63
84
|
* Not ideal, as will cut values that are not necessarily circular references.
|
|
64
85
|
* Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)
|
|
65
86
|
*/
|
|
66
|
-
export declare const getCircularReplacer: () => (key: string, value:
|
|
87
|
+
export declare const getCircularReplacer: () => (key: string, value: unknown) => any;
|
|
67
88
|
/**
|
|
68
89
|
* Base class for "trusted" errors we create, whose properties can generally be logged to telemetry safely.
|
|
69
90
|
* All properties set on the object, or passed in (via the constructor or addTelemetryProperties),
|
|
@@ -76,7 +97,9 @@ export declare class LoggingError extends Error implements ILoggingError, Omit<I
|
|
|
76
97
|
private _errorInstanceId;
|
|
77
98
|
get errorInstanceId(): string;
|
|
78
99
|
overwriteErrorInstanceId(id: string): void;
|
|
79
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* Backwards compatibility to appease {@link isFluidError} in old code that may handle this error.
|
|
102
|
+
*/
|
|
80
103
|
private readonly fluidErrorCode;
|
|
81
104
|
/**
|
|
82
105
|
* Create a new LoggingError
|
|
@@ -84,22 +107,24 @@ export declare class LoggingError extends Error implements ILoggingError, Omit<I
|
|
|
84
107
|
* @param props - telemetry props to include on the error for when it's logged
|
|
85
108
|
* @param omitPropsFromLogging - properties by name to omit from telemetry props
|
|
86
109
|
*/
|
|
87
|
-
constructor(message: string, props?:
|
|
110
|
+
constructor(message: string, props?: ITelemetryBaseProperties, omitPropsFromLogging?: Set<string>);
|
|
88
111
|
/**
|
|
89
112
|
* Determines if a given object is an instance of a LoggingError
|
|
90
113
|
* @param object - any object
|
|
91
|
-
* @returns
|
|
114
|
+
* @returns true if the object is an instance of a LoggingError, false if not.
|
|
92
115
|
*/
|
|
93
116
|
static typeCheck(object: unknown): object is LoggingError;
|
|
94
117
|
/**
|
|
95
118
|
* Add additional properties to be logged
|
|
96
119
|
*/
|
|
97
|
-
addTelemetryProperties(props:
|
|
120
|
+
addTelemetryProperties(props: ITelemetryBaseProperties): void;
|
|
98
121
|
/**
|
|
99
122
|
* Get all properties fit to be logged to telemetry for this error
|
|
100
123
|
*/
|
|
101
|
-
getTelemetryProperties():
|
|
124
|
+
getTelemetryProperties(): ITelemetryBaseProperties;
|
|
102
125
|
}
|
|
103
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* The Error class used when normalizing an external error
|
|
128
|
+
*/
|
|
104
129
|
export declare const NORMALIZED_ERROR_TYPE = "genericError";
|
|
105
130
|
//# sourceMappingURL=errorLogging.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorLogging.d.ts","sourceRoot":"","sources":["../src/errorLogging.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"errorLogging.d.ts","sourceRoot":"","sources":["../src/errorLogging.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,aAAa,EACb,wBAAwB,EAExB,MAAM,EACN,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAEN,eAAe,EAGf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAStF;;GAEG;AACH,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,OAAO,GACpB;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAoCA;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,MAAO,OAAO,uBACkC,CAAC;AAgB7E;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,KAAK,CAAC,EAAE,wBAAwB,CAAC;CACjC;AAeD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,OAAO,EACd,WAAW,GAAE,sBAA2B,GACtC,eAAe,CAqDjB;AAID;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,IAAI,KAAK,CAgB9C;AAED,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,YAAY,EAC/C,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,GAChC,CAAC,CA6BH;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EACrD,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,EAClC,MAAM,EAAE,mBAAmB,GACzB,CAAC,CAmBH;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAMzF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAWvD;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC7C,CAAC,EAAE,MAAM,CAAC,6BAA6B,CAAC,GAAG,6BAA6B,GACtE,CAAC,IAAI,MAAM,CAAC,6BAA6B,CAAC,CAE5C;AA0DD;;;;;;GAMG;AAGH,eAAO,MAAM,mBAAmB,cAAc,MAAM,SAAS,OAAO,KAAK,GAWxE,CAAC;AAGF;;;;;;GAMG;AACH,qBAAa,YACZ,SAAQ,KACR,YAAW,aAAa,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC;IA0B3D,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAxBtC,OAAO,CAAC,gBAAgB,CAAU;IAClC,IAAI,eAAe,IAAI,MAAM,CAE5B;IACD,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI1C;;OAEG;IAGH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAY;IAE3C;;;;;OAKG;gBAEF,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,wBAAwB,EACf,oBAAoB,GAAE,GAAG,CAAC,MAAM,CAAa;IAa/D;;;;OAIG;WACW,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY;IAWhE;;OAEG;IACI,sBAAsB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI;IAIpE;;OAEG;IACI,sBAAsB,IAAI,wBAAwB;CAUzD;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,iBAAiB,CAAC"}
|
package/lib/errorLogging.js
CHANGED
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { v4 as uuid } from "uuid";
|
|
6
6
|
import { hasErrorInstanceId, isFluidError, isValidLegacyError, } from "./fluidErrorBase";
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Determines if the provided value is an object but neither null nor an array.
|
|
9
|
+
*/
|
|
8
10
|
const isRegularObject = (value) => {
|
|
9
11
|
return value !== null && !Array.isArray(value) && typeof value === "object";
|
|
10
12
|
};
|
|
11
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Inspect the given error for common "safe" props and return them.
|
|
15
|
+
*/
|
|
12
16
|
export function extractLogSafeErrorProperties(error, sanitizeStack) {
|
|
13
17
|
const removeMessageFromStack = (stack, errorName) => {
|
|
14
18
|
if (!sanitizeStack) {
|
|
@@ -21,7 +25,9 @@ export function extractLogSafeErrorProperties(error, sanitizeStack) {
|
|
|
21
25
|
}
|
|
22
26
|
return stackFrames.join("\n");
|
|
23
27
|
};
|
|
24
|
-
const message = typeof
|
|
28
|
+
const message = typeof error?.message === "string"
|
|
29
|
+
? error.message
|
|
30
|
+
: String(error);
|
|
25
31
|
const safeProps = {
|
|
26
32
|
message,
|
|
27
33
|
};
|
|
@@ -37,9 +43,13 @@ export function extractLogSafeErrorProperties(error, sanitizeStack) {
|
|
|
37
43
|
}
|
|
38
44
|
return safeProps;
|
|
39
45
|
}
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
/**
|
|
47
|
+
* type guard for ILoggingError interface
|
|
48
|
+
*/
|
|
49
|
+
export const isILoggingError = (x) => typeof x?.getTelemetryProperties === "function";
|
|
50
|
+
/**
|
|
51
|
+
* Copy props from source onto target, but do not overwrite an existing prop that matches
|
|
52
|
+
*/
|
|
43
53
|
function copyProps(target, source) {
|
|
44
54
|
for (const key of Object.keys(source)) {
|
|
45
55
|
if (target[key] === undefined) {
|
|
@@ -47,8 +57,11 @@ function copyProps(target, source) {
|
|
|
47
57
|
}
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* For backwards compatibility with pre-errorInstanceId valid errors
|
|
62
|
+
*/
|
|
51
63
|
function patchLegacyError(legacyError) {
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
|
52
65
|
const patchMe = legacyError;
|
|
53
66
|
if (patchMe.errorInstanceId === undefined) {
|
|
54
67
|
patchMe.errorInstanceId = uuid();
|
|
@@ -61,14 +74,13 @@ function patchLegacyError(legacyError) {
|
|
|
61
74
|
* @param annotations - Annotations to apply to the normalized error
|
|
62
75
|
*/
|
|
63
76
|
export function normalizeError(error, annotations = {}) {
|
|
64
|
-
var _a;
|
|
65
77
|
// Back-compat, while IFluidErrorBase is rolled out
|
|
66
78
|
if (isValidLegacyError(error)) {
|
|
67
79
|
patchLegacyError(error);
|
|
68
80
|
}
|
|
69
81
|
if (isFluidError(error)) {
|
|
70
82
|
// We can simply add the telemetry props to the error and return it
|
|
71
|
-
error.addTelemetryProperties(
|
|
83
|
+
error.addTelemetryProperties(annotations.props ?? {});
|
|
72
84
|
return error;
|
|
73
85
|
}
|
|
74
86
|
// We have to construct a new Fluid Error, copying safe properties over
|
|
@@ -84,11 +96,11 @@ export function normalizeError(error, annotations = {}) {
|
|
|
84
96
|
const maybeHasRetry = error;
|
|
85
97
|
let retryProps;
|
|
86
98
|
if ("canRetry" in error) {
|
|
87
|
-
retryProps
|
|
99
|
+
retryProps ?? (retryProps = {});
|
|
88
100
|
retryProps.canRetry = maybeHasRetry.canRetry;
|
|
89
101
|
}
|
|
90
102
|
if ("retryAfterSeconds" in error) {
|
|
91
|
-
retryProps
|
|
103
|
+
retryProps ?? (retryProps = {});
|
|
92
104
|
retryProps.retryAfterSeconds = maybeHasRetry.retryAfterSeconds;
|
|
93
105
|
}
|
|
94
106
|
if (retryProps !== undefined) {
|
|
@@ -102,7 +114,10 @@ export function normalizeError(error, annotations = {}) {
|
|
|
102
114
|
const errorTelemetryProps = LoggingError.typeCheck(error)
|
|
103
115
|
? error.getTelemetryProperties()
|
|
104
116
|
: { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase
|
|
105
|
-
fluidError.addTelemetryProperties(
|
|
117
|
+
fluidError.addTelemetryProperties({
|
|
118
|
+
...errorTelemetryProps,
|
|
119
|
+
...annotations.props,
|
|
120
|
+
});
|
|
106
121
|
return fluidError;
|
|
107
122
|
}
|
|
108
123
|
let stackPopulatedOnCreation;
|
|
@@ -126,8 +141,8 @@ export function generateErrorWithStack() {
|
|
|
126
141
|
try {
|
|
127
142
|
throw err;
|
|
128
143
|
}
|
|
129
|
-
catch (
|
|
130
|
-
return
|
|
144
|
+
catch (error) {
|
|
145
|
+
return error;
|
|
131
146
|
}
|
|
132
147
|
}
|
|
133
148
|
export function generateStack() {
|
|
@@ -163,7 +178,11 @@ export function wrapError(innerError, newErrorFn) {
|
|
|
163
178
|
}
|
|
164
179
|
return newError;
|
|
165
180
|
}
|
|
166
|
-
/**
|
|
181
|
+
/**
|
|
182
|
+
* The same as wrapError, but also logs the innerError, including the wrapping error's instance ID.
|
|
183
|
+
*
|
|
184
|
+
* @typeParam T - The kind of wrapper error to create.
|
|
185
|
+
*/
|
|
167
186
|
export function wrapErrorAndLog(innerError, newErrorFn, logger) {
|
|
168
187
|
const newError = wrapError(innerError, newErrorFn);
|
|
169
188
|
// This will match innerError.errorInstanceId if present (see wrapError)
|
|
@@ -177,12 +196,19 @@ export function wrapErrorAndLog(innerError, newErrorFn, logger) {
|
|
|
177
196
|
}, innerError);
|
|
178
197
|
return newError;
|
|
179
198
|
}
|
|
180
|
-
|
|
181
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Attempts to overwrite the error's stack
|
|
201
|
+
*
|
|
202
|
+
* There have been reports of certain JS environments where overwriting stack will throw.
|
|
203
|
+
* If that happens, this adds the given stack as the telemetry property "stack2"
|
|
204
|
+
*
|
|
205
|
+
* @internal
|
|
206
|
+
*/
|
|
207
|
+
export function overwriteStack(error, stack) {
|
|
182
208
|
try {
|
|
183
209
|
Object.assign(error, { stack });
|
|
184
210
|
}
|
|
185
|
-
catch
|
|
211
|
+
catch {
|
|
186
212
|
error.addTelemetryProperties({ stack2: stack });
|
|
187
213
|
}
|
|
188
214
|
}
|
|
@@ -191,29 +217,28 @@ function overwriteStack(error, stack) {
|
|
|
191
217
|
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
192
218
|
* or wrapped in a well-known error type
|
|
193
219
|
*/
|
|
194
|
-
export function isExternalError(
|
|
220
|
+
export function isExternalError(error) {
|
|
195
221
|
// LoggingErrors are an internal FF error type. However, an external error can be converted
|
|
196
222
|
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
|
|
197
223
|
// determine whether the original error was infact external.
|
|
198
|
-
if (LoggingError.typeCheck(
|
|
199
|
-
if (
|
|
200
|
-
return
|
|
224
|
+
if (LoggingError.typeCheck(error)) {
|
|
225
|
+
if (error.errorType === NORMALIZED_ERROR_TYPE) {
|
|
226
|
+
return error.getTelemetryProperties().untrustedOrigin === 1;
|
|
201
227
|
}
|
|
202
228
|
return false;
|
|
203
229
|
}
|
|
204
|
-
return !isValidLegacyError(
|
|
230
|
+
return !isValidLegacyError(error);
|
|
205
231
|
}
|
|
206
232
|
/**
|
|
207
233
|
* Type guard to identify if a particular telemetry property appears to be a tagged telemetry property
|
|
208
234
|
*/
|
|
209
235
|
export function isTaggedTelemetryPropertyValue(x) {
|
|
210
|
-
|
|
211
|
-
return typeof ((_a = x) === null || _a === void 0 ? void 0 : _a.tag) === "string";
|
|
236
|
+
return typeof x?.tag === "string";
|
|
212
237
|
}
|
|
213
238
|
/**
|
|
214
239
|
* Filter serializable telemetry properties
|
|
215
|
-
* @param x -
|
|
216
|
-
* @returns -
|
|
240
|
+
* @param x - Any telemetry prop
|
|
241
|
+
* @returns As-is if x is primitive. returns stringified if x is an array of primitive.
|
|
217
242
|
* otherwise returns null since this is what we support at the moment.
|
|
218
243
|
*/
|
|
219
244
|
function filterValidTelemetryProps(x, key) {
|
|
@@ -269,6 +294,8 @@ function getValidTelemetryProps(obj, keysToOmit) {
|
|
|
269
294
|
* Not ideal, as will cut values that are not necessarily circular references.
|
|
270
295
|
* Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)
|
|
271
296
|
*/
|
|
297
|
+
// TODO: Use `unknown` instead (API breaking change)
|
|
298
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
272
299
|
export const getCircularReplacer = () => {
|
|
273
300
|
const seen = new WeakSet();
|
|
274
301
|
return (key, value) => {
|
|
@@ -281,6 +308,7 @@ export const getCircularReplacer = () => {
|
|
|
281
308
|
return value;
|
|
282
309
|
};
|
|
283
310
|
};
|
|
311
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
284
312
|
/**
|
|
285
313
|
* Base class for "trusted" errors we create, whose properties can generally be logged to telemetry safely.
|
|
286
314
|
* All properties set on the object, or passed in (via the constructor or addTelemetryProperties),
|
|
@@ -299,8 +327,11 @@ export class LoggingError extends Error {
|
|
|
299
327
|
super(message);
|
|
300
328
|
this.omitPropsFromLogging = omitPropsFromLogging;
|
|
301
329
|
this._errorInstanceId = uuid();
|
|
302
|
-
/**
|
|
330
|
+
/**
|
|
331
|
+
* Backwards compatibility to appease {@link isFluidError} in old code that may handle this error.
|
|
332
|
+
*/
|
|
303
333
|
// @ts-expect-error - This field shouldn't be referenced in the current version, but needs to exist at runtime.
|
|
334
|
+
// eslint-disable-next-line @typescript-eslint/prefer-as-const
|
|
304
335
|
this.fluidErrorCode = "-";
|
|
305
336
|
// Don't log this list itself, or the private _errorInstanceId
|
|
306
337
|
omitPropsFromLogging.add("omitPropsFromLogging");
|
|
@@ -318,7 +349,7 @@ export class LoggingError extends Error {
|
|
|
318
349
|
/**
|
|
319
350
|
* Determines if a given object is an instance of a LoggingError
|
|
320
351
|
* @param object - any object
|
|
321
|
-
* @returns
|
|
352
|
+
* @returns true if the object is an instance of a LoggingError, false if not.
|
|
322
353
|
*/
|
|
323
354
|
static typeCheck(object) {
|
|
324
355
|
if (typeof object === "object" && object !== null) {
|
|
@@ -340,10 +371,17 @@ export class LoggingError extends Error {
|
|
|
340
371
|
getTelemetryProperties() {
|
|
341
372
|
const taggableProps = getValidTelemetryProps(this, this.omitPropsFromLogging);
|
|
342
373
|
// Include non-enumerable props that are not returned by getValidTelemetryProps
|
|
343
|
-
return
|
|
374
|
+
return {
|
|
375
|
+
...taggableProps,
|
|
376
|
+
stack: this.stack,
|
|
377
|
+
message: this.message,
|
|
378
|
+
errorInstanceId: this._errorInstanceId,
|
|
379
|
+
};
|
|
344
380
|
}
|
|
345
381
|
}
|
|
346
|
-
/**
|
|
382
|
+
/**
|
|
383
|
+
* The Error class used when normalizing an external error
|
|
384
|
+
*/
|
|
347
385
|
export const NORMALIZED_ERROR_TYPE = "genericError";
|
|
348
386
|
class NormalizedLoggingError extends LoggingError {
|
|
349
387
|
constructor(errorProps) {
|