@fluidframework/telemetry-utils 2.0.0-internal.1.1.2 → 2.0.0-internal.1.2.0
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/dist/errorLogging.d.ts +10 -1
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js +36 -13
- package/dist/errorLogging.js.map +1 -1
- package/dist/mockLogger.d.ts +2 -0
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +12 -0
- package/dist/mockLogger.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/lib/errorLogging.d.ts +10 -1
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js +35 -12
- package/lib/errorLogging.js.map +1 -1
- package/lib/mockLogger.d.ts +2 -0
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +12 -0
- package/lib/mockLogger.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +8 -5
- package/src/errorLogging.ts +36 -13
- package/src/mockLogger.ts +13 -0
- package/src/packageVersion.ts +1 -1
package/dist/errorLogging.d.ts
CHANGED
|
@@ -47,7 +47,8 @@ export declare function wrapError<T extends LoggingError>(innerError: unknown, n
|
|
|
47
47
|
export declare function wrapErrorAndLog<T extends LoggingError>(innerError: unknown, newErrorFn: (message: string) => T, logger: ITelemetryLogger): T;
|
|
48
48
|
/**
|
|
49
49
|
* True for any error object that is an (optionally normalized) external error
|
|
50
|
-
* False for any error we created and raised within the FF codebase
|
|
50
|
+
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
51
|
+
* or wrapped in a well-known error type
|
|
51
52
|
*/
|
|
52
53
|
export declare function isExternalError(e: any): boolean;
|
|
53
54
|
/**
|
|
@@ -83,6 +84,12 @@ export declare class LoggingError extends Error implements ILoggingError, Omit<I
|
|
|
83
84
|
* @param omitPropsFromLogging - properties by name to omit from telemetry props
|
|
84
85
|
*/
|
|
85
86
|
constructor(message: string, props?: ITelemetryProperties, omitPropsFromLogging?: Set<string>);
|
|
87
|
+
/**
|
|
88
|
+
* Determines if a given object is an instance of a LoggingError
|
|
89
|
+
* @param object - any object
|
|
90
|
+
* @returns - true if the object is an instance of a LoggingError, false if not.
|
|
91
|
+
*/
|
|
92
|
+
static typeCheck(object: unknown): object is LoggingError;
|
|
86
93
|
/**
|
|
87
94
|
* Add additional properties to be logged
|
|
88
95
|
*/
|
|
@@ -92,4 +99,6 @@ export declare class LoggingError extends Error implements ILoggingError, Omit<I
|
|
|
92
99
|
*/
|
|
93
100
|
getTelemetryProperties(): ITelemetryProperties;
|
|
94
101
|
}
|
|
102
|
+
/** The Error class used when normalizing an external error */
|
|
103
|
+
export declare const NORMALIZED_ERROR_TYPE = "genericError";
|
|
95
104
|
//# 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,EACH,aAAa,EACb,4BAA4B,EAC5B,gBAAgB,EAChB,oBAAoB,EAEvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAEH,eAAe,EAGlB,MAAM,kBAAkB,CAAC;AAO1B,sEAAsE;AACtE,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO;aAiBhD,MAAM;;;EAkBrC;AAED,6CAA6C;AAC7C,eAAO,MAAM,eAAe,MAAO,GAAG,uBAAwE,CAAC;AAW/G,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAYD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,WAAW,GAAE,sBAA2B,GACzC,eAAe,
|
|
1
|
+
{"version":3,"file":"errorLogging.d.ts","sourceRoot":"","sources":["../src/errorLogging.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,aAAa,EACb,4BAA4B,EAC5B,gBAAgB,EAChB,oBAAoB,EAEvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAEH,eAAe,EAGlB,MAAM,kBAAkB,CAAC;AAO1B,sEAAsE;AACtE,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO;aAiBhD,MAAM;;;EAkBrC;AAED,6CAA6C;AAC7C,eAAO,MAAM,eAAe,MAAO,GAAG,uBAAwE,CAAC;AAW/G,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAYD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,WAAW,GAAE,sBAA2B,GACzC,eAAe,CA0CjB;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,EAC5C,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,GACnC,CAAC,CAgCH;AAED,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EAClD,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,EAClC,MAAM,EAAE,gBAAgB,KAiB3B;AAWD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAW/C;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,4BAA4B,CAExF;AAwDD;;;;;;EAME;AACF,eAAO,MAAM,mBAAmB,cAEf,MAAM,SAAS,GAAG,KAAG,GASrC,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,KAAM,YAAW,aAAa,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC;IAkB5F,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAjBzC,OAAO,CAAC,gBAAgB,CAAU;IAClC,IAAI,eAAe,WAAoC;IACvD,wBAAwB,CAAC,EAAE,EAAE,MAAM;IAEnC,2FAA2F;IAE3F,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAY;IAE3C;;;;;OAKG;gBAEC,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,oBAAoB,EACX,oBAAoB,GAAE,GAAG,CAAC,MAAM,CAAa;IAalE;;;;MAIE;WACY,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY;IAShE;;OAEG;IACI,sBAAsB,CAAC,KAAK,EAAE,oBAAoB;IAIzD;;OAEG;IACI,sBAAsB,IAAI,oBAAoB;CAUxD;AAED,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,iBAAiB,CAAC"}
|
package/dist/errorLogging.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.LoggingError = exports.getCircularReplacer = exports.isTaggedTelemetryPropertyValue = exports.isExternalError = exports.wrapErrorAndLog = exports.wrapError = exports.generateStack = exports.generateErrorWithStack = exports.normalizeError = exports.isILoggingError = exports.extractLogSafeErrorProperties = void 0;
|
|
7
|
+
exports.NORMALIZED_ERROR_TYPE = exports.LoggingError = exports.getCircularReplacer = exports.isTaggedTelemetryPropertyValue = exports.isExternalError = exports.wrapErrorAndLog = exports.wrapError = exports.generateStack = exports.generateErrorWithStack = exports.normalizeError = exports.isILoggingError = exports.extractLogSafeErrorProperties = void 0;
|
|
8
8
|
const uuid_1 = require("uuid");
|
|
9
9
|
const fluidErrorBase_1 = require("./fluidErrorBase");
|
|
10
10
|
/** @returns true if value is an object but neither null nor an array */
|
|
@@ -80,7 +80,7 @@ function normalizeError(error, annotations = {}) {
|
|
|
80
80
|
}
|
|
81
81
|
// We have to construct a new Fluid Error, copying safe properties over
|
|
82
82
|
const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);
|
|
83
|
-
const fluidError = new
|
|
83
|
+
const fluidError = new NormalizedLoggingError({
|
|
84
84
|
message,
|
|
85
85
|
stack,
|
|
86
86
|
});
|
|
@@ -95,8 +95,10 @@ function normalizeError(error, annotations = {}) {
|
|
|
95
95
|
// This is only interesting for non-objects
|
|
96
96
|
fluidError.addTelemetryProperties({ typeofError: typeof (error) });
|
|
97
97
|
}
|
|
98
|
-
const
|
|
99
|
-
|
|
98
|
+
const errorTelemetryProps = LoggingError.typeCheck(error)
|
|
99
|
+
? error.getTelemetryProperties()
|
|
100
|
+
: { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase
|
|
101
|
+
fluidError.addTelemetryProperties(Object.assign(Object.assign({}, errorTelemetryProps), annotations.props));
|
|
100
102
|
return fluidError;
|
|
101
103
|
}
|
|
102
104
|
exports.normalizeError = normalizeError;
|
|
@@ -187,12 +189,20 @@ function overwriteStack(error, stack) {
|
|
|
187
189
|
}
|
|
188
190
|
/**
|
|
189
191
|
* True for any error object that is an (optionally normalized) external error
|
|
190
|
-
* False for any error we created and raised within the FF codebase
|
|
192
|
+
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
193
|
+
* or wrapped in a well-known error type
|
|
191
194
|
*/
|
|
192
195
|
function isExternalError(e) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
// LoggingErrors are an internal FF error type. However, an external error can be converted
|
|
197
|
+
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
|
|
198
|
+
// determine whether the original error was infact external.
|
|
199
|
+
if (LoggingError.typeCheck(e)) {
|
|
200
|
+
if (e.errorType === exports.NORMALIZED_ERROR_TYPE) {
|
|
201
|
+
return e.getTelemetryProperties().untrustedOrigin === 1;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
return !(0, fluidErrorBase_1.isValidLegacyError)(e);
|
|
196
206
|
}
|
|
197
207
|
exports.isExternalError = isExternalError;
|
|
198
208
|
/**
|
|
@@ -304,6 +314,19 @@ class LoggingError extends Error {
|
|
|
304
314
|
}
|
|
305
315
|
get errorInstanceId() { return this._errorInstanceId; }
|
|
306
316
|
overwriteErrorInstanceId(id) { this._errorInstanceId = id; }
|
|
317
|
+
/**
|
|
318
|
+
* Determines if a given object is an instance of a LoggingError
|
|
319
|
+
* @param object - any object
|
|
320
|
+
* @returns - true if the object is an instance of a LoggingError, false if not.
|
|
321
|
+
*/
|
|
322
|
+
static typeCheck(object) {
|
|
323
|
+
if (typeof object === "object" && object !== null) {
|
|
324
|
+
return typeof object.addTelemetryProperties === "function"
|
|
325
|
+
&& typeof object.getTelemetryProperties === "function"
|
|
326
|
+
&& typeof object.errorInstanceId === "string";
|
|
327
|
+
}
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
307
330
|
/**
|
|
308
331
|
* Add additional properties to be logged
|
|
309
332
|
*/
|
|
@@ -321,16 +344,16 @@ class LoggingError extends Error {
|
|
|
321
344
|
}
|
|
322
345
|
exports.LoggingError = LoggingError;
|
|
323
346
|
/** The Error class used when normalizing an external error */
|
|
324
|
-
|
|
347
|
+
exports.NORMALIZED_ERROR_TYPE = "genericError";
|
|
348
|
+
class NormalizedLoggingError extends LoggingError {
|
|
325
349
|
constructor(errorProps) {
|
|
326
350
|
super(errorProps.message);
|
|
327
|
-
|
|
351
|
+
// errorType "genericError" is used as a default value throughout the code.
|
|
352
|
+
// Note that this matches ContainerErrorType/DriverErrorType's genericError
|
|
353
|
+
this.errorType = exports.NORMALIZED_ERROR_TYPE;
|
|
328
354
|
if (errorProps.stack !== undefined) {
|
|
329
355
|
overwriteStack(this, errorProps.stack);
|
|
330
356
|
}
|
|
331
357
|
}
|
|
332
358
|
}
|
|
333
|
-
// errorType "genericError" is used as a default value throughout the code.
|
|
334
|
-
// Note that this matches ContainerErrorType/DriverErrorType's genericError
|
|
335
|
-
NormalizedExternalError.normalizedErrorType = "genericError";
|
|
336
359
|
//# sourceMappingURL=errorLogging.js.map
|
package/dist/errorLogging.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorLogging.js","sourceRoot":"","sources":["../src/errorLogging.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 ILoggingError,\n ITaggedTelemetryPropertyType,\n ITelemetryLogger,\n ITelemetryProperties,\n TelemetryEventPropertyType,\n} from \"@fluidframework/common-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n hasErrorInstanceId,\n IFluidErrorBase,\n isFluidError,\n isValidLegacyError,\n} from \"./fluidErrorBase\";\n\n/** @returns true if value is an object but neither null nor an array */\nconst isRegularObject = (value: any): boolean => {\n return value !== null && !Array.isArray(value) && typeof value === \"object\";\n};\n\n/** Inspect the given error for common \"safe\" props and return them */\nexport function extractLogSafeErrorProperties(error: any, sanitizeStack: boolean) {\n const removeMessageFromStack = (stack: string, errorName?: string) => {\n if (!sanitizeStack) {\n return stack;\n }\n const stackFrames = stack.split(\"\\n\");\n stackFrames.shift(); // Remove \"[ErrorName]: [ErrorMessage]\"\n if (errorName !== undefined) {\n stackFrames.unshift(errorName); // Add \"[ErrorName]\"\n }\n return stackFrames.join(\"\\n\");\n };\n\n const message = (typeof error?.message === \"string\")\n ? error.message as string\n : String(error);\n\n const safeProps: { message: string; errorType?: string; stack?: string; } = {\n message,\n };\n\n if (isRegularObject(error)) {\n const { errorType, stack, name } = error;\n\n if (typeof errorType === \"string\") {\n safeProps.errorType = errorType;\n }\n\n if (typeof stack === \"string\") {\n const errorName = (typeof name === \"string\") ? name : undefined;\n safeProps.stack = removeMessageFromStack(stack, errorName);\n }\n }\n\n return safeProps;\n}\n\n/** type guard for ILoggingError interface */\nexport const isILoggingError = (x: any): x is ILoggingError => typeof x?.getTelemetryProperties === \"function\";\n\n/** Copy props from source onto target, but do not overwrite an existing prop that matches */\nfunction copyProps(target: ITelemetryProperties | LoggingError, source: ITelemetryProperties) {\n for (const key of Object.keys(source)) {\n if (target[key] === undefined) {\n target[key] = source[key];\n }\n }\n}\n\n/** Metadata to annotate an error object when annotating or normalizing it */\nexport interface IFluidErrorAnnotations {\n /** Telemetry props to log with the error */\n props?: ITelemetryProperties;\n}\n\n/** For backwards compatibility with pre-errorInstanceId valid errors */\nfunction patchLegacyError(\n legacyError: Omit<IFluidErrorBase, \"errorInstanceId\">,\n): asserts legacyError is IFluidErrorBase {\n const patchMe: { -readonly [P in \"errorInstanceId\"]?: IFluidErrorBase[P] } = legacyError as any;\n if (patchMe.errorInstanceId === undefined) {\n patchMe.errorInstanceId = uuid();\n }\n}\n\n/**\n * Normalize the given error yielding a valid Fluid Error\n * @returns A valid Fluid Error with any provided annotations applied\n * @param error - The error to normalize\n * @param annotations - Annotations to apply to the normalized error\n */\nexport function normalizeError(\n error: unknown,\n annotations: IFluidErrorAnnotations = {},\n): IFluidErrorBase {\n // Back-compat, while IFluidErrorBase is rolled out\n if (isValidLegacyError(error)) {\n patchLegacyError(error);\n }\n\n if (isFluidError(error)) {\n // We can simply add the telemetry props to the error and return it\n error.addTelemetryProperties(annotations.props ?? {});\n return error;\n }\n\n // We have to construct a new Fluid Error, copying safe properties over\n const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);\n const fluidError: IFluidErrorBase = new NormalizedExternalError({\n message,\n stack,\n });\n\n // We need to preserve these properties which are used in a non-typesafe way throughout driver code (see #8743)\n // Anywhere they are set should be on a valid Fluid Error that would have been returned above,\n // but we can't prove it with the types, so adding this defensive measure.\n if (typeof error === \"object\" && error !== null) {\n const { canRetry, retryAfterSeconds } = error as any;\n Object.assign(normalizeError, { canRetry, retryAfterSeconds });\n }\n\n if (typeof (error) !== \"object\") {\n // This is only interesting for non-objects\n fluidError.addTelemetryProperties({ typeofError: typeof (error) });\n }\n\n const originalErrorTelemetryProps = isILoggingError(error) ? error.getTelemetryProperties() : {};\n fluidError.addTelemetryProperties({\n ...originalErrorTelemetryProps,\n ...annotations.props,\n untrustedOrigin: 1, // This will let us filter to errors not originated by our own code\n });\n\n return fluidError;\n}\n\nlet stackPopulatedOnCreation: boolean | undefined;\n\n/**\n * The purpose of this function is to provide ability to capture stack context quickly.\n * Accessing new Error().stack is slow, and the slowest part is accessing stack property itself.\n * There are scenarios where we generate error with stack, but error is handled in most cases and\n * stack property is not accessed.\n * For such cases it's better to not read stack property right away, but rather delay it until / if it's needed\n * Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.\n * @returns Error object that has stack populated.\n */\n export function generateErrorWithStack(): Error {\n const err = new Error(\"<<generated stack>>\");\n\n if (stackPopulatedOnCreation === undefined) {\n stackPopulatedOnCreation = (err.stack !== undefined);\n }\n\n if (stackPopulatedOnCreation) {\n return err;\n }\n\n try {\n throw err;\n } catch (e) {\n return e as Error;\n }\n}\n\nexport function generateStack(): string | undefined {\n return generateErrorWithStack().stack;\n}\n\n/**\n * Create a new error using newErrorFn, wrapping and caused by the given unknown error.\n * Copies the inner error's stack, errorInstanceId and telemetry props over to the new error if present\n * @param innerError - An error from untrusted/unknown origins\n * @param newErrorFn - callback that will create a new error given the original error's message\n * @returns A new error object \"wrapping\" the given error\n */\nexport function wrapError<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n): T {\n const {\n message,\n stack,\n } = extractLogSafeErrorProperties(innerError, false /* sanitizeStack */);\n\n const newError = newErrorFn(message);\n\n if (stack !== undefined) {\n overwriteStack(newError, stack);\n }\n\n // Mark external errors with untrustedOrigin flag\n if (isExternalError(innerError)) {\n newError.addTelemetryProperties({ untrustedOrigin: 1 });\n }\n\n // Reuse errorInstanceId\n if (hasErrorInstanceId(innerError)) {\n newError.overwriteErrorInstanceId(innerError.errorInstanceId);\n\n // For \"back-compat\" in the logs\n newError.addTelemetryProperties({ innerErrorInstanceId: innerError.errorInstanceId });\n }\n\n // Lastly, copy over all other telemetry properties. Note these will not overwrite existing properties\n // This will include the untrustedOrigin property if the inner error itself was created from an external error\n if (isILoggingError(innerError)) {\n newError.addTelemetryProperties(innerError.getTelemetryProperties());\n }\n\n return newError;\n}\n\n/** The same as wrapError, but also logs the innerError, including the wrapping error's instance id */\nexport function wrapErrorAndLog<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n logger: ITelemetryLogger,\n) {\n const newError = wrapError(innerError, newErrorFn);\n\n // This will match innerError.errorInstanceId if present (see wrapError)\n const errorInstanceId = newError.errorInstanceId;\n\n // For \"back-compat\" in the logs\n const wrappedByErrorInstanceId = errorInstanceId;\n\n logger.sendTelemetryEvent({\n eventName: \"WrapError\",\n errorInstanceId,\n wrappedByErrorInstanceId,\n }, innerError);\n\n return newError;\n}\n\nfunction overwriteStack(error: IFluidErrorBase | LoggingError, stack: string) {\n // supposedly setting stack on an Error can throw.\n try {\n Object.assign(error, { stack });\n } catch (errorSettingStack) {\n error.addTelemetryProperties({ stack2: stack });\n }\n}\n\n/**\n * True for any error object that is an (optionally normalized) external error\n * False for any error we created and raised within the FF codebase, or wrapped in a well-known error type\n */\nexport function isExternalError(e: any): boolean {\n return !isValidLegacyError(e) ||\n (e.getTelemetryProperties().untrustedOrigin === 1 &&\n e.errorType === NormalizedExternalError.normalizedErrorType);\n}\n\n/**\n * Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property\n */\nexport function isTaggedTelemetryPropertyValue(x: any): x is ITaggedTelemetryPropertyType {\n return typeof (x?.tag) === \"string\";\n}\n\n/**\n * Filter serializable telemetry properties\n * @param x - any telemetry prop\n * @returns - as-is if x is primitive. returns stringified if x is an array of primitive.\n * otherwise returns null since this is what we support at the moment.\n */\nfunction filterValidTelemetryProps(x: any, key: string): TelemetryEventPropertyType {\n if (Array.isArray(x) && x.every((val) => isTelemetryEventPropertyValue(val))) {\n return JSON.stringify(x);\n }\n if (isTelemetryEventPropertyValue(x)) {\n return x;\n }\n // We don't support logging arbitrary objects\n console.error(`UnSupported Format of Logging Error Property for key ${key}:`, x);\n return \"REDACTED (arbitrary object)\";\n}\n\n// checking type of x, returns false if x is null\nfunction isTelemetryEventPropertyValue(x: any): x is TelemetryEventPropertyType {\n switch (typeof x) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"undefined\":\n return true;\n default:\n return false;\n }\n}\n/**\n * Walk an object's enumerable properties to find those fit for telemetry.\n */\nfunction getValidTelemetryProps(obj: any, keysToOmit: Set<string>): ITelemetryProperties {\n const props: ITelemetryProperties = {};\n for (const key of Object.keys(obj)) {\n if (keysToOmit.has(key)) {\n continue;\n }\n const val = obj[key];\n\n // ensure only valid props get logged, since props of logging error could be in any shape\n if (isTaggedTelemetryPropertyValue(val)) {\n props[key] = {\n value: filterValidTelemetryProps(val.value, key),\n tag: val.tag,\n };\n } else {\n props[key] = filterValidTelemetryProps(val, key);\n }\n }\n return props;\n}\n\n/**\n * Borrowed from\n * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples}\n * Avoids runtime errors with circular references.\n * Not ideal, as will cut values that are not necessarily circular references.\n * Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)\n*/\nexport const getCircularReplacer = () => {\n const seen = new WeakSet();\n return (key: string, value: any): any => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) {\n return \"<removed/circular>\";\n }\n seen.add(value);\n }\n return value;\n };\n};\n\n/**\n * Base class for \"trusted\" errors we create, whose properties can generally be logged to telemetry safely.\n * All properties set on the object, or passed in (via the constructor or addTelemetryProperties),\n * will be logged in accordance with their tag, if present.\n *\n * PLEASE take care to avoid setting sensitive data on this object without proper tagging!\n */\nexport class LoggingError extends Error implements ILoggingError, Omit<IFluidErrorBase, \"errorType\"> {\n private _errorInstanceId = uuid();\n get errorInstanceId() { return this._errorInstanceId; }\n overwriteErrorInstanceId(id: string) { this._errorInstanceId = id; }\n\n /** Back-compat to appease isFluidError typeguard in old code that may handle this error */\n // @ts-expect-error - This field shouldn't be referenced in the current version, but needs to exist at runtime.\n private readonly fluidErrorCode: \"-\" = \"-\";\n\n /**\n * Create a new LoggingError\n * @param message - Error message to use for Error base class\n * @param props - telemetry props to include on the error for when it's logged\n * @param omitPropsFromLogging - properties by name to omit from telemetry props\n */\n constructor(\n message: string,\n props?: ITelemetryProperties,\n private readonly omitPropsFromLogging: Set<string> = new Set(),\n ) {\n super(message);\n\n // Don't log this list itself, or the private _errorInstanceId\n omitPropsFromLogging.add(\"omitPropsFromLogging\");\n omitPropsFromLogging.add(\"_errorInstanceId\");\n\n if (props) {\n this.addTelemetryProperties(props);\n }\n }\n\n /**\n * Add additional properties to be logged\n */\n public addTelemetryProperties(props: ITelemetryProperties) {\n copyProps(this, props);\n }\n\n /**\n * Get all properties fit to be logged to telemetry for this error\n */\n public getTelemetryProperties(): ITelemetryProperties {\n const taggableProps = getValidTelemetryProps(this, this.omitPropsFromLogging);\n // Include non-enumerable props that are not returned by getValidTelemetryProps\n return {\n ...taggableProps,\n stack: this.stack,\n message: this.message,\n errorInstanceId: this._errorInstanceId,\n };\n }\n}\n\n/** The Error class used when normalizing an external error */\nclass NormalizedExternalError extends LoggingError {\n // errorType \"genericError\" is used as a default value throughout the code.\n // Note that this matches ContainerErrorType/DriverErrorType's genericError\n static readonly normalizedErrorType = \"genericError\";\n\n errorType = NormalizedExternalError.normalizedErrorType;\n\n constructor(\n errorProps: Pick<IFluidErrorBase,\n | \"message\"\n | \"stack\"\n >,\n ) {\n super(errorProps.message);\n\n if (errorProps.stack !== undefined) {\n overwriteStack(this, errorProps.stack);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"errorLogging.js","sourceRoot":"","sources":["../src/errorLogging.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 ILoggingError,\n ITaggedTelemetryPropertyType,\n ITelemetryLogger,\n ITelemetryProperties,\n TelemetryEventPropertyType,\n} from \"@fluidframework/common-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n hasErrorInstanceId,\n IFluidErrorBase,\n isFluidError,\n isValidLegacyError,\n} from \"./fluidErrorBase\";\n\n/** @returns true if value is an object but neither null nor an array */\nconst isRegularObject = (value: any): boolean => {\n return value !== null && !Array.isArray(value) && typeof value === \"object\";\n};\n\n/** Inspect the given error for common \"safe\" props and return them */\nexport function extractLogSafeErrorProperties(error: any, sanitizeStack: boolean) {\n const removeMessageFromStack = (stack: string, errorName?: string) => {\n if (!sanitizeStack) {\n return stack;\n }\n const stackFrames = stack.split(\"\\n\");\n stackFrames.shift(); // Remove \"[ErrorName]: [ErrorMessage]\"\n if (errorName !== undefined) {\n stackFrames.unshift(errorName); // Add \"[ErrorName]\"\n }\n return stackFrames.join(\"\\n\");\n };\n\n const message = (typeof error?.message === \"string\")\n ? error.message as string\n : String(error);\n\n const safeProps: { message: string; errorType?: string; stack?: string; } = {\n message,\n };\n\n if (isRegularObject(error)) {\n const { errorType, stack, name } = error;\n\n if (typeof errorType === \"string\") {\n safeProps.errorType = errorType;\n }\n\n if (typeof stack === \"string\") {\n const errorName = (typeof name === \"string\") ? name : undefined;\n safeProps.stack = removeMessageFromStack(stack, errorName);\n }\n }\n\n return safeProps;\n}\n\n/** type guard for ILoggingError interface */\nexport const isILoggingError = (x: any): x is ILoggingError => typeof x?.getTelemetryProperties === \"function\";\n\n/** Copy props from source onto target, but do not overwrite an existing prop that matches */\nfunction copyProps(target: ITelemetryProperties | LoggingError, source: ITelemetryProperties) {\n for (const key of Object.keys(source)) {\n if (target[key] === undefined) {\n target[key] = source[key];\n }\n }\n}\n\n/** Metadata to annotate an error object when annotating or normalizing it */\nexport interface IFluidErrorAnnotations {\n /** Telemetry props to log with the error */\n props?: ITelemetryProperties;\n}\n\n/** For backwards compatibility with pre-errorInstanceId valid errors */\nfunction patchLegacyError(\n legacyError: Omit<IFluidErrorBase, \"errorInstanceId\">,\n): asserts legacyError is IFluidErrorBase {\n const patchMe: { -readonly [P in \"errorInstanceId\"]?: IFluidErrorBase[P] } = legacyError as any;\n if (patchMe.errorInstanceId === undefined) {\n patchMe.errorInstanceId = uuid();\n }\n}\n\n/**\n * Normalize the given error yielding a valid Fluid Error\n * @returns A valid Fluid Error with any provided annotations applied\n * @param error - The error to normalize\n * @param annotations - Annotations to apply to the normalized error\n */\nexport function normalizeError(\n error: unknown,\n annotations: IFluidErrorAnnotations = {},\n): IFluidErrorBase {\n // Back-compat, while IFluidErrorBase is rolled out\n if (isValidLegacyError(error)) {\n patchLegacyError(error);\n }\n\n if (isFluidError(error)) {\n // We can simply add the telemetry props to the error and return it\n error.addTelemetryProperties(annotations.props ?? {});\n return error;\n }\n\n // We have to construct a new Fluid Error, copying safe properties over\n const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);\n const fluidError: IFluidErrorBase = new NormalizedLoggingError({\n message,\n stack,\n });\n\n // We need to preserve these properties which are used in a non-typesafe way throughout driver code (see #8743)\n // Anywhere they are set should be on a valid Fluid Error that would have been returned above,\n // but we can't prove it with the types, so adding this defensive measure.\n if (typeof error === \"object\" && error !== null) {\n const { canRetry, retryAfterSeconds } = error as any;\n Object.assign(normalizeError, { canRetry, retryAfterSeconds });\n }\n\n if (typeof (error) !== \"object\") {\n // This is only interesting for non-objects\n fluidError.addTelemetryProperties({ typeofError: typeof (error) });\n }\n\n const errorTelemetryProps = LoggingError.typeCheck(error)\n ? error.getTelemetryProperties()\n : { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase\n\n fluidError.addTelemetryProperties({\n ...errorTelemetryProps,\n ...annotations.props,\n });\n\n return fluidError;\n}\n\nlet stackPopulatedOnCreation: boolean | undefined;\n\n/**\n * The purpose of this function is to provide ability to capture stack context quickly.\n * Accessing new Error().stack is slow, and the slowest part is accessing stack property itself.\n * There are scenarios where we generate error with stack, but error is handled in most cases and\n * stack property is not accessed.\n * For such cases it's better to not read stack property right away, but rather delay it until / if it's needed\n * Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.\n * @returns Error object that has stack populated.\n */\nexport function generateErrorWithStack(): Error {\n const err = new Error(\"<<generated stack>>\");\n\n if (stackPopulatedOnCreation === undefined) {\n stackPopulatedOnCreation = (err.stack !== undefined);\n }\n\n if (stackPopulatedOnCreation) {\n return err;\n }\n\n try {\n throw err;\n } catch (e) {\n return e as Error;\n }\n}\n\nexport function generateStack(): string | undefined {\n return generateErrorWithStack().stack;\n}\n\n/**\n * Create a new error using newErrorFn, wrapping and caused by the given unknown error.\n * Copies the inner error's stack, errorInstanceId and telemetry props over to the new error if present\n * @param innerError - An error from untrusted/unknown origins\n * @param newErrorFn - callback that will create a new error given the original error's message\n * @returns A new error object \"wrapping\" the given error\n */\nexport function wrapError<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n): T {\n const {\n message,\n stack,\n } = extractLogSafeErrorProperties(innerError, false /* sanitizeStack */);\n\n const newError = newErrorFn(message);\n\n if (stack !== undefined) {\n overwriteStack(newError, stack);\n }\n\n // Mark external errors with untrustedOrigin flag\n if (isExternalError(innerError)) {\n newError.addTelemetryProperties({ untrustedOrigin: 1 });\n }\n\n // Reuse errorInstanceId\n if (hasErrorInstanceId(innerError)) {\n newError.overwriteErrorInstanceId(innerError.errorInstanceId);\n\n // For \"back-compat\" in the logs\n newError.addTelemetryProperties({ innerErrorInstanceId: innerError.errorInstanceId });\n }\n\n // Lastly, copy over all other telemetry properties. Note these will not overwrite existing properties\n // This will include the untrustedOrigin property if the inner error itself was created from an external error\n if (isILoggingError(innerError)) {\n newError.addTelemetryProperties(innerError.getTelemetryProperties());\n }\n\n return newError;\n}\n\n/** The same as wrapError, but also logs the innerError, including the wrapping error's instance id */\nexport function wrapErrorAndLog<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n logger: ITelemetryLogger,\n) {\n const newError = wrapError(innerError, newErrorFn);\n\n // This will match innerError.errorInstanceId if present (see wrapError)\n const errorInstanceId = newError.errorInstanceId;\n\n // For \"back-compat\" in the logs\n const wrappedByErrorInstanceId = errorInstanceId;\n\n logger.sendTelemetryEvent({\n eventName: \"WrapError\",\n errorInstanceId,\n wrappedByErrorInstanceId,\n }, innerError);\n\n return newError;\n}\n\nfunction overwriteStack(error: IFluidErrorBase | LoggingError, stack: string) {\n // supposedly setting stack on an Error can throw.\n try {\n Object.assign(error, { stack });\n } catch (errorSettingStack) {\n error.addTelemetryProperties({ stack2: stack });\n }\n}\n\n/**\n * True for any error object that is an (optionally normalized) external error\n * False for any error we created and raised within the FF codebase via LoggingError base class,\n * or wrapped in a well-known error type\n */\nexport function isExternalError(e: any): boolean {\n // LoggingErrors are an internal FF error type. However, an external error can be converted\n // into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to\n // determine whether the original error was infact external.\n if (LoggingError.typeCheck(e)) {\n if ((e as NormalizedLoggingError).errorType === NORMALIZED_ERROR_TYPE) {\n return e.getTelemetryProperties().untrustedOrigin === 1;\n }\n return false;\n }\n return !isValidLegacyError(e);\n}\n\n/**\n * Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property\n */\nexport function isTaggedTelemetryPropertyValue(x: any): x is ITaggedTelemetryPropertyType {\n return typeof (x?.tag) === \"string\";\n}\n\n/**\n * Filter serializable telemetry properties\n * @param x - any telemetry prop\n * @returns - as-is if x is primitive. returns stringified if x is an array of primitive.\n * otherwise returns null since this is what we support at the moment.\n */\nfunction filterValidTelemetryProps(x: any, key: string): TelemetryEventPropertyType {\n if (Array.isArray(x) && x.every((val) => isTelemetryEventPropertyValue(val))) {\n return JSON.stringify(x);\n }\n if (isTelemetryEventPropertyValue(x)) {\n return x;\n }\n // We don't support logging arbitrary objects\n console.error(`UnSupported Format of Logging Error Property for key ${key}:`, x);\n return \"REDACTED (arbitrary object)\";\n}\n\n// checking type of x, returns false if x is null\nfunction isTelemetryEventPropertyValue(x: any): x is TelemetryEventPropertyType {\n switch (typeof x) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"undefined\":\n return true;\n default:\n return false;\n }\n}\n/**\n * Walk an object's enumerable properties to find those fit for telemetry.\n */\nfunction getValidTelemetryProps(obj: any, keysToOmit: Set<string>): ITelemetryProperties {\n const props: ITelemetryProperties = {};\n for (const key of Object.keys(obj)) {\n if (keysToOmit.has(key)) {\n continue;\n }\n const val = obj[key];\n\n // ensure only valid props get logged, since props of logging error could be in any shape\n if (isTaggedTelemetryPropertyValue(val)) {\n props[key] = {\n value: filterValidTelemetryProps(val.value, key),\n tag: val.tag,\n };\n } else {\n props[key] = filterValidTelemetryProps(val, key);\n }\n }\n return props;\n}\n\n/**\n * Borrowed from\n * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples}\n * Avoids runtime errors with circular references.\n * Not ideal, as will cut values that are not necessarily circular references.\n * Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)\n*/\nexport const getCircularReplacer = () => {\n const seen = new WeakSet();\n return (key: string, value: any): any => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) {\n return \"<removed/circular>\";\n }\n seen.add(value);\n }\n return value;\n };\n};\n\n/**\n * Base class for \"trusted\" errors we create, whose properties can generally be logged to telemetry safely.\n * All properties set on the object, or passed in (via the constructor or addTelemetryProperties),\n * will be logged in accordance with their tag, if present.\n *\n * PLEASE take care to avoid setting sensitive data on this object without proper tagging!\n */\nexport class LoggingError extends Error implements ILoggingError, Omit<IFluidErrorBase, \"errorType\"> {\n private _errorInstanceId = uuid();\n get errorInstanceId() { return this._errorInstanceId; }\n overwriteErrorInstanceId(id: string) { this._errorInstanceId = id; }\n\n /** Back-compat to appease isFluidError typeguard in old code that may handle this error */\n // @ts-expect-error - This field shouldn't be referenced in the current version, but needs to exist at runtime.\n private readonly fluidErrorCode: \"-\" = \"-\";\n\n /**\n * Create a new LoggingError\n * @param message - Error message to use for Error base class\n * @param props - telemetry props to include on the error for when it's logged\n * @param omitPropsFromLogging - properties by name to omit from telemetry props\n */\n constructor(\n message: string,\n props?: ITelemetryProperties,\n private readonly omitPropsFromLogging: Set<string> = new Set(),\n ) {\n super(message);\n\n // Don't log this list itself, or the private _errorInstanceId\n omitPropsFromLogging.add(\"omitPropsFromLogging\");\n omitPropsFromLogging.add(\"_errorInstanceId\");\n\n if (props) {\n this.addTelemetryProperties(props);\n }\n }\n\n /**\n * Determines if a given object is an instance of a LoggingError\n * @param object - any object\n * @returns - true if the object is an instance of a LoggingError, false if not.\n */\n public static typeCheck(object: unknown): object is LoggingError {\n if (typeof object === \"object\" && object !== null) {\n return typeof (object as LoggingError).addTelemetryProperties === \"function\"\n && typeof (object as LoggingError).getTelemetryProperties === \"function\"\n && typeof (object as LoggingError).errorInstanceId === \"string\";\n }\n return false;\n }\n\n /**\n * Add additional properties to be logged\n */\n public addTelemetryProperties(props: ITelemetryProperties) {\n copyProps(this, props);\n }\n\n /**\n * Get all properties fit to be logged to telemetry for this error\n */\n public getTelemetryProperties(): ITelemetryProperties {\n const taggableProps = getValidTelemetryProps(this, this.omitPropsFromLogging);\n // Include non-enumerable props that are not returned by getValidTelemetryProps\n return {\n ...taggableProps,\n stack: this.stack,\n message: this.message,\n errorInstanceId: this._errorInstanceId,\n };\n }\n}\n\n/** The Error class used when normalizing an external error */\nexport const NORMALIZED_ERROR_TYPE = \"genericError\";\nclass NormalizedLoggingError extends LoggingError {\n // errorType \"genericError\" is used as a default value throughout the code.\n // Note that this matches ContainerErrorType/DriverErrorType's genericError\n errorType = NORMALIZED_ERROR_TYPE;\n\n constructor(\n errorProps: Pick<IFluidErrorBase,\n | \"message\"\n | \"stack\"\n >,\n ) {\n super(errorProps.message);\n\n if (errorProps.stack !== undefined) {\n overwriteStack(this, errorProps.stack);\n }\n }\n}\n"]}
|
package/dist/mockLogger.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export declare class MockLogger extends TelemetryLogger implements ITelemetryLog
|
|
|
34
34
|
matchAnyEvent(expectedEvents: Omit<ITelemetryBaseEvent, "category">[]): boolean;
|
|
35
35
|
/** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */
|
|
36
36
|
assertMatchAny(expectedEvents: Omit<ITelemetryBaseEvent, "category">[], message?: string): void;
|
|
37
|
+
/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
|
|
38
|
+
assertMatchNone(disallowedEvents: Omit<ITelemetryBaseEvent, "category">[], message?: string): void;
|
|
37
39
|
private getMatchedEventsCount;
|
|
38
40
|
/**
|
|
39
41
|
* Ensure the expected event is a strict subset of the actual event
|
package/dist/mockLogger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockLogger.d.ts","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,qBAAa,UAAW,SAAQ,eAAgB,YAAW,gBAAgB;IACvE,MAAM,EAAE,mBAAmB,EAAE,CAAM;;IAInC,KAAK;IAIL,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAItC;;;;;;OAMG;IACH,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAO7E,qFAAqF;IACrF,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYrF;;;;;;;OAOG;IACH,aAAa,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAK/E,uFAAuF;IACvF,cAAc,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYxF,OAAO,CAAC,qBAAqB;IAkB7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;CAI7B"}
|
|
1
|
+
{"version":3,"file":"mockLogger.d.ts","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,qBAAa,UAAW,SAAQ,eAAgB,YAAW,gBAAgB;IACvE,MAAM,EAAE,mBAAmB,EAAE,CAAM;;IAInC,KAAK;IAIL,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAItC;;;;;;OAMG;IACH,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAO7E,qFAAqF;IACrF,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYrF;;;;;;;OAOG;IACH,aAAa,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAK/E,uFAAuF;IACvF,cAAc,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYxF,6GAA6G;IAC7G,eAAe,CAAC,gBAAgB,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAY3F,OAAO,CAAC,qBAAqB;IAkB7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;CAI7B"}
|
package/dist/mockLogger.js
CHANGED
|
@@ -66,6 +66,18 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
66
66
|
expected:
|
|
67
67
|
${JSON.stringify(expectedEvents)}
|
|
68
68
|
|
|
69
|
+
actual:
|
|
70
|
+
${JSON.stringify(actualEvents)}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
|
|
74
|
+
assertMatchNone(disallowedEvents, message) {
|
|
75
|
+
const actualEvents = this.events;
|
|
76
|
+
if (this.matchAnyEvent(disallowedEvents)) {
|
|
77
|
+
throw new Error(`${message}
|
|
78
|
+
disallowed events:
|
|
79
|
+
${JSON.stringify(disallowedEvents)}
|
|
80
|
+
|
|
69
81
|
actual:
|
|
70
82
|
${JSON.stringify(actualEvents)}`);
|
|
71
83
|
}
|
package/dist/mockLogger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,qCAA2C;AAE3C;;;GAGG;AACH,MAAa,UAAW,SAAQ,wBAAe;IAG3C;QAAgB,KAAK,EAAE,CAAC;QAFxB,WAAM,GAA0B,EAAE,CAAC;IAEV,CAAC;IAE1B,KAAK;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,KAA0B;QAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,cAAuD;QAC/D,MAAM,yBAAyB,GAAG,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAC7E,2DAA2D;QAC3D,MAAM,2BAA2B,GAAG,cAAc,CAAC,MAAM,GAAG,yBAAyB,CAAC;QACtF,OAAO,2BAA2B,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED,qFAAqF;IACrF,WAAW,CAAC,cAAuD,EAAE,OAAgB;QACjF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO;;EAEpC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;EAG9B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;SACzB;IACL,CAAC;IAED;;;;;;;OAOG;IACH,aAAa,CAAC,cAAuD;QACjE,MAAM,yBAAyB,GAAG,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAC7E,OAAO,yBAAyB,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,uFAAuF;IACvF,cAAc,CAAC,cAAuD,EAAE,OAAgB;QACpF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE;YACrC,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO;;EAEpC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;EAG9B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;SACrB;IACT,CAAC;IAEO,qBAAqB,CAAC,cAAuD;QACjF,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,cAAc,GAAG,cAAc,CAAC,MAAM;gBACtC,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC,EAC/D;gBACE,8CAA8C;gBAC9C,EAAE,cAAc,CAAC;aACpB;QACL,CAAC,CAAC,CAAC;QAEH,oFAAoF;QACpF,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QAEjB,sCAAsC;QACtC,OAAO,cAAc,CAAC;IAC1B,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,WAAW,CAAC,MAA2B,EAAE,QAA+C;QACnG,MAAM,MAAM,mCAAQ,MAAM,GAAK,QAAQ,CAAE,CAAC;QAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;CACJ;
|
|
1
|
+
{"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.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 { ITelemetryLogger, ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport { TelemetryLogger } from \"./logger\";\n\n/**\n * The MockLogger records events sent to it, and then can walk back over those events\n * searching for a set of expected events to match against the logged events.\n */\nexport class MockLogger extends TelemetryLogger implements ITelemetryLogger {\n events: ITelemetryBaseEvent[] = [];\n\n constructor() { super(); }\n\n clear() {\n this.events = [];\n }\n\n send(event: ITelemetryBaseEvent): void {\n this.events.push(event);\n }\n\n /**\n * Search events logged since the last time matchEvents was called, looking for the given expected\n * events in order.\n * @param expectedEvents - events in order that are expected to appear in the recorded log.\n * These event objects may be subsets of the logged events.\n * Note: category is ommitted from the type because it's usually uninteresting and tedious to type.\n */\n matchEvents(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): boolean {\n const matchedExpectedEventCount = this.getMatchedEventsCount(expectedEvents);\n // How many expected events were left over? Hopefully none.\n const unmatchedExpectedEventCount = expectedEvents.length - matchedExpectedEventCount;\n return unmatchedExpectedEventCount === 0;\n }\n\n /** Asserts that matchEvents is true, and prints the actual/expected output if not */\n assertMatch(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (!this.matchEvents(expectedEvents)) {\n throw new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n /**\n * Search events logged since the last time matchEvents was called, looking for any of the given\n * expected events.\n * @param expectedEvents - events that are expected to appear in the recorded log.\n * These event objects may be subsets of the logged events.\n * Note: category is ommitted from the type because it's usually uninteresting and tedious to type.\n * @returns if any of the expected events is found.\n */\n matchAnyEvent(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): boolean {\n const matchedExpectedEventCount = this.getMatchedEventsCount(expectedEvents);\n return matchedExpectedEventCount > 0;\n }\n\n /** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */\n assertMatchAny(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (!this.matchAnyEvent(expectedEvents)) {\n throw new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n /** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */\n assertMatchNone(disallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (this.matchAnyEvent(disallowedEvents)) {\n throw new Error(`${message}\ndisallowed events:\n${JSON.stringify(disallowedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n private getMatchedEventsCount(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): number {\n let iExpectedEvent = 0;\n this.events.forEach((event) => {\n if (iExpectedEvent < expectedEvents.length &&\n MockLogger.eventsMatch(event, expectedEvents[iExpectedEvent])\n ) {\n // We found the next expected event; increment\n ++iExpectedEvent;\n }\n });\n\n // Remove the events so far; next call will just compare subsequent events from here\n this.events = [];\n\n // Return the count of matched events.\n return iExpectedEvent;\n }\n\n /**\n * Ensure the expected event is a strict subset of the actual event\n */\n private static eventsMatch(actual: ITelemetryBaseEvent, expected: Omit<ITelemetryBaseEvent, \"category\">): boolean {\n const masked = { ...actual, ...expected };\n return JSON.stringify(masked) === JSON.stringify(actual);\n }\n}\n"]}
|
package/dist/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/telemetry-utils";
|
|
8
|
-
export declare const pkgVersion = "2.0.0-internal.1.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-internal.1.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/telemetry-utils";
|
|
11
|
-
exports.pkgVersion = "2.0.0-internal.1.
|
|
11
|
+
exports.pkgVersion = "2.0.0-internal.1.2.0";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,iCAAiC,CAAC;AAC5C,QAAA,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/telemetry-utils\";\nexport const pkgVersion = \"2.0.0-internal.1.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,iCAAiC,CAAC;AAC5C,QAAA,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/telemetry-utils\";\nexport const pkgVersion = \"2.0.0-internal.1.2.0\";\n"]}
|
package/lib/errorLogging.d.ts
CHANGED
|
@@ -47,7 +47,8 @@ export declare function wrapError<T extends LoggingError>(innerError: unknown, n
|
|
|
47
47
|
export declare function wrapErrorAndLog<T extends LoggingError>(innerError: unknown, newErrorFn: (message: string) => T, logger: ITelemetryLogger): T;
|
|
48
48
|
/**
|
|
49
49
|
* True for any error object that is an (optionally normalized) external error
|
|
50
|
-
* False for any error we created and raised within the FF codebase
|
|
50
|
+
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
51
|
+
* or wrapped in a well-known error type
|
|
51
52
|
*/
|
|
52
53
|
export declare function isExternalError(e: any): boolean;
|
|
53
54
|
/**
|
|
@@ -83,6 +84,12 @@ export declare class LoggingError extends Error implements ILoggingError, Omit<I
|
|
|
83
84
|
* @param omitPropsFromLogging - properties by name to omit from telemetry props
|
|
84
85
|
*/
|
|
85
86
|
constructor(message: string, props?: ITelemetryProperties, omitPropsFromLogging?: Set<string>);
|
|
87
|
+
/**
|
|
88
|
+
* Determines if a given object is an instance of a LoggingError
|
|
89
|
+
* @param object - any object
|
|
90
|
+
* @returns - true if the object is an instance of a LoggingError, false if not.
|
|
91
|
+
*/
|
|
92
|
+
static typeCheck(object: unknown): object is LoggingError;
|
|
86
93
|
/**
|
|
87
94
|
* Add additional properties to be logged
|
|
88
95
|
*/
|
|
@@ -92,4 +99,6 @@ export declare class LoggingError extends Error implements ILoggingError, Omit<I
|
|
|
92
99
|
*/
|
|
93
100
|
getTelemetryProperties(): ITelemetryProperties;
|
|
94
101
|
}
|
|
102
|
+
/** The Error class used when normalizing an external error */
|
|
103
|
+
export declare const NORMALIZED_ERROR_TYPE = "genericError";
|
|
95
104
|
//# 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,EACH,aAAa,EACb,4BAA4B,EAC5B,gBAAgB,EAChB,oBAAoB,EAEvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAEH,eAAe,EAGlB,MAAM,kBAAkB,CAAC;AAO1B,sEAAsE;AACtE,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO;aAiBhD,MAAM;;;EAkBrC;AAED,6CAA6C;AAC7C,eAAO,MAAM,eAAe,MAAO,GAAG,uBAAwE,CAAC;AAW/G,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAYD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,WAAW,GAAE,sBAA2B,GACzC,eAAe,
|
|
1
|
+
{"version":3,"file":"errorLogging.d.ts","sourceRoot":"","sources":["../src/errorLogging.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,aAAa,EACb,4BAA4B,EAC5B,gBAAgB,EAChB,oBAAoB,EAEvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAEH,eAAe,EAGlB,MAAM,kBAAkB,CAAC;AAO1B,sEAAsE;AACtE,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO;aAiBhD,MAAM;;;EAkBrC;AAED,6CAA6C;AAC7C,eAAO,MAAM,eAAe,MAAO,GAAG,uBAAwE,CAAC;AAW/G,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAYD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,WAAW,GAAE,sBAA2B,GACzC,eAAe,CA0CjB;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,EAC5C,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,GACnC,CAAC,CAgCH;AAED,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EAClD,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,EAClC,MAAM,EAAE,gBAAgB,KAiB3B;AAWD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAW/C;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,4BAA4B,CAExF;AAwDD;;;;;;EAME;AACF,eAAO,MAAM,mBAAmB,cAEf,MAAM,SAAS,GAAG,KAAG,GASrC,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,KAAM,YAAW,aAAa,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC;IAkB5F,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAjBzC,OAAO,CAAC,gBAAgB,CAAU;IAClC,IAAI,eAAe,WAAoC;IACvD,wBAAwB,CAAC,EAAE,EAAE,MAAM;IAEnC,2FAA2F;IAE3F,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAY;IAE3C;;;;;OAKG;gBAEC,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,oBAAoB,EACX,oBAAoB,GAAE,GAAG,CAAC,MAAM,CAAa;IAalE;;;;MAIE;WACY,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY;IAShE;;OAEG;IACI,sBAAsB,CAAC,KAAK,EAAE,oBAAoB;IAIzD;;OAEG;IACI,sBAAsB,IAAI,oBAAoB;CAUxD;AAED,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,iBAAiB,CAAC"}
|
package/lib/errorLogging.js
CHANGED
|
@@ -75,7 +75,7 @@ export function normalizeError(error, annotations = {}) {
|
|
|
75
75
|
}
|
|
76
76
|
// We have to construct a new Fluid Error, copying safe properties over
|
|
77
77
|
const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);
|
|
78
|
-
const fluidError = new
|
|
78
|
+
const fluidError = new NormalizedLoggingError({
|
|
79
79
|
message,
|
|
80
80
|
stack,
|
|
81
81
|
});
|
|
@@ -90,8 +90,10 @@ export function normalizeError(error, annotations = {}) {
|
|
|
90
90
|
// This is only interesting for non-objects
|
|
91
91
|
fluidError.addTelemetryProperties({ typeofError: typeof (error) });
|
|
92
92
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
93
|
+
const errorTelemetryProps = LoggingError.typeCheck(error)
|
|
94
|
+
? error.getTelemetryProperties()
|
|
95
|
+
: { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase
|
|
96
|
+
fluidError.addTelemetryProperties(Object.assign(Object.assign({}, errorTelemetryProps), annotations.props));
|
|
95
97
|
return fluidError;
|
|
96
98
|
}
|
|
97
99
|
let stackPopulatedOnCreation;
|
|
@@ -177,12 +179,20 @@ function overwriteStack(error, stack) {
|
|
|
177
179
|
}
|
|
178
180
|
/**
|
|
179
181
|
* True for any error object that is an (optionally normalized) external error
|
|
180
|
-
* False for any error we created and raised within the FF codebase
|
|
182
|
+
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
183
|
+
* or wrapped in a well-known error type
|
|
181
184
|
*/
|
|
182
185
|
export function isExternalError(e) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
// LoggingErrors are an internal FF error type. However, an external error can be converted
|
|
187
|
+
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
|
|
188
|
+
// determine whether the original error was infact external.
|
|
189
|
+
if (LoggingError.typeCheck(e)) {
|
|
190
|
+
if (e.errorType === NORMALIZED_ERROR_TYPE) {
|
|
191
|
+
return e.getTelemetryProperties().untrustedOrigin === 1;
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
return !isValidLegacyError(e);
|
|
186
196
|
}
|
|
187
197
|
/**
|
|
188
198
|
* Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property
|
|
@@ -291,6 +301,19 @@ export class LoggingError extends Error {
|
|
|
291
301
|
}
|
|
292
302
|
get errorInstanceId() { return this._errorInstanceId; }
|
|
293
303
|
overwriteErrorInstanceId(id) { this._errorInstanceId = id; }
|
|
304
|
+
/**
|
|
305
|
+
* Determines if a given object is an instance of a LoggingError
|
|
306
|
+
* @param object - any object
|
|
307
|
+
* @returns - true if the object is an instance of a LoggingError, false if not.
|
|
308
|
+
*/
|
|
309
|
+
static typeCheck(object) {
|
|
310
|
+
if (typeof object === "object" && object !== null) {
|
|
311
|
+
return typeof object.addTelemetryProperties === "function"
|
|
312
|
+
&& typeof object.getTelemetryProperties === "function"
|
|
313
|
+
&& typeof object.errorInstanceId === "string";
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
294
317
|
/**
|
|
295
318
|
* Add additional properties to be logged
|
|
296
319
|
*/
|
|
@@ -307,16 +330,16 @@ export class LoggingError extends Error {
|
|
|
307
330
|
}
|
|
308
331
|
}
|
|
309
332
|
/** The Error class used when normalizing an external error */
|
|
310
|
-
|
|
333
|
+
export const NORMALIZED_ERROR_TYPE = "genericError";
|
|
334
|
+
class NormalizedLoggingError extends LoggingError {
|
|
311
335
|
constructor(errorProps) {
|
|
312
336
|
super(errorProps.message);
|
|
313
|
-
|
|
337
|
+
// errorType "genericError" is used as a default value throughout the code.
|
|
338
|
+
// Note that this matches ContainerErrorType/DriverErrorType's genericError
|
|
339
|
+
this.errorType = NORMALIZED_ERROR_TYPE;
|
|
314
340
|
if (errorProps.stack !== undefined) {
|
|
315
341
|
overwriteStack(this, errorProps.stack);
|
|
316
342
|
}
|
|
317
343
|
}
|
|
318
344
|
}
|
|
319
|
-
// errorType "genericError" is used as a default value throughout the code.
|
|
320
|
-
// Note that this matches ContainerErrorType/DriverErrorType's genericError
|
|
321
|
-
NormalizedExternalError.normalizedErrorType = "genericError";
|
|
322
345
|
//# sourceMappingURL=errorLogging.js.map
|
package/lib/errorLogging.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errorLogging.js","sourceRoot":"","sources":["../src/errorLogging.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 ILoggingError,\n ITaggedTelemetryPropertyType,\n ITelemetryLogger,\n ITelemetryProperties,\n TelemetryEventPropertyType,\n} from \"@fluidframework/common-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n hasErrorInstanceId,\n IFluidErrorBase,\n isFluidError,\n isValidLegacyError,\n} from \"./fluidErrorBase\";\n\n/** @returns true if value is an object but neither null nor an array */\nconst isRegularObject = (value: any): boolean => {\n return value !== null && !Array.isArray(value) && typeof value === \"object\";\n};\n\n/** Inspect the given error for common \"safe\" props and return them */\nexport function extractLogSafeErrorProperties(error: any, sanitizeStack: boolean) {\n const removeMessageFromStack = (stack: string, errorName?: string) => {\n if (!sanitizeStack) {\n return stack;\n }\n const stackFrames = stack.split(\"\\n\");\n stackFrames.shift(); // Remove \"[ErrorName]: [ErrorMessage]\"\n if (errorName !== undefined) {\n stackFrames.unshift(errorName); // Add \"[ErrorName]\"\n }\n return stackFrames.join(\"\\n\");\n };\n\n const message = (typeof error?.message === \"string\")\n ? error.message as string\n : String(error);\n\n const safeProps: { message: string; errorType?: string; stack?: string; } = {\n message,\n };\n\n if (isRegularObject(error)) {\n const { errorType, stack, name } = error;\n\n if (typeof errorType === \"string\") {\n safeProps.errorType = errorType;\n }\n\n if (typeof stack === \"string\") {\n const errorName = (typeof name === \"string\") ? name : undefined;\n safeProps.stack = removeMessageFromStack(stack, errorName);\n }\n }\n\n return safeProps;\n}\n\n/** type guard for ILoggingError interface */\nexport const isILoggingError = (x: any): x is ILoggingError => typeof x?.getTelemetryProperties === \"function\";\n\n/** Copy props from source onto target, but do not overwrite an existing prop that matches */\nfunction copyProps(target: ITelemetryProperties | LoggingError, source: ITelemetryProperties) {\n for (const key of Object.keys(source)) {\n if (target[key] === undefined) {\n target[key] = source[key];\n }\n }\n}\n\n/** Metadata to annotate an error object when annotating or normalizing it */\nexport interface IFluidErrorAnnotations {\n /** Telemetry props to log with the error */\n props?: ITelemetryProperties;\n}\n\n/** For backwards compatibility with pre-errorInstanceId valid errors */\nfunction patchLegacyError(\n legacyError: Omit<IFluidErrorBase, \"errorInstanceId\">,\n): asserts legacyError is IFluidErrorBase {\n const patchMe: { -readonly [P in \"errorInstanceId\"]?: IFluidErrorBase[P] } = legacyError as any;\n if (patchMe.errorInstanceId === undefined) {\n patchMe.errorInstanceId = uuid();\n }\n}\n\n/**\n * Normalize the given error yielding a valid Fluid Error\n * @returns A valid Fluid Error with any provided annotations applied\n * @param error - The error to normalize\n * @param annotations - Annotations to apply to the normalized error\n */\nexport function normalizeError(\n error: unknown,\n annotations: IFluidErrorAnnotations = {},\n): IFluidErrorBase {\n // Back-compat, while IFluidErrorBase is rolled out\n if (isValidLegacyError(error)) {\n patchLegacyError(error);\n }\n\n if (isFluidError(error)) {\n // We can simply add the telemetry props to the error and return it\n error.addTelemetryProperties(annotations.props ?? {});\n return error;\n }\n\n // We have to construct a new Fluid Error, copying safe properties over\n const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);\n const fluidError: IFluidErrorBase = new NormalizedExternalError({\n message,\n stack,\n });\n\n // We need to preserve these properties which are used in a non-typesafe way throughout driver code (see #8743)\n // Anywhere they are set should be on a valid Fluid Error that would have been returned above,\n // but we can't prove it with the types, so adding this defensive measure.\n if (typeof error === \"object\" && error !== null) {\n const { canRetry, retryAfterSeconds } = error as any;\n Object.assign(normalizeError, { canRetry, retryAfterSeconds });\n }\n\n if (typeof (error) !== \"object\") {\n // This is only interesting for non-objects\n fluidError.addTelemetryProperties({ typeofError: typeof (error) });\n }\n\n const originalErrorTelemetryProps = isILoggingError(error) ? error.getTelemetryProperties() : {};\n fluidError.addTelemetryProperties({\n ...originalErrorTelemetryProps,\n ...annotations.props,\n untrustedOrigin: 1, // This will let us filter to errors not originated by our own code\n });\n\n return fluidError;\n}\n\nlet stackPopulatedOnCreation: boolean | undefined;\n\n/**\n * The purpose of this function is to provide ability to capture stack context quickly.\n * Accessing new Error().stack is slow, and the slowest part is accessing stack property itself.\n * There are scenarios where we generate error with stack, but error is handled in most cases and\n * stack property is not accessed.\n * For such cases it's better to not read stack property right away, but rather delay it until / if it's needed\n * Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.\n * @returns Error object that has stack populated.\n */\n export function generateErrorWithStack(): Error {\n const err = new Error(\"<<generated stack>>\");\n\n if (stackPopulatedOnCreation === undefined) {\n stackPopulatedOnCreation = (err.stack !== undefined);\n }\n\n if (stackPopulatedOnCreation) {\n return err;\n }\n\n try {\n throw err;\n } catch (e) {\n return e as Error;\n }\n}\n\nexport function generateStack(): string | undefined {\n return generateErrorWithStack().stack;\n}\n\n/**\n * Create a new error using newErrorFn, wrapping and caused by the given unknown error.\n * Copies the inner error's stack, errorInstanceId and telemetry props over to the new error if present\n * @param innerError - An error from untrusted/unknown origins\n * @param newErrorFn - callback that will create a new error given the original error's message\n * @returns A new error object \"wrapping\" the given error\n */\nexport function wrapError<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n): T {\n const {\n message,\n stack,\n } = extractLogSafeErrorProperties(innerError, false /* sanitizeStack */);\n\n const newError = newErrorFn(message);\n\n if (stack !== undefined) {\n overwriteStack(newError, stack);\n }\n\n // Mark external errors with untrustedOrigin flag\n if (isExternalError(innerError)) {\n newError.addTelemetryProperties({ untrustedOrigin: 1 });\n }\n\n // Reuse errorInstanceId\n if (hasErrorInstanceId(innerError)) {\n newError.overwriteErrorInstanceId(innerError.errorInstanceId);\n\n // For \"back-compat\" in the logs\n newError.addTelemetryProperties({ innerErrorInstanceId: innerError.errorInstanceId });\n }\n\n // Lastly, copy over all other telemetry properties. Note these will not overwrite existing properties\n // This will include the untrustedOrigin property if the inner error itself was created from an external error\n if (isILoggingError(innerError)) {\n newError.addTelemetryProperties(innerError.getTelemetryProperties());\n }\n\n return newError;\n}\n\n/** The same as wrapError, but also logs the innerError, including the wrapping error's instance id */\nexport function wrapErrorAndLog<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n logger: ITelemetryLogger,\n) {\n const newError = wrapError(innerError, newErrorFn);\n\n // This will match innerError.errorInstanceId if present (see wrapError)\n const errorInstanceId = newError.errorInstanceId;\n\n // For \"back-compat\" in the logs\n const wrappedByErrorInstanceId = errorInstanceId;\n\n logger.sendTelemetryEvent({\n eventName: \"WrapError\",\n errorInstanceId,\n wrappedByErrorInstanceId,\n }, innerError);\n\n return newError;\n}\n\nfunction overwriteStack(error: IFluidErrorBase | LoggingError, stack: string) {\n // supposedly setting stack on an Error can throw.\n try {\n Object.assign(error, { stack });\n } catch (errorSettingStack) {\n error.addTelemetryProperties({ stack2: stack });\n }\n}\n\n/**\n * True for any error object that is an (optionally normalized) external error\n * False for any error we created and raised within the FF codebase, or wrapped in a well-known error type\n */\nexport function isExternalError(e: any): boolean {\n return !isValidLegacyError(e) ||\n (e.getTelemetryProperties().untrustedOrigin === 1 &&\n e.errorType === NormalizedExternalError.normalizedErrorType);\n}\n\n/**\n * Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property\n */\nexport function isTaggedTelemetryPropertyValue(x: any): x is ITaggedTelemetryPropertyType {\n return typeof (x?.tag) === \"string\";\n}\n\n/**\n * Filter serializable telemetry properties\n * @param x - any telemetry prop\n * @returns - as-is if x is primitive. returns stringified if x is an array of primitive.\n * otherwise returns null since this is what we support at the moment.\n */\nfunction filterValidTelemetryProps(x: any, key: string): TelemetryEventPropertyType {\n if (Array.isArray(x) && x.every((val) => isTelemetryEventPropertyValue(val))) {\n return JSON.stringify(x);\n }\n if (isTelemetryEventPropertyValue(x)) {\n return x;\n }\n // We don't support logging arbitrary objects\n console.error(`UnSupported Format of Logging Error Property for key ${key}:`, x);\n return \"REDACTED (arbitrary object)\";\n}\n\n// checking type of x, returns false if x is null\nfunction isTelemetryEventPropertyValue(x: any): x is TelemetryEventPropertyType {\n switch (typeof x) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"undefined\":\n return true;\n default:\n return false;\n }\n}\n/**\n * Walk an object's enumerable properties to find those fit for telemetry.\n */\nfunction getValidTelemetryProps(obj: any, keysToOmit: Set<string>): ITelemetryProperties {\n const props: ITelemetryProperties = {};\n for (const key of Object.keys(obj)) {\n if (keysToOmit.has(key)) {\n continue;\n }\n const val = obj[key];\n\n // ensure only valid props get logged, since props of logging error could be in any shape\n if (isTaggedTelemetryPropertyValue(val)) {\n props[key] = {\n value: filterValidTelemetryProps(val.value, key),\n tag: val.tag,\n };\n } else {\n props[key] = filterValidTelemetryProps(val, key);\n }\n }\n return props;\n}\n\n/**\n * Borrowed from\n * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples}\n * Avoids runtime errors with circular references.\n * Not ideal, as will cut values that are not necessarily circular references.\n * Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)\n*/\nexport const getCircularReplacer = () => {\n const seen = new WeakSet();\n return (key: string, value: any): any => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) {\n return \"<removed/circular>\";\n }\n seen.add(value);\n }\n return value;\n };\n};\n\n/**\n * Base class for \"trusted\" errors we create, whose properties can generally be logged to telemetry safely.\n * All properties set on the object, or passed in (via the constructor or addTelemetryProperties),\n * will be logged in accordance with their tag, if present.\n *\n * PLEASE take care to avoid setting sensitive data on this object without proper tagging!\n */\nexport class LoggingError extends Error implements ILoggingError, Omit<IFluidErrorBase, \"errorType\"> {\n private _errorInstanceId = uuid();\n get errorInstanceId() { return this._errorInstanceId; }\n overwriteErrorInstanceId(id: string) { this._errorInstanceId = id; }\n\n /** Back-compat to appease isFluidError typeguard in old code that may handle this error */\n // @ts-expect-error - This field shouldn't be referenced in the current version, but needs to exist at runtime.\n private readonly fluidErrorCode: \"-\" = \"-\";\n\n /**\n * Create a new LoggingError\n * @param message - Error message to use for Error base class\n * @param props - telemetry props to include on the error for when it's logged\n * @param omitPropsFromLogging - properties by name to omit from telemetry props\n */\n constructor(\n message: string,\n props?: ITelemetryProperties,\n private readonly omitPropsFromLogging: Set<string> = new Set(),\n ) {\n super(message);\n\n // Don't log this list itself, or the private _errorInstanceId\n omitPropsFromLogging.add(\"omitPropsFromLogging\");\n omitPropsFromLogging.add(\"_errorInstanceId\");\n\n if (props) {\n this.addTelemetryProperties(props);\n }\n }\n\n /**\n * Add additional properties to be logged\n */\n public addTelemetryProperties(props: ITelemetryProperties) {\n copyProps(this, props);\n }\n\n /**\n * Get all properties fit to be logged to telemetry for this error\n */\n public getTelemetryProperties(): ITelemetryProperties {\n const taggableProps = getValidTelemetryProps(this, this.omitPropsFromLogging);\n // Include non-enumerable props that are not returned by getValidTelemetryProps\n return {\n ...taggableProps,\n stack: this.stack,\n message: this.message,\n errorInstanceId: this._errorInstanceId,\n };\n }\n}\n\n/** The Error class used when normalizing an external error */\nclass NormalizedExternalError extends LoggingError {\n // errorType \"genericError\" is used as a default value throughout the code.\n // Note that this matches ContainerErrorType/DriverErrorType's genericError\n static readonly normalizedErrorType = \"genericError\";\n\n errorType = NormalizedExternalError.normalizedErrorType;\n\n constructor(\n errorProps: Pick<IFluidErrorBase,\n | \"message\"\n | \"stack\"\n >,\n ) {\n super(errorProps.message);\n\n if (errorProps.stack !== undefined) {\n overwriteStack(this, errorProps.stack);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"errorLogging.js","sourceRoot":"","sources":["../src/errorLogging.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 ILoggingError,\n ITaggedTelemetryPropertyType,\n ITelemetryLogger,\n ITelemetryProperties,\n TelemetryEventPropertyType,\n} from \"@fluidframework/common-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n hasErrorInstanceId,\n IFluidErrorBase,\n isFluidError,\n isValidLegacyError,\n} from \"./fluidErrorBase\";\n\n/** @returns true if value is an object but neither null nor an array */\nconst isRegularObject = (value: any): boolean => {\n return value !== null && !Array.isArray(value) && typeof value === \"object\";\n};\n\n/** Inspect the given error for common \"safe\" props and return them */\nexport function extractLogSafeErrorProperties(error: any, sanitizeStack: boolean) {\n const removeMessageFromStack = (stack: string, errorName?: string) => {\n if (!sanitizeStack) {\n return stack;\n }\n const stackFrames = stack.split(\"\\n\");\n stackFrames.shift(); // Remove \"[ErrorName]: [ErrorMessage]\"\n if (errorName !== undefined) {\n stackFrames.unshift(errorName); // Add \"[ErrorName]\"\n }\n return stackFrames.join(\"\\n\");\n };\n\n const message = (typeof error?.message === \"string\")\n ? error.message as string\n : String(error);\n\n const safeProps: { message: string; errorType?: string; stack?: string; } = {\n message,\n };\n\n if (isRegularObject(error)) {\n const { errorType, stack, name } = error;\n\n if (typeof errorType === \"string\") {\n safeProps.errorType = errorType;\n }\n\n if (typeof stack === \"string\") {\n const errorName = (typeof name === \"string\") ? name : undefined;\n safeProps.stack = removeMessageFromStack(stack, errorName);\n }\n }\n\n return safeProps;\n}\n\n/** type guard for ILoggingError interface */\nexport const isILoggingError = (x: any): x is ILoggingError => typeof x?.getTelemetryProperties === \"function\";\n\n/** Copy props from source onto target, but do not overwrite an existing prop that matches */\nfunction copyProps(target: ITelemetryProperties | LoggingError, source: ITelemetryProperties) {\n for (const key of Object.keys(source)) {\n if (target[key] === undefined) {\n target[key] = source[key];\n }\n }\n}\n\n/** Metadata to annotate an error object when annotating or normalizing it */\nexport interface IFluidErrorAnnotations {\n /** Telemetry props to log with the error */\n props?: ITelemetryProperties;\n}\n\n/** For backwards compatibility with pre-errorInstanceId valid errors */\nfunction patchLegacyError(\n legacyError: Omit<IFluidErrorBase, \"errorInstanceId\">,\n): asserts legacyError is IFluidErrorBase {\n const patchMe: { -readonly [P in \"errorInstanceId\"]?: IFluidErrorBase[P] } = legacyError as any;\n if (patchMe.errorInstanceId === undefined) {\n patchMe.errorInstanceId = uuid();\n }\n}\n\n/**\n * Normalize the given error yielding a valid Fluid Error\n * @returns A valid Fluid Error with any provided annotations applied\n * @param error - The error to normalize\n * @param annotations - Annotations to apply to the normalized error\n */\nexport function normalizeError(\n error: unknown,\n annotations: IFluidErrorAnnotations = {},\n): IFluidErrorBase {\n // Back-compat, while IFluidErrorBase is rolled out\n if (isValidLegacyError(error)) {\n patchLegacyError(error);\n }\n\n if (isFluidError(error)) {\n // We can simply add the telemetry props to the error and return it\n error.addTelemetryProperties(annotations.props ?? {});\n return error;\n }\n\n // We have to construct a new Fluid Error, copying safe properties over\n const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);\n const fluidError: IFluidErrorBase = new NormalizedLoggingError({\n message,\n stack,\n });\n\n // We need to preserve these properties which are used in a non-typesafe way throughout driver code (see #8743)\n // Anywhere they are set should be on a valid Fluid Error that would have been returned above,\n // but we can't prove it with the types, so adding this defensive measure.\n if (typeof error === \"object\" && error !== null) {\n const { canRetry, retryAfterSeconds } = error as any;\n Object.assign(normalizeError, { canRetry, retryAfterSeconds });\n }\n\n if (typeof (error) !== \"object\") {\n // This is only interesting for non-objects\n fluidError.addTelemetryProperties({ typeofError: typeof (error) });\n }\n\n const errorTelemetryProps = LoggingError.typeCheck(error)\n ? error.getTelemetryProperties()\n : { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase\n\n fluidError.addTelemetryProperties({\n ...errorTelemetryProps,\n ...annotations.props,\n });\n\n return fluidError;\n}\n\nlet stackPopulatedOnCreation: boolean | undefined;\n\n/**\n * The purpose of this function is to provide ability to capture stack context quickly.\n * Accessing new Error().stack is slow, and the slowest part is accessing stack property itself.\n * There are scenarios where we generate error with stack, but error is handled in most cases and\n * stack property is not accessed.\n * For such cases it's better to not read stack property right away, but rather delay it until / if it's needed\n * Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.\n * @returns Error object that has stack populated.\n */\nexport function generateErrorWithStack(): Error {\n const err = new Error(\"<<generated stack>>\");\n\n if (stackPopulatedOnCreation === undefined) {\n stackPopulatedOnCreation = (err.stack !== undefined);\n }\n\n if (stackPopulatedOnCreation) {\n return err;\n }\n\n try {\n throw err;\n } catch (e) {\n return e as Error;\n }\n}\n\nexport function generateStack(): string | undefined {\n return generateErrorWithStack().stack;\n}\n\n/**\n * Create a new error using newErrorFn, wrapping and caused by the given unknown error.\n * Copies the inner error's stack, errorInstanceId and telemetry props over to the new error if present\n * @param innerError - An error from untrusted/unknown origins\n * @param newErrorFn - callback that will create a new error given the original error's message\n * @returns A new error object \"wrapping\" the given error\n */\nexport function wrapError<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n): T {\n const {\n message,\n stack,\n } = extractLogSafeErrorProperties(innerError, false /* sanitizeStack */);\n\n const newError = newErrorFn(message);\n\n if (stack !== undefined) {\n overwriteStack(newError, stack);\n }\n\n // Mark external errors with untrustedOrigin flag\n if (isExternalError(innerError)) {\n newError.addTelemetryProperties({ untrustedOrigin: 1 });\n }\n\n // Reuse errorInstanceId\n if (hasErrorInstanceId(innerError)) {\n newError.overwriteErrorInstanceId(innerError.errorInstanceId);\n\n // For \"back-compat\" in the logs\n newError.addTelemetryProperties({ innerErrorInstanceId: innerError.errorInstanceId });\n }\n\n // Lastly, copy over all other telemetry properties. Note these will not overwrite existing properties\n // This will include the untrustedOrigin property if the inner error itself was created from an external error\n if (isILoggingError(innerError)) {\n newError.addTelemetryProperties(innerError.getTelemetryProperties());\n }\n\n return newError;\n}\n\n/** The same as wrapError, but also logs the innerError, including the wrapping error's instance id */\nexport function wrapErrorAndLog<T extends LoggingError>(\n innerError: unknown,\n newErrorFn: (message: string) => T,\n logger: ITelemetryLogger,\n) {\n const newError = wrapError(innerError, newErrorFn);\n\n // This will match innerError.errorInstanceId if present (see wrapError)\n const errorInstanceId = newError.errorInstanceId;\n\n // For \"back-compat\" in the logs\n const wrappedByErrorInstanceId = errorInstanceId;\n\n logger.sendTelemetryEvent({\n eventName: \"WrapError\",\n errorInstanceId,\n wrappedByErrorInstanceId,\n }, innerError);\n\n return newError;\n}\n\nfunction overwriteStack(error: IFluidErrorBase | LoggingError, stack: string) {\n // supposedly setting stack on an Error can throw.\n try {\n Object.assign(error, { stack });\n } catch (errorSettingStack) {\n error.addTelemetryProperties({ stack2: stack });\n }\n}\n\n/**\n * True for any error object that is an (optionally normalized) external error\n * False for any error we created and raised within the FF codebase via LoggingError base class,\n * or wrapped in a well-known error type\n */\nexport function isExternalError(e: any): boolean {\n // LoggingErrors are an internal FF error type. However, an external error can be converted\n // into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to\n // determine whether the original error was infact external.\n if (LoggingError.typeCheck(e)) {\n if ((e as NormalizedLoggingError).errorType === NORMALIZED_ERROR_TYPE) {\n return e.getTelemetryProperties().untrustedOrigin === 1;\n }\n return false;\n }\n return !isValidLegacyError(e);\n}\n\n/**\n * Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property\n */\nexport function isTaggedTelemetryPropertyValue(x: any): x is ITaggedTelemetryPropertyType {\n return typeof (x?.tag) === \"string\";\n}\n\n/**\n * Filter serializable telemetry properties\n * @param x - any telemetry prop\n * @returns - as-is if x is primitive. returns stringified if x is an array of primitive.\n * otherwise returns null since this is what we support at the moment.\n */\nfunction filterValidTelemetryProps(x: any, key: string): TelemetryEventPropertyType {\n if (Array.isArray(x) && x.every((val) => isTelemetryEventPropertyValue(val))) {\n return JSON.stringify(x);\n }\n if (isTelemetryEventPropertyValue(x)) {\n return x;\n }\n // We don't support logging arbitrary objects\n console.error(`UnSupported Format of Logging Error Property for key ${key}:`, x);\n return \"REDACTED (arbitrary object)\";\n}\n\n// checking type of x, returns false if x is null\nfunction isTelemetryEventPropertyValue(x: any): x is TelemetryEventPropertyType {\n switch (typeof x) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"undefined\":\n return true;\n default:\n return false;\n }\n}\n/**\n * Walk an object's enumerable properties to find those fit for telemetry.\n */\nfunction getValidTelemetryProps(obj: any, keysToOmit: Set<string>): ITelemetryProperties {\n const props: ITelemetryProperties = {};\n for (const key of Object.keys(obj)) {\n if (keysToOmit.has(key)) {\n continue;\n }\n const val = obj[key];\n\n // ensure only valid props get logged, since props of logging error could be in any shape\n if (isTaggedTelemetryPropertyValue(val)) {\n props[key] = {\n value: filterValidTelemetryProps(val.value, key),\n tag: val.tag,\n };\n } else {\n props[key] = filterValidTelemetryProps(val, key);\n }\n }\n return props;\n}\n\n/**\n * Borrowed from\n * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples}\n * Avoids runtime errors with circular references.\n * Not ideal, as will cut values that are not necessarily circular references.\n * Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)\n*/\nexport const getCircularReplacer = () => {\n const seen = new WeakSet();\n return (key: string, value: any): any => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) {\n return \"<removed/circular>\";\n }\n seen.add(value);\n }\n return value;\n };\n};\n\n/**\n * Base class for \"trusted\" errors we create, whose properties can generally be logged to telemetry safely.\n * All properties set on the object, or passed in (via the constructor or addTelemetryProperties),\n * will be logged in accordance with their tag, if present.\n *\n * PLEASE take care to avoid setting sensitive data on this object without proper tagging!\n */\nexport class LoggingError extends Error implements ILoggingError, Omit<IFluidErrorBase, \"errorType\"> {\n private _errorInstanceId = uuid();\n get errorInstanceId() { return this._errorInstanceId; }\n overwriteErrorInstanceId(id: string) { this._errorInstanceId = id; }\n\n /** Back-compat to appease isFluidError typeguard in old code that may handle this error */\n // @ts-expect-error - This field shouldn't be referenced in the current version, but needs to exist at runtime.\n private readonly fluidErrorCode: \"-\" = \"-\";\n\n /**\n * Create a new LoggingError\n * @param message - Error message to use for Error base class\n * @param props - telemetry props to include on the error for when it's logged\n * @param omitPropsFromLogging - properties by name to omit from telemetry props\n */\n constructor(\n message: string,\n props?: ITelemetryProperties,\n private readonly omitPropsFromLogging: Set<string> = new Set(),\n ) {\n super(message);\n\n // Don't log this list itself, or the private _errorInstanceId\n omitPropsFromLogging.add(\"omitPropsFromLogging\");\n omitPropsFromLogging.add(\"_errorInstanceId\");\n\n if (props) {\n this.addTelemetryProperties(props);\n }\n }\n\n /**\n * Determines if a given object is an instance of a LoggingError\n * @param object - any object\n * @returns - true if the object is an instance of a LoggingError, false if not.\n */\n public static typeCheck(object: unknown): object is LoggingError {\n if (typeof object === \"object\" && object !== null) {\n return typeof (object as LoggingError).addTelemetryProperties === \"function\"\n && typeof (object as LoggingError).getTelemetryProperties === \"function\"\n && typeof (object as LoggingError).errorInstanceId === \"string\";\n }\n return false;\n }\n\n /**\n * Add additional properties to be logged\n */\n public addTelemetryProperties(props: ITelemetryProperties) {\n copyProps(this, props);\n }\n\n /**\n * Get all properties fit to be logged to telemetry for this error\n */\n public getTelemetryProperties(): ITelemetryProperties {\n const taggableProps = getValidTelemetryProps(this, this.omitPropsFromLogging);\n // Include non-enumerable props that are not returned by getValidTelemetryProps\n return {\n ...taggableProps,\n stack: this.stack,\n message: this.message,\n errorInstanceId: this._errorInstanceId,\n };\n }\n}\n\n/** The Error class used when normalizing an external error */\nexport const NORMALIZED_ERROR_TYPE = \"genericError\";\nclass NormalizedLoggingError extends LoggingError {\n // errorType \"genericError\" is used as a default value throughout the code.\n // Note that this matches ContainerErrorType/DriverErrorType's genericError\n errorType = NORMALIZED_ERROR_TYPE;\n\n constructor(\n errorProps: Pick<IFluidErrorBase,\n | \"message\"\n | \"stack\"\n >,\n ) {\n super(errorProps.message);\n\n if (errorProps.stack !== undefined) {\n overwriteStack(this, errorProps.stack);\n }\n }\n}\n"]}
|
package/lib/mockLogger.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export declare class MockLogger extends TelemetryLogger implements ITelemetryLog
|
|
|
34
34
|
matchAnyEvent(expectedEvents: Omit<ITelemetryBaseEvent, "category">[]): boolean;
|
|
35
35
|
/** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */
|
|
36
36
|
assertMatchAny(expectedEvents: Omit<ITelemetryBaseEvent, "category">[], message?: string): void;
|
|
37
|
+
/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
|
|
38
|
+
assertMatchNone(disallowedEvents: Omit<ITelemetryBaseEvent, "category">[], message?: string): void;
|
|
37
39
|
private getMatchedEventsCount;
|
|
38
40
|
/**
|
|
39
41
|
* Ensure the expected event is a strict subset of the actual event
|
package/lib/mockLogger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockLogger.d.ts","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,qBAAa,UAAW,SAAQ,eAAgB,YAAW,gBAAgB;IACvE,MAAM,EAAE,mBAAmB,EAAE,CAAM;;IAInC,KAAK;IAIL,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAItC;;;;;;OAMG;IACH,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAO7E,qFAAqF;IACrF,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYrF;;;;;;;OAOG;IACH,aAAa,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAK/E,uFAAuF;IACvF,cAAc,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYxF,OAAO,CAAC,qBAAqB;IAkB7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;CAI7B"}
|
|
1
|
+
{"version":3,"file":"mockLogger.d.ts","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,qBAAa,UAAW,SAAQ,eAAgB,YAAW,gBAAgB;IACvE,MAAM,EAAE,mBAAmB,EAAE,CAAM;;IAInC,KAAK;IAIL,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAItC;;;;;;OAMG;IACH,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAO7E,qFAAqF;IACrF,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYrF;;;;;;;OAOG;IACH,aAAa,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,GAAG,OAAO;IAK/E,uFAAuF;IACvF,cAAc,CAAC,cAAc,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAYxF,6GAA6G;IAC7G,eAAe,CAAC,gBAAgB,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM;IAY3F,OAAO,CAAC,qBAAqB;IAkB7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;CAI7B"}
|
package/lib/mockLogger.js
CHANGED
|
@@ -63,6 +63,18 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
63
63
|
expected:
|
|
64
64
|
${JSON.stringify(expectedEvents)}
|
|
65
65
|
|
|
66
|
+
actual:
|
|
67
|
+
${JSON.stringify(actualEvents)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
|
|
71
|
+
assertMatchNone(disallowedEvents, message) {
|
|
72
|
+
const actualEvents = this.events;
|
|
73
|
+
if (this.matchAnyEvent(disallowedEvents)) {
|
|
74
|
+
throw new Error(`${message}
|
|
75
|
+
disallowed events:
|
|
76
|
+
${JSON.stringify(disallowedEvents)}
|
|
77
|
+
|
|
66
78
|
actual:
|
|
67
79
|
${JSON.stringify(actualEvents)}`);
|
|
68
80
|
}
|
package/lib/mockLogger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,MAAM,OAAO,UAAW,SAAQ,eAAe;IAG3C;QAAgB,KAAK,EAAE,CAAC;QAFxB,WAAM,GAA0B,EAAE,CAAC;IAEV,CAAC;IAE1B,KAAK;QACD,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,KAA0B;QAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,cAAuD;QAC/D,MAAM,yBAAyB,GAAG,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAC7E,2DAA2D;QAC3D,MAAM,2BAA2B,GAAG,cAAc,CAAC,MAAM,GAAG,yBAAyB,CAAC;QACtF,OAAO,2BAA2B,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED,qFAAqF;IACrF,WAAW,CAAC,cAAuD,EAAE,OAAgB;QACjF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO;;EAEpC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;EAG9B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;SACzB;IACL,CAAC;IAED;;;;;;;OAOG;IACH,aAAa,CAAC,cAAuD;QACjE,MAAM,yBAAyB,GAAG,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;QAC7E,OAAO,yBAAyB,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,uFAAuF;IACvF,cAAc,CAAC,cAAuD,EAAE,OAAgB;QACpF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE;YACrC,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO;;EAEpC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;EAG9B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;SACrB;IACT,CAAC;IAEO,qBAAqB,CAAC,cAAuD;QACjF,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,cAAc,GAAG,cAAc,CAAC,MAAM;gBACtC,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC,EAC/D;gBACE,8CAA8C;gBAC9C,EAAE,cAAc,CAAC;aACpB;QACL,CAAC,CAAC,CAAC;QAEH,oFAAoF;QACpF,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QAEjB,sCAAsC;QACtC,OAAO,cAAc,CAAC;IAC1B,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,WAAW,CAAC,MAA2B,EAAE,QAA+C;QACnG,MAAM,MAAM,mCAAQ,MAAM,GAAK,QAAQ,CAAE,CAAC;QAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;CACJ","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport { TelemetryLogger } from \"./logger\";\n\n/**\n * The MockLogger records events sent to it, and then can walk back over those events\n * searching for a set of expected events to match against the logged events.\n */\nexport class MockLogger extends TelemetryLogger implements ITelemetryLogger {\n events: ITelemetryBaseEvent[] = [];\n\n constructor() { super(); }\n\n clear() {\n this.events = [];\n }\n\n send(event: ITelemetryBaseEvent): void {\n this.events.push(event);\n }\n\n /**\n * Search events logged since the last time matchEvents was called, looking for the given expected\n * events in order.\n * @param expectedEvents - events in order that are expected to appear in the recorded log.\n * These event objects may be subsets of the logged events.\n * Note: category is ommitted from the type because it's usually uninteresting and tedious to type.\n */\n matchEvents(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): boolean {\n const matchedExpectedEventCount = this.getMatchedEventsCount(expectedEvents);\n // How many expected events were left over? Hopefully none.\n const unmatchedExpectedEventCount = expectedEvents.length - matchedExpectedEventCount;\n return unmatchedExpectedEventCount === 0;\n }\n\n /** Asserts that matchEvents is true, and prints the actual/expected output if not */\n assertMatch(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (!this.matchEvents(expectedEvents)) {\n throw new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n /**\n * Search events logged since the last time matchEvents was called, looking for any of the given\n * expected events.\n * @param expectedEvents - events that are expected to appear in the recorded log.\n * These event objects may be subsets of the logged events.\n * Note: category is ommitted from the type because it's usually uninteresting and tedious to type.\n * @returns if any of the expected events is found.\n */\n matchAnyEvent(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): boolean {\n const matchedExpectedEventCount = this.getMatchedEventsCount(expectedEvents);\n return matchedExpectedEventCount > 0;\n }\n\n /** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */\n assertMatchAny(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (!this.matchAnyEvent(expectedEvents)) {\n throw new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n private getMatchedEventsCount(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): number {\n let iExpectedEvent = 0;\n this.events.forEach((event) => {\n if (iExpectedEvent < expectedEvents.length &&\n MockLogger.eventsMatch(event, expectedEvents[iExpectedEvent])\n ) {\n // We found the next expected event; increment\n ++iExpectedEvent;\n }\n });\n\n // Remove the events so far; next call will just compare subsequent events from here\n this.events = [];\n\n // Return the count of matched events.\n return iExpectedEvent;\n }\n\n /**\n * Ensure the expected event is a strict subset of the actual event\n */\n private static eventsMatch(actual: ITelemetryBaseEvent, expected: Omit<ITelemetryBaseEvent, \"category\">): boolean {\n const masked = { ...actual, ...expected };\n return JSON.stringify(masked) === JSON.stringify(actual);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.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 { ITelemetryLogger, ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport { TelemetryLogger } from \"./logger\";\n\n/**\n * The MockLogger records events sent to it, and then can walk back over those events\n * searching for a set of expected events to match against the logged events.\n */\nexport class MockLogger extends TelemetryLogger implements ITelemetryLogger {\n events: ITelemetryBaseEvent[] = [];\n\n constructor() { super(); }\n\n clear() {\n this.events = [];\n }\n\n send(event: ITelemetryBaseEvent): void {\n this.events.push(event);\n }\n\n /**\n * Search events logged since the last time matchEvents was called, looking for the given expected\n * events in order.\n * @param expectedEvents - events in order that are expected to appear in the recorded log.\n * These event objects may be subsets of the logged events.\n * Note: category is ommitted from the type because it's usually uninteresting and tedious to type.\n */\n matchEvents(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): boolean {\n const matchedExpectedEventCount = this.getMatchedEventsCount(expectedEvents);\n // How many expected events were left over? Hopefully none.\n const unmatchedExpectedEventCount = expectedEvents.length - matchedExpectedEventCount;\n return unmatchedExpectedEventCount === 0;\n }\n\n /** Asserts that matchEvents is true, and prints the actual/expected output if not */\n assertMatch(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (!this.matchEvents(expectedEvents)) {\n throw new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n /**\n * Search events logged since the last time matchEvents was called, looking for any of the given\n * expected events.\n * @param expectedEvents - events that are expected to appear in the recorded log.\n * These event objects may be subsets of the logged events.\n * Note: category is ommitted from the type because it's usually uninteresting and tedious to type.\n * @returns if any of the expected events is found.\n */\n matchAnyEvent(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): boolean {\n const matchedExpectedEventCount = this.getMatchedEventsCount(expectedEvents);\n return matchedExpectedEventCount > 0;\n }\n\n /** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */\n assertMatchAny(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (!this.matchAnyEvent(expectedEvents)) {\n throw new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n /** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */\n assertMatchNone(disallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[], message?: string) {\n const actualEvents = this.events;\n if (this.matchAnyEvent(disallowedEvents)) {\n throw new Error(`${message}\ndisallowed events:\n${JSON.stringify(disallowedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n }\n }\n\n private getMatchedEventsCount(expectedEvents: Omit<ITelemetryBaseEvent, \"category\">[]): number {\n let iExpectedEvent = 0;\n this.events.forEach((event) => {\n if (iExpectedEvent < expectedEvents.length &&\n MockLogger.eventsMatch(event, expectedEvents[iExpectedEvent])\n ) {\n // We found the next expected event; increment\n ++iExpectedEvent;\n }\n });\n\n // Remove the events so far; next call will just compare subsequent events from here\n this.events = [];\n\n // Return the count of matched events.\n return iExpectedEvent;\n }\n\n /**\n * Ensure the expected event is a strict subset of the actual event\n */\n private static eventsMatch(actual: ITelemetryBaseEvent, expected: Omit<ITelemetryBaseEvent, \"category\">): boolean {\n const masked = { ...actual, ...expected };\n return JSON.stringify(masked) === JSON.stringify(actual);\n }\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/telemetry-utils";
|
|
8
|
-
export declare const pkgVersion = "2.0.0-internal.1.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-internal.1.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export const pkgName = "@fluidframework/telemetry-utils";
|
|
8
|
-
export const pkgVersion = "2.0.0-internal.1.
|
|
8
|
+
export const pkgVersion = "2.0.0-internal.1.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,iCAAiC,CAAC;AACzD,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/telemetry-utils\";\nexport const pkgVersion = \"2.0.0-internal.1.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,iCAAiC,CAAC;AACzD,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/telemetry-utils\";\nexport const pkgVersion = \"2.0.0-internal.1.2.0\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/telemetry-utils",
|
|
3
|
-
"version": "2.0.0-internal.1.
|
|
3
|
+
"version": "2.0.0-internal.1.2.0",
|
|
4
4
|
"description": "Collection of telemetry relates utilities for Fluid",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -71,10 +71,10 @@
|
|
|
71
71
|
"uuid": "^8.3.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@fluidframework/build-common": "^0.
|
|
75
|
-
"@fluidframework/build-tools": "^0.
|
|
76
|
-
"@fluidframework/eslint-config-fluid": "^0.
|
|
77
|
-
"@fluidframework/mocha-test-setup": "^2.0.0-internal.1.
|
|
74
|
+
"@fluidframework/build-common": "^1.0.0",
|
|
75
|
+
"@fluidframework/build-tools": "^0.4.4000",
|
|
76
|
+
"@fluidframework/eslint-config-fluid": "^1.0.0",
|
|
77
|
+
"@fluidframework/mocha-test-setup": "^2.0.0-internal.1.2.0",
|
|
78
78
|
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@^1.0.0",
|
|
79
79
|
"@microsoft/api-extractor": "^7.22.2",
|
|
80
80
|
"@rushstack/eslint-config": "^2.5.1",
|
|
@@ -101,6 +101,9 @@
|
|
|
101
101
|
},
|
|
102
102
|
"EnumDeclaration_TelemetryDataTag": {
|
|
103
103
|
"forwardCompat": false
|
|
104
|
+
},
|
|
105
|
+
"ClassDeclaration_MockLogger": {
|
|
106
|
+
"forwardCompat": false
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
109
|
}
|
package/src/errorLogging.ts
CHANGED
|
@@ -112,7 +112,7 @@ export function normalizeError(
|
|
|
112
112
|
|
|
113
113
|
// We have to construct a new Fluid Error, copying safe properties over
|
|
114
114
|
const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);
|
|
115
|
-
const fluidError: IFluidErrorBase = new
|
|
115
|
+
const fluidError: IFluidErrorBase = new NormalizedLoggingError({
|
|
116
116
|
message,
|
|
117
117
|
stack,
|
|
118
118
|
});
|
|
@@ -130,11 +130,13 @@ export function normalizeError(
|
|
|
130
130
|
fluidError.addTelemetryProperties({ typeofError: typeof (error) });
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
const
|
|
133
|
+
const errorTelemetryProps = LoggingError.typeCheck(error)
|
|
134
|
+
? error.getTelemetryProperties()
|
|
135
|
+
: { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase
|
|
136
|
+
|
|
134
137
|
fluidError.addTelemetryProperties({
|
|
135
|
-
...
|
|
138
|
+
...errorTelemetryProps,
|
|
136
139
|
...annotations.props,
|
|
137
|
-
untrustedOrigin: 1, // This will let us filter to errors not originated by our own code
|
|
138
140
|
});
|
|
139
141
|
|
|
140
142
|
return fluidError;
|
|
@@ -151,7 +153,7 @@ let stackPopulatedOnCreation: boolean | undefined;
|
|
|
151
153
|
* Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.
|
|
152
154
|
* @returns Error object that has stack populated.
|
|
153
155
|
*/
|
|
154
|
-
|
|
156
|
+
export function generateErrorWithStack(): Error {
|
|
155
157
|
const err = new Error("<<generated stack>>");
|
|
156
158
|
|
|
157
159
|
if (stackPopulatedOnCreation === undefined) {
|
|
@@ -251,12 +253,20 @@ function overwriteStack(error: IFluidErrorBase | LoggingError, stack: string) {
|
|
|
251
253
|
|
|
252
254
|
/**
|
|
253
255
|
* True for any error object that is an (optionally normalized) external error
|
|
254
|
-
* False for any error we created and raised within the FF codebase
|
|
256
|
+
* False for any error we created and raised within the FF codebase via LoggingError base class,
|
|
257
|
+
* or wrapped in a well-known error type
|
|
255
258
|
*/
|
|
256
259
|
export function isExternalError(e: any): boolean {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
+
// LoggingErrors are an internal FF error type. However, an external error can be converted
|
|
261
|
+
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
|
|
262
|
+
// determine whether the original error was infact external.
|
|
263
|
+
if (LoggingError.typeCheck(e)) {
|
|
264
|
+
if ((e as NormalizedLoggingError).errorType === NORMALIZED_ERROR_TYPE) {
|
|
265
|
+
return e.getTelemetryProperties().untrustedOrigin === 1;
|
|
266
|
+
}
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
return !isValidLegacyError(e);
|
|
260
270
|
}
|
|
261
271
|
|
|
262
272
|
/**
|
|
@@ -378,6 +388,20 @@ export class LoggingError extends Error implements ILoggingError, Omit<IFluidErr
|
|
|
378
388
|
}
|
|
379
389
|
}
|
|
380
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Determines if a given object is an instance of a LoggingError
|
|
393
|
+
* @param object - any object
|
|
394
|
+
* @returns - true if the object is an instance of a LoggingError, false if not.
|
|
395
|
+
*/
|
|
396
|
+
public static typeCheck(object: unknown): object is LoggingError {
|
|
397
|
+
if (typeof object === "object" && object !== null) {
|
|
398
|
+
return typeof (object as LoggingError).addTelemetryProperties === "function"
|
|
399
|
+
&& typeof (object as LoggingError).getTelemetryProperties === "function"
|
|
400
|
+
&& typeof (object as LoggingError).errorInstanceId === "string";
|
|
401
|
+
}
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
|
|
381
405
|
/**
|
|
382
406
|
* Add additional properties to be logged
|
|
383
407
|
*/
|
|
@@ -401,12 +425,11 @@ export class LoggingError extends Error implements ILoggingError, Omit<IFluidErr
|
|
|
401
425
|
}
|
|
402
426
|
|
|
403
427
|
/** The Error class used when normalizing an external error */
|
|
404
|
-
|
|
428
|
+
export const NORMALIZED_ERROR_TYPE = "genericError";
|
|
429
|
+
class NormalizedLoggingError extends LoggingError {
|
|
405
430
|
// errorType "genericError" is used as a default value throughout the code.
|
|
406
431
|
// Note that this matches ContainerErrorType/DriverErrorType's genericError
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
errorType = NormalizedExternalError.normalizedErrorType;
|
|
432
|
+
errorType = NORMALIZED_ERROR_TYPE;
|
|
410
433
|
|
|
411
434
|
constructor(
|
|
412
435
|
errorProps: Pick<IFluidErrorBase,
|
package/src/mockLogger.ts
CHANGED
|
@@ -71,6 +71,19 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
71
71
|
expected:
|
|
72
72
|
${JSON.stringify(expectedEvents)}
|
|
73
73
|
|
|
74
|
+
actual:
|
|
75
|
+
${JSON.stringify(actualEvents)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
|
|
80
|
+
assertMatchNone(disallowedEvents: Omit<ITelemetryBaseEvent, "category">[], message?: string) {
|
|
81
|
+
const actualEvents = this.events;
|
|
82
|
+
if (this.matchAnyEvent(disallowedEvents)) {
|
|
83
|
+
throw new Error(`${message}
|
|
84
|
+
disallowed events:
|
|
85
|
+
${JSON.stringify(disallowedEvents)}
|
|
86
|
+
|
|
74
87
|
actual:
|
|
75
88
|
${JSON.stringify(actualEvents)}`);
|
|
76
89
|
}
|
package/src/packageVersion.ts
CHANGED