@fluidframework/telemetry-utils 1.4.0-121020 → 2.0.0-dev-rc.1.0.0.224419

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.
Files changed (155) hide show
  1. package/.eslintrc.js +12 -13
  2. package/.mocharc.js +12 -0
  3. package/CHANGELOG.md +249 -0
  4. package/README.md +68 -1
  5. package/api-extractor-lint.json +4 -0
  6. package/api-extractor.json +2 -2
  7. package/api-report/telemetry-utils.api.md +444 -0
  8. package/dist/config.d.ts +47 -16
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +88 -38
  11. package/dist/config.js.map +1 -1
  12. package/dist/error.d.ts +112 -0
  13. package/dist/error.d.ts.map +1 -0
  14. package/dist/error.js +159 -0
  15. package/dist/error.js.map +1 -0
  16. package/dist/errorLogging.d.ts +86 -20
  17. package/dist/errorLogging.d.ts.map +1 -1
  18. package/dist/errorLogging.js +190 -60
  19. package/dist/errorLogging.js.map +1 -1
  20. package/dist/eventEmitterWithErrorHandling.d.ts +9 -3
  21. package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
  22. package/dist/eventEmitterWithErrorHandling.js +16 -3
  23. package/dist/eventEmitterWithErrorHandling.js.map +1 -1
  24. package/dist/events.d.ts +27 -3
  25. package/dist/events.d.ts.map +1 -1
  26. package/dist/events.js +26 -2
  27. package/dist/events.js.map +1 -1
  28. package/dist/fluidErrorBase.d.ts +57 -16
  29. package/dist/fluidErrorBase.d.ts.map +1 -1
  30. package/dist/fluidErrorBase.js +27 -14
  31. package/dist/fluidErrorBase.js.map +1 -1
  32. package/dist/index.d.ts +12 -11
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +55 -21
  35. package/dist/index.js.map +1 -1
  36. package/dist/logger.d.ts +267 -51
  37. package/dist/logger.d.ts.map +1 -1
  38. package/dist/logger.js +423 -132
  39. package/dist/logger.js.map +1 -1
  40. package/dist/mockLogger.d.ts +39 -12
  41. package/dist/mockLogger.d.ts.map +1 -1
  42. package/dist/mockLogger.js +105 -22
  43. package/dist/mockLogger.js.map +1 -1
  44. package/dist/sampledTelemetryHelper.d.ts +18 -12
  45. package/dist/sampledTelemetryHelper.d.ts.map +1 -1
  46. package/dist/sampledTelemetryHelper.js +28 -19
  47. package/dist/sampledTelemetryHelper.js.map +1 -1
  48. package/dist/telemetry-utils-alpha.d.ts +290 -0
  49. package/dist/telemetry-utils-beta.d.ts +264 -0
  50. package/dist/telemetry-utils-public.d.ts +264 -0
  51. package/dist/telemetry-utils-untrimmed.d.ts +1102 -0
  52. package/dist/telemetryTypes.d.ts +115 -0
  53. package/dist/telemetryTypes.d.ts.map +1 -0
  54. package/dist/telemetryTypes.js +7 -0
  55. package/dist/telemetryTypes.js.map +1 -0
  56. package/dist/thresholdCounter.d.ts +6 -5
  57. package/dist/thresholdCounter.d.ts.map +1 -1
  58. package/dist/thresholdCounter.js +4 -3
  59. package/dist/thresholdCounter.js.map +1 -1
  60. package/dist/tsdoc-metadata.json +11 -0
  61. package/dist/utils.d.ts +54 -3
  62. package/dist/utils.d.ts.map +1 -1
  63. package/dist/utils.js +58 -3
  64. package/dist/utils.js.map +1 -1
  65. package/lib/config.d.ts +47 -16
  66. package/lib/config.d.ts.map +1 -1
  67. package/lib/config.js +85 -36
  68. package/lib/config.js.map +1 -1
  69. package/lib/error.d.ts +112 -0
  70. package/lib/error.d.ts.map +1 -0
  71. package/lib/error.js +150 -0
  72. package/lib/error.js.map +1 -0
  73. package/lib/errorLogging.d.ts +86 -20
  74. package/lib/errorLogging.d.ts.map +1 -1
  75. package/lib/errorLogging.js +189 -60
  76. package/lib/errorLogging.js.map +1 -1
  77. package/lib/eventEmitterWithErrorHandling.d.ts +9 -3
  78. package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
  79. package/lib/eventEmitterWithErrorHandling.js +15 -2
  80. package/lib/eventEmitterWithErrorHandling.js.map +1 -1
  81. package/lib/events.d.ts +27 -3
  82. package/lib/events.d.ts.map +1 -1
  83. package/lib/events.js +26 -2
  84. package/lib/events.js.map +1 -1
  85. package/lib/fluidErrorBase.d.ts +57 -16
  86. package/lib/fluidErrorBase.d.ts.map +1 -1
  87. package/lib/fluidErrorBase.js +27 -14
  88. package/lib/fluidErrorBase.js.map +1 -1
  89. package/lib/index.d.ts +12 -11
  90. package/lib/index.d.ts.map +1 -1
  91. package/lib/index.js +11 -11
  92. package/lib/index.js.map +1 -1
  93. package/lib/logger.d.ts +267 -51
  94. package/lib/logger.d.ts.map +1 -1
  95. package/lib/logger.js +415 -131
  96. package/lib/logger.js.map +1 -1
  97. package/lib/mockLogger.d.ts +39 -12
  98. package/lib/mockLogger.d.ts.map +1 -1
  99. package/lib/mockLogger.js +106 -23
  100. package/lib/mockLogger.js.map +1 -1
  101. package/lib/sampledTelemetryHelper.d.ts +18 -12
  102. package/lib/sampledTelemetryHelper.d.ts.map +1 -1
  103. package/lib/sampledTelemetryHelper.js +26 -17
  104. package/lib/sampledTelemetryHelper.js.map +1 -1
  105. package/lib/telemetry-utils-alpha.d.ts +290 -0
  106. package/lib/telemetry-utils-beta.d.ts +264 -0
  107. package/lib/telemetry-utils-public.d.ts +264 -0
  108. package/lib/telemetry-utils-untrimmed.d.ts +1102 -0
  109. package/lib/telemetryTypes.d.ts +115 -0
  110. package/lib/telemetryTypes.d.ts.map +1 -0
  111. package/lib/telemetryTypes.js +6 -0
  112. package/lib/telemetryTypes.js.map +1 -0
  113. package/lib/thresholdCounter.d.ts +6 -5
  114. package/lib/thresholdCounter.d.ts.map +1 -1
  115. package/lib/thresholdCounter.js +4 -3
  116. package/lib/thresholdCounter.js.map +1 -1
  117. package/lib/utils.d.ts +54 -3
  118. package/lib/utils.d.ts.map +1 -1
  119. package/lib/utils.js +56 -2
  120. package/lib/utils.js.map +1 -1
  121. package/package.json +86 -57
  122. package/prettier.config.cjs +8 -0
  123. package/src/config.ts +254 -189
  124. package/src/error.ts +235 -0
  125. package/src/errorLogging.ts +440 -290
  126. package/src/eventEmitterWithErrorHandling.ts +26 -14
  127. package/src/events.ts +54 -25
  128. package/src/fluidErrorBase.ts +94 -46
  129. package/src/index.ts +76 -17
  130. package/src/logger.ts +966 -505
  131. package/src/mockLogger.ts +225 -83
  132. package/src/sampledTelemetryHelper.ts +136 -128
  133. package/src/telemetryTypes.ts +140 -0
  134. package/src/thresholdCounter.ts +38 -37
  135. package/src/utils.ts +108 -17
  136. package/tsconfig.esnext.json +6 -6
  137. package/tsconfig.json +9 -13
  138. package/dist/debugLogger.d.ts +0 -39
  139. package/dist/debugLogger.d.ts.map +0 -1
  140. package/dist/debugLogger.js +0 -101
  141. package/dist/debugLogger.js.map +0 -1
  142. package/dist/packageVersion.d.ts +0 -9
  143. package/dist/packageVersion.d.ts.map +0 -1
  144. package/dist/packageVersion.js +0 -12
  145. package/dist/packageVersion.js.map +0 -1
  146. package/lib/debugLogger.d.ts +0 -39
  147. package/lib/debugLogger.d.ts.map +0 -1
  148. package/lib/debugLogger.js +0 -97
  149. package/lib/debugLogger.js.map +0 -1
  150. package/lib/packageVersion.d.ts +0 -9
  151. package/lib/packageVersion.d.ts.map +0 -1
  152. package/lib/packageVersion.js +0 -9
  153. package/lib/packageVersion.js.map +0 -1
  154. package/src/debugLogger.ts +0 -126
  155. package/src/packageVersion.ts +0 -9
@@ -2,26 +2,43 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ILoggingError, ITaggedTelemetryPropertyType, ITelemetryLogger, ITelemetryProperties } from "@fluidframework/common-definitions";
5
+ import { ILoggingError, ITelemetryBaseProperties, Tagged } from "@fluidframework/core-interfaces";
6
6
  import { IFluidErrorBase } from "./fluidErrorBase";
7
- /** Inspect the given error for common "safe" props and return them */
8
- export declare function extractLogSafeErrorProperties(error: any, sanitizeStack: boolean): {
7
+ import { ITelemetryLoggerExt, TelemetryEventPropertyTypeExt } from "./telemetryTypes";
8
+ /**
9
+ * Inspect the given error for common "safe" props and return them.
10
+ *
11
+ * @internal
12
+ */
13
+ export declare function extractLogSafeErrorProperties(error: unknown, sanitizeStack: boolean): {
9
14
  message: string;
10
15
  errorType?: string | undefined;
11
16
  stack?: string | undefined;
12
17
  };
13
- /** type guard for ILoggingError interface */
14
- export declare const isILoggingError: (x: any) => x is ILoggingError;
15
- /** Metadata to annotate an error object when annotating or normalizing it */
18
+ /**
19
+ * Type-guard for {@link @fluidframework/core-interfaces#ILoggingError}.
20
+ *
21
+ * @internal
22
+ */
23
+ export declare const isILoggingError: (x: unknown) => x is ILoggingError;
24
+ /**
25
+ * Metadata to annotate an error object when annotating or normalizing it
26
+ *
27
+ * @internal
28
+ */
16
29
  export interface IFluidErrorAnnotations {
17
- /** Telemetry props to log with the error */
18
- props?: ITelemetryProperties;
30
+ /**
31
+ * Telemetry props to log with the error
32
+ */
33
+ props?: ITelemetryBaseProperties;
19
34
  }
20
35
  /**
21
36
  * Normalize the given error yielding a valid Fluid Error
22
37
  * @returns A valid Fluid Error with any provided annotations applied
23
38
  * @param error - The error to normalize
24
39
  * @param annotations - Annotations to apply to the normalized error
40
+ *
41
+ * @internal
25
42
  */
26
43
  export declare function normalizeError(error: unknown, annotations?: IFluidErrorAnnotations): IFluidErrorBase;
27
44
  /**
@@ -32,8 +49,16 @@ export declare function normalizeError(error: unknown, annotations?: IFluidError
32
49
  * For such cases it's better to not read stack property right away, but rather delay it until / if it's needed
33
50
  * Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.
34
51
  * @returns Error object that has stack populated.
52
+ *
53
+ * @internal
35
54
  */
36
55
  export declare function generateErrorWithStack(): Error;
56
+ /**
57
+ * Generate a stack at this callsite as if an error were thrown from here.
58
+ * @returns the callstack (does not throw)
59
+ *
60
+ * @internal
61
+ */
37
62
  export declare function generateStack(): string | undefined;
38
63
  /**
39
64
  * Create a new error using newErrorFn, wrapping and caused by the given unknown error.
@@ -41,40 +66,69 @@ export declare function generateStack(): string | undefined;
41
66
  * @param innerError - An error from untrusted/unknown origins
42
67
  * @param newErrorFn - callback that will create a new error given the original error's message
43
68
  * @returns A new error object "wrapping" the given error
69
+ *
70
+ * @internal
44
71
  */
45
72
  export declare function wrapError<T extends LoggingError>(innerError: unknown, newErrorFn: (message: string) => T): T;
46
- /** The same as wrapError, but also logs the innerError, including the wrapping error's instance id */
47
- export declare function wrapErrorAndLog<T extends LoggingError>(innerError: unknown, newErrorFn: (message: string) => T, logger: ITelemetryLogger): T;
73
+ /**
74
+ * The same as wrapError, but also logs the innerError, including the wrapping error's instance ID.
75
+ *
76
+ * @typeParam T - The kind of wrapper error to create.
77
+ *
78
+ * @internal
79
+ */
80
+ export declare function wrapErrorAndLog<T extends LoggingError>(innerError: unknown, newErrorFn: (message: string) => T, logger: ITelemetryLoggerExt): T;
81
+ /**
82
+ * Attempts to overwrite the error's stack
83
+ *
84
+ * There have been reports of certain JS environments where overwriting stack will throw.
85
+ * If that happens, this adds the given stack as the telemetry property "stack2"
86
+ *
87
+ * @internal
88
+ */
89
+ export declare function overwriteStack(error: IFluidErrorBase | LoggingError, stack: string): void;
48
90
  /**
49
91
  * 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, or wrapped in a well-known error type
92
+ * False for any error we created and raised within the FF codebase via LoggingError base class,
93
+ * or wrapped in a well-known error type
94
+ *
95
+ * @internal
51
96
  */
52
- export declare function isExternalError(e: any): boolean;
97
+ export declare function isExternalError(error: unknown): boolean;
53
98
  /**
54
- * Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property
99
+ * Type guard to identify if a particular telemetry property appears to be a
100
+ * {@link @fluidframework/core-interfaces#Tagged} telemetry property.
101
+ *
102
+ * @internal
55
103
  */
56
- export declare function isTaggedTelemetryPropertyValue(x: any): x is ITaggedTelemetryPropertyType;
104
+ export declare function isTaggedTelemetryPropertyValue(x: Tagged<TelemetryEventPropertyTypeExt> | TelemetryEventPropertyTypeExt): x is Tagged<TelemetryEventPropertyTypeExt>;
57
105
  /**
58
106
  * Borrowed from
59
107
  * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples}
60
108
  * Avoids runtime errors with circular references.
61
109
  * Not ideal, as will cut values that are not necessarily circular references.
62
110
  * Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)
63
- */
64
- export declare const getCircularReplacer: () => (key: string, value: any) => any;
111
+ *
112
+ * @internal
113
+ */
114
+ export declare const getCircularReplacer: () => (key: string, value: unknown) => any;
65
115
  /**
66
116
  * Base class for "trusted" errors we create, whose properties can generally be logged to telemetry safely.
67
117
  * All properties set on the object, or passed in (via the constructor or addTelemetryProperties),
68
118
  * will be logged in accordance with their tag, if present.
69
119
  *
70
120
  * PLEASE take care to avoid setting sensitive data on this object without proper tagging!
121
+ *
122
+ * @internal
71
123
  */
72
124
  export declare class LoggingError extends Error implements ILoggingError, Omit<IFluidErrorBase, "errorType"> {
73
125
  private readonly omitPropsFromLogging;
74
126
  private _errorInstanceId;
75
127
  get errorInstanceId(): string;
76
128
  overwriteErrorInstanceId(id: string): void;
77
- /** Back-compat to appease isFluidError typeguard in old code that may handle this error */
129
+ /**
130
+ * Backwards compatibility to appease {@link isFluidError} in old code that may handle this error.
131
+ */
78
132
  private readonly fluidErrorCode;
79
133
  /**
80
134
  * Create a new LoggingError
@@ -82,14 +136,26 @@ export declare class LoggingError extends Error implements ILoggingError, Omit<I
82
136
  * @param props - telemetry props to include on the error for when it's logged
83
137
  * @param omitPropsFromLogging - properties by name to omit from telemetry props
84
138
  */
85
- constructor(message: string, props?: ITelemetryProperties, omitPropsFromLogging?: Set<string>);
139
+ constructor(message: string, props?: ITelemetryBaseProperties, omitPropsFromLogging?: Set<string>);
140
+ /**
141
+ * Determines if a given object is an instance of a LoggingError
142
+ * @param object - any object
143
+ * @returns true if the object is an instance of a LoggingError, false if not.
144
+ */
145
+ static typeCheck(object: unknown): object is LoggingError;
86
146
  /**
87
147
  * Add additional properties to be logged
88
148
  */
89
- addTelemetryProperties(props: ITelemetryProperties): void;
149
+ addTelemetryProperties(props: ITelemetryBaseProperties): void;
90
150
  /**
91
151
  * Get all properties fit to be logged to telemetry for this error
92
152
  */
93
- getTelemetryProperties(): ITelemetryProperties;
153
+ getTelemetryProperties(): ITelemetryBaseProperties;
94
154
  }
155
+ /**
156
+ * The Error class used when normalizing an external error
157
+ *
158
+ * @internal
159
+ */
160
+ export declare const NORMALIZED_ERROR_TYPE = "genericError";
95
161
  //# 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,EACvB,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,CAwCjB;AAID;;;;;;;;GAQG;AACF,wBAAgB,sBAAsB,IAAI,KAAK,CAgB/C;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;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAI/C;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,4BAA4B,CAExF;AAiCD;;;;;;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;;OAEG;IACI,sBAAsB,CAAC,KAAK,EAAE,oBAAoB;IAIzD;;OAEG;IACI,sBAAsB,IAAI,oBAAoB;CAUxD"}
1
+ {"version":3,"file":"errorLogging.d.ts","sourceRoot":"","sources":["../src/errorLogging.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,aAAa,EACb,wBAAwB,EAExB,MAAM,EACN,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAEN,eAAe,EAGf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAStF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,OAAO,GACpB;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAoCA;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,MAAO,OAAO,uBACkC,CAAC;AAgB7E;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,KAAK,CAAC,EAAE,wBAAwB,CAAC;CACjC;AAeD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,OAAO,EACd,WAAW,GAAE,sBAA2B,GACtC,eAAe,CAqDjB;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI,KAAK,CAgB9C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,YAAY,EAC/C,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,GAChC,CAAC,CA6BH;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EACrD,UAAU,EAAE,OAAO,EACnB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,EAClC,MAAM,EAAE,mBAAmB,GACzB,CAAC,CAmBH;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAMzF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAWvD;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC7C,CAAC,EAAE,MAAM,CAAC,6BAA6B,CAAC,GAAG,6BAA6B,GACtE,CAAC,IAAI,MAAM,CAAC,6BAA6B,CAAC,CAE5C;AA2DD;;;;;;;;GAQG;AAGH,eAAO,MAAM,mBAAmB,cAAc,MAAM,SAAS,OAAO,KAAK,GAWxE,CAAC;AAGF;;;;;;;;GAQG;AACH,qBAAa,YACZ,SAAQ,KACR,YAAW,aAAa,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC;IA0B3D,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IAxBtC,OAAO,CAAC,gBAAgB,CAAU;IAClC,IAAI,eAAe,IAAI,MAAM,CAE5B;IACD,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI1C;;OAEG;IAGH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAY;IAE3C;;;;;OAKG;gBAEF,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,wBAAwB,EACf,oBAAoB,GAAE,GAAG,CAAC,MAAM,CAAa;IAa/D;;;;OAIG;WACW,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY;IAWhE;;OAEG;IACI,sBAAsB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI;IAIpE;;OAEG;IACI,sBAAsB,IAAI,wBAAwB;CAUzD;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,iBAAiB,CAAC"}
@@ -4,11 +4,17 @@
4
4
  */
5
5
  import { v4 as uuid } from "uuid";
6
6
  import { hasErrorInstanceId, isFluidError, isValidLegacyError, } from "./fluidErrorBase";
7
- /** @returns true if value is an object but neither null nor an array */
7
+ /**
8
+ * Determines if the provided value is an object but neither null nor an array.
9
+ */
8
10
  const isRegularObject = (value) => {
9
11
  return value !== null && !Array.isArray(value) && typeof value === "object";
10
12
  };
11
- /** Inspect the given error for common "safe" props and return them */
13
+ /**
14
+ * Inspect the given error for common "safe" props and return them.
15
+ *
16
+ * @internal
17
+ */
12
18
  export function extractLogSafeErrorProperties(error, sanitizeStack) {
13
19
  const removeMessageFromStack = (stack, errorName) => {
14
20
  if (!sanitizeStack) {
@@ -21,7 +27,7 @@ export function extractLogSafeErrorProperties(error, sanitizeStack) {
21
27
  }
22
28
  return stackFrames.join("\n");
23
29
  };
24
- const message = (typeof (error === null || error === void 0 ? void 0 : error.message) === "string")
30
+ const message = typeof error?.message === "string"
25
31
  ? error.message
26
32
  : String(error);
27
33
  const safeProps = {
@@ -33,15 +39,21 @@ export function extractLogSafeErrorProperties(error, sanitizeStack) {
33
39
  safeProps.errorType = errorType;
34
40
  }
35
41
  if (typeof stack === "string") {
36
- const errorName = (typeof name === "string") ? name : undefined;
42
+ const errorName = typeof name === "string" ? name : undefined;
37
43
  safeProps.stack = removeMessageFromStack(stack, errorName);
38
44
  }
39
45
  }
40
46
  return safeProps;
41
47
  }
42
- /** type guard for ILoggingError interface */
43
- export const isILoggingError = (x) => typeof (x === null || x === void 0 ? void 0 : x.getTelemetryProperties) === "function";
44
- /** Copy props from source onto target, but do not overwrite an existing prop that matches */
48
+ /**
49
+ * Type-guard for {@link @fluidframework/core-interfaces#ILoggingError}.
50
+ *
51
+ * @internal
52
+ */
53
+ export const isILoggingError = (x) => typeof x?.getTelemetryProperties === "function";
54
+ /**
55
+ * Copy props from source onto target, but do not overwrite an existing prop that matches
56
+ */
45
57
  function copyProps(target, source) {
46
58
  for (const key of Object.keys(source)) {
47
59
  if (target[key] === undefined) {
@@ -49,8 +61,11 @@ function copyProps(target, source) {
49
61
  }
50
62
  }
51
63
  }
52
- /** For backwards compatibility with pre-errorInstanceId valid errors */
64
+ /**
65
+ * For backwards compatibility with pre-errorInstanceId valid errors
66
+ */
53
67
  function patchLegacyError(legacyError) {
68
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
54
69
  const patchMe = legacyError;
55
70
  if (patchMe.errorInstanceId === undefined) {
56
71
  patchMe.errorInstanceId = uuid();
@@ -61,21 +76,22 @@ function patchLegacyError(legacyError) {
61
76
  * @returns A valid Fluid Error with any provided annotations applied
62
77
  * @param error - The error to normalize
63
78
  * @param annotations - Annotations to apply to the normalized error
79
+ *
80
+ * @internal
64
81
  */
65
82
  export function normalizeError(error, annotations = {}) {
66
- var _a;
67
83
  // Back-compat, while IFluidErrorBase is rolled out
68
84
  if (isValidLegacyError(error)) {
69
85
  patchLegacyError(error);
70
86
  }
71
87
  if (isFluidError(error)) {
72
88
  // We can simply add the telemetry props to the error and return it
73
- error.addTelemetryProperties((_a = annotations.props) !== null && _a !== void 0 ? _a : {});
89
+ error.addTelemetryProperties(annotations.props ?? {});
74
90
  return error;
75
91
  }
76
92
  // We have to construct a new Fluid Error, copying safe properties over
77
93
  const { message, stack } = extractLogSafeErrorProperties(error, false /* sanitizeStack */);
78
- const fluidError = new NormalizedExternalError({
94
+ const fluidError = new NormalizedLoggingError({
79
95
  message,
80
96
  stack,
81
97
  });
@@ -83,15 +99,31 @@ export function normalizeError(error, annotations = {}) {
83
99
  // Anywhere they are set should be on a valid Fluid Error that would have been returned above,
84
100
  // but we can't prove it with the types, so adding this defensive measure.
85
101
  if (typeof error === "object" && error !== null) {
86
- const { canRetry, retryAfterSeconds } = error;
87
- Object.assign(normalizeError, { canRetry, retryAfterSeconds });
102
+ const maybeHasRetry = error;
103
+ let retryProps;
104
+ if ("canRetry" in error) {
105
+ retryProps ?? (retryProps = {});
106
+ retryProps.canRetry = maybeHasRetry.canRetry;
107
+ }
108
+ if ("retryAfterSeconds" in error) {
109
+ retryProps ?? (retryProps = {});
110
+ retryProps.retryAfterSeconds = maybeHasRetry.retryAfterSeconds;
111
+ }
112
+ if (retryProps !== undefined) {
113
+ Object.assign(fluidError, retryProps);
114
+ }
88
115
  }
89
- if (typeof (error) !== "object") {
116
+ if (typeof error !== "object") {
90
117
  // This is only interesting for non-objects
91
- fluidError.addTelemetryProperties({ typeofError: typeof (error) });
118
+ fluidError.addTelemetryProperties({ typeofError: typeof error });
92
119
  }
93
- const originalErrorTelemetryProps = isILoggingError(error) ? error.getTelemetryProperties() : {};
94
- fluidError.addTelemetryProperties(Object.assign(Object.assign(Object.assign({}, originalErrorTelemetryProps), annotations.props), { untrustedOrigin: 1 }));
120
+ const errorTelemetryProps = LoggingError.typeCheck(error)
121
+ ? error.getTelemetryProperties()
122
+ : { untrustedOrigin: 1 }; // This will let us filter errors that did not originate from our own codebase
123
+ fluidError.addTelemetryProperties({
124
+ ...errorTelemetryProps,
125
+ ...annotations.props,
126
+ });
95
127
  return fluidError;
96
128
  }
97
129
  let stackPopulatedOnCreation;
@@ -103,11 +135,13 @@ let stackPopulatedOnCreation;
103
135
  * For such cases it's better to not read stack property right away, but rather delay it until / if it's needed
104
136
  * Some browsers will populate stack right away, others require throwing Error, so we do auto-detection on the fly.
105
137
  * @returns Error object that has stack populated.
138
+ *
139
+ * @internal
106
140
  */
107
141
  export function generateErrorWithStack() {
108
142
  const err = new Error("<<generated stack>>");
109
143
  if (stackPopulatedOnCreation === undefined) {
110
- stackPopulatedOnCreation = (err.stack !== undefined);
144
+ stackPopulatedOnCreation = err.stack !== undefined;
111
145
  }
112
146
  if (stackPopulatedOnCreation) {
113
147
  return err;
@@ -115,10 +149,16 @@ export function generateErrorWithStack() {
115
149
  try {
116
150
  throw err;
117
151
  }
118
- catch (e) {
119
- return e;
152
+ catch (error) {
153
+ return error;
120
154
  }
121
155
  }
156
+ /**
157
+ * Generate a stack at this callsite as if an error were thrown from here.
158
+ * @returns the callstack (does not throw)
159
+ *
160
+ * @internal
161
+ */
122
162
  export function generateStack() {
123
163
  return generateErrorWithStack().stack;
124
164
  }
@@ -128,9 +168,11 @@ export function generateStack() {
128
168
  * @param innerError - An error from untrusted/unknown origins
129
169
  * @param newErrorFn - callback that will create a new error given the original error's message
130
170
  * @returns A new error object "wrapping" the given error
171
+ *
172
+ * @internal
131
173
  */
132
174
  export function wrapError(innerError, newErrorFn) {
133
- const { message, stack, } = extractLogSafeErrorProperties(innerError, false /* sanitizeStack */);
175
+ const { message, stack } = extractLogSafeErrorProperties(innerError, false /* sanitizeStack */);
134
176
  const newError = newErrorFn(message);
135
177
  if (stack !== undefined) {
136
178
  overwriteStack(newError, stack);
@@ -152,7 +194,13 @@ export function wrapError(innerError, newErrorFn) {
152
194
  }
153
195
  return newError;
154
196
  }
155
- /** The same as wrapError, but also logs the innerError, including the wrapping error's instance id */
197
+ /**
198
+ * The same as wrapError, but also logs the innerError, including the wrapping error's instance ID.
199
+ *
200
+ * @typeParam T - The kind of wrapper error to create.
201
+ *
202
+ * @internal
203
+ */
156
204
  export function wrapErrorAndLog(innerError, newErrorFn, logger) {
157
205
  const newError = wrapError(innerError, newErrorFn);
158
206
  // This will match innerError.errorInstanceId if present (see wrapError)
@@ -166,29 +214,80 @@ export function wrapErrorAndLog(innerError, newErrorFn, logger) {
166
214
  }, innerError);
167
215
  return newError;
168
216
  }
169
- function overwriteStack(error, stack) {
170
- // supposedly setting stack on an Error can throw.
217
+ /**
218
+ * Attempts to overwrite the error's stack
219
+ *
220
+ * There have been reports of certain JS environments where overwriting stack will throw.
221
+ * If that happens, this adds the given stack as the telemetry property "stack2"
222
+ *
223
+ * @internal
224
+ */
225
+ export function overwriteStack(error, stack) {
171
226
  try {
172
227
  Object.assign(error, { stack });
173
228
  }
174
- catch (errorSettingStack) {
229
+ catch {
175
230
  error.addTelemetryProperties({ stack2: stack });
176
231
  }
177
232
  }
178
233
  /**
179
234
  * 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, or wrapped in a well-known error type
235
+ * False for any error we created and raised within the FF codebase via LoggingError base class,
236
+ * or wrapped in a well-known error type
237
+ *
238
+ * @internal
181
239
  */
182
- export function isExternalError(e) {
183
- return !isValidLegacyError(e) ||
184
- (e.getTelemetryProperties().untrustedOrigin === 1 &&
185
- e.errorType === NormalizedExternalError.normalizedErrorType);
240
+ export function isExternalError(error) {
241
+ // LoggingErrors are an internal FF error type. However, an external error can be converted
242
+ // into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
243
+ // determine whether the original error was infact external.
244
+ if (LoggingError.typeCheck(error)) {
245
+ if (error.errorType === NORMALIZED_ERROR_TYPE) {
246
+ return error.getTelemetryProperties().untrustedOrigin === 1;
247
+ }
248
+ return false;
249
+ }
250
+ return !isValidLegacyError(error);
186
251
  }
187
252
  /**
188
- * Type guard to identify if a particular value (loosely) appears to be a tagged telemetry property
253
+ * Type guard to identify if a particular telemetry property appears to be a
254
+ * {@link @fluidframework/core-interfaces#Tagged} telemetry property.
255
+ *
256
+ * @internal
189
257
  */
190
258
  export function isTaggedTelemetryPropertyValue(x) {
191
- return (typeof (x === null || x === void 0 ? void 0 : x.value) !== "object" && typeof (x === null || x === void 0 ? void 0 : x.tag) === "string");
259
+ return typeof x?.tag === "string";
260
+ }
261
+ /**
262
+ * Filter serializable telemetry properties
263
+ * @param x - Any telemetry prop
264
+ * @returns As-is if x is primitive. returns stringified if x is an array of primitive.
265
+ * otherwise returns null since this is what we support at the moment.
266
+ */
267
+ function filterValidTelemetryProps(x, key) {
268
+ if (Array.isArray(x) && x.every((val) => isTelemetryEventPropertyValue(val))) {
269
+ return JSON.stringify(x);
270
+ }
271
+ if (isTelemetryEventPropertyValue(x)) {
272
+ return x;
273
+ }
274
+ // We don't support logging arbitrary objects
275
+ console.error(`UnSupported Format of Logging Error Property for key ${key}:`, x);
276
+ return "REDACTED (arbitrary object)";
277
+ }
278
+ // checking type of x, returns false if x is null
279
+ function isTelemetryEventPropertyValue(x) {
280
+ switch (typeof x) {
281
+ case "string":
282
+ case "number":
283
+ case "boolean":
284
+ case "undefined": {
285
+ return true;
286
+ }
287
+ default: {
288
+ return false;
289
+ }
290
+ }
192
291
  }
193
292
  /**
194
293
  * Walk an object's enumerable properties to find those fit for telemetry.
@@ -200,24 +299,13 @@ function getValidTelemetryProps(obj, keysToOmit) {
200
299
  continue;
201
300
  }
202
301
  const val = obj[key];
203
- switch (typeof val) {
204
- case "string":
205
- case "number":
206
- case "boolean":
207
- case "undefined":
208
- props[key] = val;
209
- break;
210
- default: {
211
- if (isTaggedTelemetryPropertyValue(val)) {
212
- props[key] = val;
213
- }
214
- else {
215
- // We don't support logging arbitrary objects
216
- props[key] = "REDACTED (arbitrary object)";
217
- }
218
- break;
302
+ // ensure only valid props get logged, since props of logging error could be in any shape
303
+ props[key] = isTaggedTelemetryPropertyValue(val)
304
+ ? {
305
+ value: filterValidTelemetryProps(val.value, key),
306
+ tag: val.tag,
219
307
  }
220
- }
308
+ : filterValidTelemetryProps(val, key);
221
309
  }
222
310
  return props;
223
311
  }
@@ -227,7 +315,11 @@ function getValidTelemetryProps(obj, keysToOmit) {
227
315
  * Avoids runtime errors with circular references.
228
316
  * Not ideal, as will cut values that are not necessarily circular references.
229
317
  * Could be improved by implementing Node's util.inspect() for browser (minus all the coloring code)
230
- */
318
+ *
319
+ * @internal
320
+ */
321
+ // TODO: Use `unknown` instead (API breaking change)
322
+ /* eslint-disable @typescript-eslint/no-explicit-any */
231
323
  export const getCircularReplacer = () => {
232
324
  const seen = new WeakSet();
233
325
  return (key, value) => {
@@ -240,14 +332,23 @@ export const getCircularReplacer = () => {
240
332
  return value;
241
333
  };
242
334
  };
335
+ /* eslint-enable @typescript-eslint/no-explicit-any */
243
336
  /**
244
337
  * Base class for "trusted" errors we create, whose properties can generally be logged to telemetry safely.
245
338
  * All properties set on the object, or passed in (via the constructor or addTelemetryProperties),
246
339
  * will be logged in accordance with their tag, if present.
247
340
  *
248
341
  * PLEASE take care to avoid setting sensitive data on this object without proper tagging!
342
+ *
343
+ * @internal
249
344
  */
250
345
  export class LoggingError extends Error {
346
+ get errorInstanceId() {
347
+ return this._errorInstanceId;
348
+ }
349
+ overwriteErrorInstanceId(id) {
350
+ this._errorInstanceId = id;
351
+ }
251
352
  /**
252
353
  * Create a new LoggingError
253
354
  * @param message - Error message to use for Error base class
@@ -258,8 +359,11 @@ export class LoggingError extends Error {
258
359
  super(message);
259
360
  this.omitPropsFromLogging = omitPropsFromLogging;
260
361
  this._errorInstanceId = uuid();
261
- /** Back-compat to appease isFluidError typeguard in old code that may handle this error */
362
+ /**
363
+ * Backwards compatibility to appease {@link isFluidError} in old code that may handle this error.
364
+ */
262
365
  // @ts-expect-error - This field shouldn't be referenced in the current version, but needs to exist at runtime.
366
+ // eslint-disable-next-line @typescript-eslint/prefer-as-const
263
367
  this.fluidErrorCode = "-";
264
368
  // Don't log this list itself, or the private _errorInstanceId
265
369
  omitPropsFromLogging.add("omitPropsFromLogging");
@@ -268,8 +372,19 @@ export class LoggingError extends Error {
268
372
  this.addTelemetryProperties(props);
269
373
  }
270
374
  }
271
- get errorInstanceId() { return this._errorInstanceId; }
272
- overwriteErrorInstanceId(id) { this._errorInstanceId = id; }
375
+ /**
376
+ * Determines if a given object is an instance of a LoggingError
377
+ * @param object - any object
378
+ * @returns true if the object is an instance of a LoggingError, false if not.
379
+ */
380
+ static typeCheck(object) {
381
+ if (typeof object === "object" && object !== null) {
382
+ return (typeof object.addTelemetryProperties === "function" &&
383
+ typeof object.getTelemetryProperties === "function" &&
384
+ typeof object.errorInstanceId === "string");
385
+ }
386
+ return false;
387
+ }
273
388
  /**
274
389
  * Add additional properties to be logged
275
390
  */
@@ -282,20 +397,34 @@ export class LoggingError extends Error {
282
397
  getTelemetryProperties() {
283
398
  const taggableProps = getValidTelemetryProps(this, this.omitPropsFromLogging);
284
399
  // Include non-enumerable props that are not returned by getValidTelemetryProps
285
- return Object.assign(Object.assign({}, taggableProps), { stack: this.stack, message: this.message, errorInstanceId: this._errorInstanceId });
400
+ return {
401
+ ...taggableProps,
402
+ stack: this.stack,
403
+ message: this.message,
404
+ errorInstanceId: this._errorInstanceId,
405
+ };
286
406
  }
287
407
  }
288
- /** The Error class used when normalizing an external error */
289
- class NormalizedExternalError extends LoggingError {
408
+ /**
409
+ * The Error class used when normalizing an external error
410
+ *
411
+ * @internal
412
+ */
413
+ export const NORMALIZED_ERROR_TYPE = "genericError";
414
+ /**
415
+ * Subclass of LoggingError returned by normalizeError
416
+ *
417
+ * @internal
418
+ */
419
+ class NormalizedLoggingError extends LoggingError {
290
420
  constructor(errorProps) {
291
421
  super(errorProps.message);
292
- this.errorType = NormalizedExternalError.normalizedErrorType;
422
+ // errorType "genericError" is used as a default value throughout the code.
423
+ // Note that this matches ContainerErrorType/DriverErrorType's genericError
424
+ this.errorType = NORMALIZED_ERROR_TYPE;
293
425
  if (errorProps.stack !== undefined) {
294
426
  overwriteStack(this, errorProps.stack);
295
427
  }
296
428
  }
297
429
  }
298
- // errorType "genericError" is used as a default value throughout the code.
299
- // Note that this matches ContainerErrorType/DriverErrorType's genericError
300
- NormalizedExternalError.normalizedErrorType = "genericError";
301
430
  //# sourceMappingURL=errorLogging.js.map