@fluidframework/telemetry-utils 2.0.0-internal.6.1.1 → 2.0.0-internal.6.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.
Files changed (109) hide show
  1. package/.eslintrc.js +2 -1
  2. package/CHANGELOG.md +31 -0
  3. package/README.md +4 -3
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +9 -4
  6. package/dist/config.js.map +1 -1
  7. package/dist/error.d.ts +92 -0
  8. package/dist/error.d.ts.map +1 -0
  9. package/dist/error.js +133 -0
  10. package/dist/error.js.map +1 -0
  11. package/dist/errorLogging.d.ts +27 -11
  12. package/dist/errorLogging.d.ts.map +1 -1
  13. package/dist/errorLogging.js +42 -17
  14. package/dist/errorLogging.js.map +1 -1
  15. package/dist/eventEmitterWithErrorHandling.d.ts +2 -2
  16. package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
  17. package/dist/eventEmitterWithErrorHandling.js +4 -1
  18. package/dist/eventEmitterWithErrorHandling.js.map +1 -1
  19. package/dist/events.d.ts +1 -1
  20. package/dist/events.d.ts.map +1 -1
  21. package/dist/events.js.map +1 -1
  22. package/dist/fluidErrorBase.d.ts +48 -15
  23. package/dist/fluidErrorBase.d.ts.map +1 -1
  24. package/dist/fluidErrorBase.js +18 -11
  25. package/dist/fluidErrorBase.js.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +7 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/logger.d.ts +28 -16
  31. package/dist/logger.d.ts.map +1 -1
  32. package/dist/logger.js +41 -14
  33. package/dist/logger.js.map +1 -1
  34. package/dist/mockLogger.d.ts +14 -5
  35. package/dist/mockLogger.d.ts.map +1 -1
  36. package/dist/mockLogger.js +19 -7
  37. package/dist/mockLogger.js.map +1 -1
  38. package/dist/sampledTelemetryHelper.d.ts +8 -7
  39. package/dist/sampledTelemetryHelper.d.ts.map +1 -1
  40. package/dist/sampledTelemetryHelper.js +10 -8
  41. package/dist/sampledTelemetryHelper.js.map +1 -1
  42. package/dist/telemetryTypes.d.ts +8 -4
  43. package/dist/telemetryTypes.d.ts.map +1 -1
  44. package/dist/telemetryTypes.js.map +1 -1
  45. package/dist/thresholdCounter.d.ts.map +1 -1
  46. package/dist/thresholdCounter.js.map +1 -1
  47. package/dist/utils.d.ts +1 -1
  48. package/dist/utils.d.ts.map +1 -1
  49. package/dist/utils.js.map +1 -1
  50. package/lib/config.d.ts.map +1 -1
  51. package/lib/config.js +9 -4
  52. package/lib/config.js.map +1 -1
  53. package/lib/error.d.ts +92 -0
  54. package/lib/error.d.ts.map +1 -0
  55. package/lib/error.js +125 -0
  56. package/lib/error.js.map +1 -0
  57. package/lib/errorLogging.d.ts +27 -11
  58. package/lib/errorLogging.d.ts.map +1 -1
  59. package/lib/errorLogging.js +42 -17
  60. package/lib/errorLogging.js.map +1 -1
  61. package/lib/eventEmitterWithErrorHandling.d.ts +2 -2
  62. package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
  63. package/lib/eventEmitterWithErrorHandling.js +4 -1
  64. package/lib/eventEmitterWithErrorHandling.js.map +1 -1
  65. package/lib/events.d.ts +1 -1
  66. package/lib/events.d.ts.map +1 -1
  67. package/lib/events.js.map +1 -1
  68. package/lib/fluidErrorBase.d.ts +48 -15
  69. package/lib/fluidErrorBase.d.ts.map +1 -1
  70. package/lib/fluidErrorBase.js +18 -11
  71. package/lib/fluidErrorBase.js.map +1 -1
  72. package/lib/index.d.ts +1 -0
  73. package/lib/index.d.ts.map +1 -1
  74. package/lib/index.js +1 -0
  75. package/lib/index.js.map +1 -1
  76. package/lib/logger.d.ts +28 -16
  77. package/lib/logger.d.ts.map +1 -1
  78. package/lib/logger.js +41 -14
  79. package/lib/logger.js.map +1 -1
  80. package/lib/mockLogger.d.ts +14 -5
  81. package/lib/mockLogger.d.ts.map +1 -1
  82. package/lib/mockLogger.js +19 -7
  83. package/lib/mockLogger.js.map +1 -1
  84. package/lib/sampledTelemetryHelper.d.ts +8 -7
  85. package/lib/sampledTelemetryHelper.d.ts.map +1 -1
  86. package/lib/sampledTelemetryHelper.js +10 -8
  87. package/lib/sampledTelemetryHelper.js.map +1 -1
  88. package/lib/telemetryTypes.d.ts +8 -4
  89. package/lib/telemetryTypes.d.ts.map +1 -1
  90. package/lib/telemetryTypes.js.map +1 -1
  91. package/lib/thresholdCounter.d.ts.map +1 -1
  92. package/lib/thresholdCounter.js.map +1 -1
  93. package/lib/utils.d.ts +1 -1
  94. package/lib/utils.d.ts.map +1 -1
  95. package/lib/utils.js.map +1 -1
  96. package/package.json +12 -12
  97. package/src/config.ts +12 -7
  98. package/src/error.ts +202 -0
  99. package/src/errorLogging.ts +78 -38
  100. package/src/eventEmitterWithErrorHandling.ts +4 -2
  101. package/src/events.ts +3 -3
  102. package/src/fluidErrorBase.ts +62 -26
  103. package/src/index.ts +7 -0
  104. package/src/logger.ts +109 -35
  105. package/src/mockLogger.ts +25 -14
  106. package/src/sampledTelemetryHelper.ts +17 -13
  107. package/src/telemetryTypes.ts +20 -4
  108. package/src/thresholdCounter.ts +2 -2
  109. package/src/utils.ts +1 -1
@@ -6,62 +6,98 @@
6
6
  import { ITelemetryProperties } from "@fluidframework/core-interfaces";
7
7
 
8
8
  /**
9
+ * An error emitted by the Fluid Framework.
10
+ *
11
+ * @remarks
12
+ *
9
13
  * All normalized errors flowing through the Fluid Framework adhere to this readonly interface.
10
- * It features errorType and errorInstanceId on top of Error's members as readonly,
11
- * and a getter/setter for telemetry props to be included when the error is logged.
14
+ *
15
+ * It features the members of {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error | Error}
16
+ * made readonly, as well as {@link IFluidErrorBase.errorType} and {@link IFluidErrorBase.errorInstanceId}.
17
+ * It also features getters and setters for telemetry props to be included when the error is logged.
12
18
  */
13
19
  export interface IFluidErrorBase extends Error {
14
- /** Classification of what type of error this is, used programmatically by consumers to interpret the error */
20
+ /**
21
+ * Classification of what type of error this is.
22
+ *
23
+ * @remarks Used programmatically by consumers to interpret the error.
24
+ */
15
25
  readonly errorType: string;
16
26
 
17
27
  /**
18
28
  * Error's message property, made readonly.
19
- * Be specific, but also take care when including variable data to consider suitability for aggregation in telemetry
20
- * Also avoid including any data that jeopardizes the user's privacy. Add a tagged telemetry property instead.
29
+ *
30
+ * @remarks
31
+ *
32
+ * Recommendations:
33
+ *
34
+ * Be specific, but also take care when including variable data to consider suitability for aggregation in telemetry.
35
+ * Also avoid including any data that jeopardizes the user's privacy. Add a tagged telemetry property instead.
21
36
  */
22
37
  readonly message: string;
23
38
 
24
- /** Error's stack property, made readonly */
39
+ /**
40
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack}.
41
+ */
25
42
  readonly stack?: string;
26
43
 
27
- /** Error's name property, made readonly */
44
+ /**
45
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/name}.
46
+ */
28
47
  readonly name: string;
29
48
 
30
49
  /**
31
50
  * A Guid identifying this error instance.
32
- * Useful in telemetry for deduping multiple logging events arising from the same error,
51
+ *
52
+ * @remarks
53
+ *
54
+ * Useful in telemetry for deduplicating multiple logging events arising from the same error,
33
55
  * or correlating an error with an inner error that caused it, in case of error wrapping.
34
56
  */
35
57
  readonly errorInstanceId: string;
36
58
 
37
- /** Get the telemetry properties stashed on this error for logging */
59
+ /**
60
+ * Get the telemetry properties stashed on this error for logging.
61
+ */
38
62
  getTelemetryProperties(): ITelemetryProperties;
39
- /** Add telemetry properties to this error which will be logged with the error */
63
+
64
+ /**
65
+ * Add telemetry properties to this error which will be logged with the error
66
+ */
40
67
  addTelemetryProperties: (props: ITelemetryProperties) => void;
41
68
  }
42
69
 
43
- const hasTelemetryPropFunctions = (x: any): boolean =>
44
- typeof x?.getTelemetryProperties === "function" &&
45
- typeof x?.addTelemetryProperties === "function";
70
+ const hasTelemetryPropFunctions = (x: unknown): boolean =>
71
+ typeof (x as Partial<IFluidErrorBase>)?.getTelemetryProperties === "function" &&
72
+ typeof (x as Partial<IFluidErrorBase>)?.addTelemetryProperties === "function";
46
73
 
47
- export const hasErrorInstanceId = (x: any): x is { errorInstanceId: string } =>
48
- typeof x?.errorInstanceId === "string";
74
+ /**
75
+ * Type guard for error data containing the {@link IFluidErrorBase.errorInstanceId} property.
76
+ */
77
+ export const hasErrorInstanceId = (x: unknown): x is { errorInstanceId: string } =>
78
+ typeof (x as Partial<{ errorInstanceId: string }>)?.errorInstanceId === "string";
49
79
 
50
- /** type guard for IFluidErrorBase interface */
51
- export function isFluidError(e: any): e is IFluidErrorBase {
80
+ /**
81
+ * Type guard for {@link IFluidErrorBase}.
82
+ */
83
+ export function isFluidError(error: unknown): error is IFluidErrorBase {
52
84
  return (
53
- typeof e?.errorType === "string" &&
54
- typeof e?.message === "string" &&
55
- hasErrorInstanceId(e) &&
56
- hasTelemetryPropFunctions(e)
85
+ typeof (error as Partial<IFluidErrorBase>)?.errorType === "string" &&
86
+ typeof (error as Partial<IFluidErrorBase>)?.message === "string" &&
87
+ hasErrorInstanceId(error) &&
88
+ hasTelemetryPropFunctions(error)
57
89
  );
58
90
  }
59
91
 
60
- /** type guard for old standard of valid/known errors */
61
- export function isValidLegacyError(e: any): e is Omit<IFluidErrorBase, "errorInstanceId"> {
92
+ /**
93
+ * Type guard for old standard of valid/known errors.
94
+ */
95
+ export function isValidLegacyError(
96
+ error: unknown,
97
+ ): error is Omit<IFluidErrorBase, "errorInstanceId"> {
62
98
  return (
63
- typeof e?.errorType === "string" &&
64
- typeof e?.message === "string" &&
65
- hasTelemetryPropFunctions(e)
99
+ typeof (error as Partial<IFluidErrorBase>)?.errorType === "string" &&
100
+ typeof (error as Partial<IFluidErrorBase>)?.message === "string" &&
101
+ hasTelemetryPropFunctions(error)
66
102
  );
67
103
  }
package/src/index.ts CHANGED
@@ -12,6 +12,13 @@ export {
12
12
  ConfigTypes,
13
13
  loggerToMonitoringContext,
14
14
  } from "./config";
15
+ export {
16
+ DataCorruptionError,
17
+ DataProcessingError,
18
+ extractSafePropertiesFromMessage,
19
+ GenericError,
20
+ UsageError,
21
+ } from "./error";
15
22
  export {
16
23
  extractLogSafeErrorProperties,
17
24
  generateErrorWithStack,
package/src/logger.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  TelemetryEventPropertyType,
14
14
  ITaggedTelemetryPropertyType,
15
15
  TelemetryEventCategory,
16
+ LogLevel,
16
17
  } from "@fluidframework/core-interfaces";
17
18
  import { IsomorphicPerformance, performance } from "@fluidframework/common-utils";
18
19
  import { CachedConfigProvider, loggerIsMonitoringContext, mixinMonitoringContext } from "./config";
@@ -28,6 +29,7 @@ import {
28
29
  ITelemetryGenericEventExt,
29
30
  ITelemetryLoggerExt,
30
31
  ITelemetryPerformanceEventExt,
32
+ ITelemetryPropertiesExt,
31
33
  TelemetryEventPropertyTypeExt,
32
34
  } from "./telemetryTypes";
33
35
 
@@ -43,9 +45,13 @@ export interface PerformanceWithMemory extends IsomorphicPerformance {
43
45
  * Please do not modify existing entries for backwards compatibility.
44
46
  */
45
47
  export enum TelemetryDataTag {
46
- /** Data containing terms or IDs from code packages that may have been dynamically loaded */
48
+ /**
49
+ * Data containing terms or IDs from code packages that may have been dynamically loaded
50
+ */
47
51
  CodeArtifact = "CodeArtifact",
48
- /** Personal data of a variety of classifications that pertains to the user */
52
+ /**
53
+ * Personal data of a variety of classifications that pertains to the user
54
+ */
49
55
  UserData = "UserData",
50
56
  }
51
57
 
@@ -65,6 +71,7 @@ export interface ITelemetryLoggerPropertyBags {
65
71
  * Used to make telemetry data typed (and support math operations, like comparison),
66
72
  * in places where we do expect numbers (like contentsize/duration property in http header)
67
73
  */
74
+ // eslint-disable-next-line @rushstack/no-new-null
68
75
  export function numberFromString(str: string | null | undefined): string | number | undefined {
69
76
  if (str === undefined || str === null) {
70
77
  return undefined;
@@ -83,12 +90,11 @@ export const eventNamespaceSeparator = ":" as const;
83
90
  * TelemetryLogger class contains various helper telemetry methods,
84
91
  * encoding in one place schemas for various types of Fluid telemetry events.
85
92
  * Creates sub-logger that appends properties to all events
86
- *
87
93
  */
88
94
  export abstract class TelemetryLogger implements ITelemetryLoggerExt {
89
95
  public static readonly eventNamespaceSeparator = eventNamespaceSeparator;
90
96
 
91
- public static sanitizePkgName(name: string) {
97
+ public static sanitizePkgName(name: string): string {
92
98
  return name.replace("@", "").replace("/", "-");
93
99
  }
94
100
 
@@ -99,7 +105,11 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
99
105
  * @param error - Error to extract info from
100
106
  * @param fetchStack - Whether to fetch the current callstack if error.stack is undefined
101
107
  */
102
- public static prepareErrorObject(event: ITelemetryBaseEvent, error: any, fetchStack: boolean) {
108
+ public static prepareErrorObject(
109
+ event: ITelemetryBaseEvent,
110
+ error: unknown,
111
+ fetchStack: boolean,
112
+ ): void {
103
113
  const { message, errorType, stack } = extractLogSafeErrorProperties(
104
114
  error,
105
115
  true /* sanitizeStack */,
@@ -137,16 +147,26 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
137
147
  *
138
148
  * @param event - the event to send
139
149
  */
140
- public abstract send(event: ITelemetryBaseEvent): void;
150
+ public abstract send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void;
141
151
 
142
152
  /**
143
153
  * Send a telemetry event with the logger
144
154
  *
145
155
  * @param event - the event to send
146
156
  * @param error - optional error object to log
157
+ * @param logLevel - optional level of the log. It category of event is set as error,
158
+ * then the logLevel will be upgraded to be an error.
147
159
  */
148
- public sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: any) {
149
- this.sendTelemetryEventCore({ ...event, category: event.category ?? "generic" }, error);
160
+ public sendTelemetryEvent(
161
+ event: ITelemetryGenericEventExt,
162
+ error?: unknown,
163
+ logLevel: LogLevel.verbose | LogLevel.default = LogLevel.default,
164
+ ): void {
165
+ this.sendTelemetryEventCore(
166
+ { ...event, category: event.category ?? "generic" },
167
+ error,
168
+ event.category === "error" ? LogLevel.error : logLevel,
169
+ );
150
170
  }
151
171
 
152
172
  /**
@@ -154,11 +174,13 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
154
174
  *
155
175
  * @param event - the event to send
156
176
  * @param error - optional error object to log
177
+ * @param logLevel - optional level of the log.
157
178
  */
158
179
  protected sendTelemetryEventCore(
159
180
  event: ITelemetryGenericEventExt & { category: TelemetryEventCategory },
160
- error?: any,
161
- ) {
181
+ error?: unknown,
182
+ logLevel?: LogLevel,
183
+ ): void {
162
184
  const newEvent = convertToBaseEvent(event);
163
185
  if (error !== undefined) {
164
186
  TelemetryLogger.prepareErrorObject(newEvent, error, false);
@@ -169,7 +191,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
169
191
  newEvent.duration = formatTick(newEvent.duration);
170
192
  }
171
193
 
172
- this.send(newEvent);
194
+ this.send(newEvent, logLevel);
173
195
  }
174
196
 
175
197
  /**
@@ -178,7 +200,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
178
200
  * @param event - the event to send
179
201
  * @param error - optional error object to log
180
202
  */
181
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
203
+ public sendErrorEvent(event: ITelemetryErrorEvent, error?: unknown): void {
182
204
  this.sendTelemetryEventCore(
183
205
  {
184
206
  // ensure the error field has some value,
@@ -188,6 +210,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
188
210
  category: "error",
189
211
  },
190
212
  error,
213
+ LogLevel.error,
191
214
  );
192
215
  }
193
216
 
@@ -196,14 +219,24 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
196
219
  *
197
220
  * @param event - Event to send
198
221
  * @param error - optional error object to log
222
+ * @param logLevel - optional level of the log. It category of event is set as error,
223
+ * then the logLevel will be upgraded to be an error.
199
224
  */
200
- public sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: any): void {
225
+ public sendPerformanceEvent(
226
+ event: ITelemetryPerformanceEventExt,
227
+ error?: unknown,
228
+ logLevel: LogLevel.verbose | LogLevel.default = LogLevel.default,
229
+ ): void {
201
230
  const perfEvent = {
202
231
  ...event,
203
232
  category: event.category ?? "performance",
204
233
  };
205
234
 
206
- this.sendTelemetryEventCore(perfEvent, error);
235
+ this.sendTelemetryEventCore(
236
+ perfEvent,
237
+ error,
238
+ perfEvent.category === "error" ? LogLevel.error : logLevel,
239
+ );
207
240
  }
208
241
 
209
242
  protected prepareEvent(event: ITelemetryBaseEvent): ITelemetryBaseEvent {
@@ -220,7 +253,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
220
253
  private extendProperties<T extends ITelemetryLoggerPropertyBag = ITelemetryLoggerPropertyBag>(
221
254
  toExtend: T,
222
255
  includeErrorProps: boolean,
223
- ) {
256
+ ): T {
224
257
  const eventLike: ITelemetryLoggerPropertyBag = toExtend;
225
258
  if (this.properties) {
226
259
  const properties: (undefined | ITelemetryLoggerPropertyBag)[] = [];
@@ -257,7 +290,10 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
257
290
  export class TaggedLoggerAdapter implements ITelemetryBaseLogger {
258
291
  public constructor(private readonly logger: ITelemetryBaseLogger) {}
259
292
 
260
- public send(eventWithTagsMaybe: ITelemetryBaseEvent) {
293
+ /**
294
+ * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.send}
295
+ */
296
+ public send(eventWithTagsMaybe: ITelemetryBaseEvent): void {
261
297
  const newEvent: ITelemetryBaseEvent = {
262
298
  category: eventWithTagsMaybe.category,
263
299
  eventName: eventWithTagsMaybe.eventName,
@@ -368,7 +404,11 @@ export class ChildLogger extends TelemetryLogger {
368
404
  return child;
369
405
  }
370
406
 
371
- return new ChildLogger(baseLogger ? baseLogger : { send() {} }, namespace, properties);
407
+ return new ChildLogger(
408
+ baseLogger ? baseLogger : { send(): void {} },
409
+ namespace,
410
+ properties,
411
+ );
372
412
  }
373
413
 
374
414
  private constructor(
@@ -384,13 +424,23 @@ export class ChildLogger extends TelemetryLogger {
384
424
  }
385
425
  }
386
426
 
427
+ private shouldFilterOutEvent(event: ITelemetryPropertiesExt, logLevel?: LogLevel): boolean {
428
+ const eventLogLevel = logLevel ?? LogLevel.default;
429
+ const configLogLevel = this.baseLogger.minLogLevel ?? LogLevel.default;
430
+ // Filter out in case event log level is below what is wanted in config.
431
+ return eventLogLevel < configLogLevel;
432
+ }
433
+
387
434
  /**
388
435
  * Send an event with the logger
389
436
  *
390
437
  * @param event - the event to send
391
438
  */
392
- public send(event: ITelemetryBaseEvent): void {
393
- this.baseLogger.send(this.prepareEvent(event));
439
+ public send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void {
440
+ if (this.shouldFilterOutEvent(event, logLevel)) {
441
+ return;
442
+ }
443
+ this.baseLogger.send(this.prepareEvent(event), logLevel);
394
444
  }
395
445
  }
396
446
 
@@ -438,8 +488,11 @@ export class MultiSinkLogger extends TelemetryLogger {
438
488
  loggers
439
489
  .filter((l): l is this => l instanceof TelemetryLogger)
440
490
  .map((l) => l.properties ?? {})
491
+ // eslint-disable-next-line unicorn/no-array-for-each
441
492
  .forEach((cv) => {
493
+ // eslint-disable-next-line unicorn/no-array-for-each
442
494
  Object.keys(cv).forEach((k) => {
495
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
443
496
  merge[k] = { ...cv[k], ...merge?.[k] };
444
497
  });
445
498
  });
@@ -453,7 +506,7 @@ export class MultiSinkLogger extends TelemetryLogger {
453
506
  * Add logger to send all events to
454
507
  * @param logger - Logger to add
455
508
  */
456
- public addLogger(logger?: ITelemetryBaseLogger) {
509
+ public addLogger(logger?: ITelemetryBaseLogger): void {
457
510
  if (logger !== undefined && logger !== null) {
458
511
  this.loggers.push(logger);
459
512
  }
@@ -466,9 +519,9 @@ export class MultiSinkLogger extends TelemetryLogger {
466
519
  */
467
520
  public send(event: ITelemetryBaseEvent): void {
468
521
  const newEvent = this.prepareEvent(event);
469
- this.loggers.forEach((logger: ITelemetryBaseLogger) => {
522
+ for (const logger of this.loggers) {
470
523
  logger.send(newEvent);
471
- });
524
+ }
472
525
  }
473
526
  }
474
527
 
@@ -493,7 +546,7 @@ export class PerformanceEvent {
493
546
  event: ITelemetryGenericEvent,
494
547
  markers?: IPerformanceEventMarkers,
495
548
  recordHeapSize: boolean = false,
496
- ) {
549
+ ): PerformanceEvent {
497
550
  return new PerformanceEvent(logger, event, markers, recordHeapSize);
498
551
  }
499
552
 
@@ -502,7 +555,7 @@ export class PerformanceEvent {
502
555
  event: ITelemetryGenericEvent,
503
556
  callback: (event: PerformanceEvent) => T,
504
557
  markers?: IPerformanceEventMarkers,
505
- ) {
558
+ ): T {
506
559
  const perfEvent = PerformanceEvent.start(logger, event, markers);
507
560
  try {
508
561
  const ret = callback(perfEvent);
@@ -520,7 +573,7 @@ export class PerformanceEvent {
520
573
  callback: (event: PerformanceEvent) => Promise<T>,
521
574
  markers?: IPerformanceEventMarkers,
522
575
  recordHeapSize?: boolean,
523
- ) {
576
+ ): Promise<T> {
524
577
  const perfEvent = PerformanceEvent.start(logger, event, markers, recordHeapSize);
525
578
  try {
526
579
  const ret = await callback(perfEvent);
@@ -532,7 +585,7 @@ export class PerformanceEvent {
532
585
  }
533
586
  }
534
587
 
535
- public get duration() {
588
+ public get duration(): number {
536
589
  return performance.now() - this.startTime;
537
590
  }
538
591
 
@@ -552,6 +605,7 @@ export class PerformanceEvent {
552
605
  this.reportEvent("start");
553
606
  }
554
607
 
608
+ // eslint-disable-next-line unicorn/no-null
555
609
  if (typeof window === "object" && window != null && window.performance?.mark) {
556
610
  this.startMark = `${event.eventName}-start`;
557
611
  window.performance.mark(this.startMark);
@@ -562,7 +616,7 @@ export class PerformanceEvent {
562
616
  this.reportEvent(eventNameSuffix, props);
563
617
  }
564
618
 
565
- private autoEnd() {
619
+ private autoEnd(): void {
566
620
  // Event might have been cancelled or ended in the callback
567
621
  if (this.event && this.markers.end) {
568
622
  this.reportEvent("end");
@@ -577,7 +631,7 @@ export class PerformanceEvent {
577
631
  this.event = undefined;
578
632
  }
579
633
 
580
- private performanceEndMark() {
634
+ private performanceEndMark(): void {
581
635
  if (this.startMark && this.event) {
582
636
  const endMark = `${this.event.eventName}-end`;
583
637
  window.performance.mark(endMark);
@@ -586,7 +640,7 @@ export class PerformanceEvent {
586
640
  }
587
641
  }
588
642
 
589
- public cancel(props?: ITelemetryProperties, error?: any): void {
643
+ public cancel(props?: ITelemetryProperties, error?: unknown): void {
590
644
  if (this.markers.cancel !== undefined) {
591
645
  this.reportEvent("cancel", { category: this.markers.cancel, ...props }, error);
592
646
  }
@@ -596,7 +650,11 @@ export class PerformanceEvent {
596
650
  /**
597
651
  * Report the event, if it hasn't already been reported.
598
652
  */
599
- public reportEvent(eventNameSuffix: string, props?: ITelemetryProperties, error?: any) {
653
+ public reportEvent(
654
+ eventNameSuffix: string,
655
+ props?: ITelemetryProperties,
656
+ error?: unknown,
657
+ ): void {
600
658
  // There are strange sequences involving multiple Promise chains
601
659
  // where the event can be cancelled and then later a callback is invoked
602
660
  // and the caller attempts to end directly, e.g. issue #3936. Just return.
@@ -637,9 +695,9 @@ export class PerformanceEvent {
637
695
  */
638
696
  export class TelemetryNullLogger implements ITelemetryLoggerExt {
639
697
  public send(event: ITelemetryBaseEvent): void {}
640
- public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any): void {}
641
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any): void {}
642
- public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: any): void {}
698
+ public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: unknown): void {}
699
+ public sendErrorEvent(event: ITelemetryErrorEvent, error?: unknown): void {}
700
+ public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: unknown): void {}
643
701
  }
644
702
 
645
703
  /**
@@ -706,9 +764,17 @@ export const tagData = <
706
764
  >(
707
765
  tag: T,
708
766
  values: V,
709
- ) =>
767
+ ): {
768
+ [P in keyof V]:
769
+ | {
770
+ value: Exclude<V[P], undefined>;
771
+ tag: T;
772
+ }
773
+ | (V[P] extends undefined ? undefined : never);
774
+ } =>
710
775
  (Object.entries(values) as [keyof V, V[keyof V]][])
711
776
  .filter((e): e is [keyof V, Exclude<V[keyof V], undefined>] => e[1] !== undefined)
777
+ // eslint-disable-next-line unicorn/no-array-reduce
712
778
  .reduce<{
713
779
  [P in keyof V]:
714
780
  | (V[P] extends undefined ? undefined : never)
@@ -716,8 +782,16 @@ export const tagData = <
716
782
  }>((pv, cv) => {
717
783
  pv[cv[0]] = { tag, value: cv[1] };
718
784
  return pv;
785
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
719
786
  }, {} as any);
720
787
 
721
788
  export const tagCodeArtifacts = <T extends Record<string, TelemetryEventPropertyTypeExt>>(
722
789
  values: T,
723
- ) => tagData(TelemetryDataTag.CodeArtifact, values);
790
+ ): {
791
+ [P in keyof T]:
792
+ | {
793
+ value: Exclude<T[P], undefined>;
794
+ tag: TelemetryDataTag.CodeArtifact;
795
+ }
796
+ | (T[P] extends undefined ? undefined : never);
797
+ } => tagData(TelemetryDataTag.CodeArtifact, values);
package/src/mockLogger.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { ITelemetryBaseEvent, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
7
7
  import { assert } from "@fluidframework/common-utils";
8
- import { ITelemetryPropertiesExt } from "./telemetryTypes";
8
+ import { ITelemetryLoggerExt, ITelemetryPropertiesExt } from "./telemetryTypes";
9
9
  import { createChildLogger } from "./logger";
10
10
 
11
11
  /**
@@ -15,11 +15,11 @@ import { createChildLogger } from "./logger";
15
15
  export class MockLogger implements ITelemetryBaseLogger {
16
16
  events: ITelemetryBaseEvent[] = [];
17
17
 
18
- clear() {
18
+ clear(): void {
19
19
  this.events = [];
20
20
  }
21
21
 
22
- toTelemetryLogger() {
22
+ toTelemetryLogger(): ITelemetryLoggerExt {
23
23
  return createChildLogger({ logger: this });
24
24
  }
25
25
 
@@ -48,12 +48,14 @@ export class MockLogger implements ITelemetryBaseLogger {
48
48
  return unmatchedExpectedEventCount === 0;
49
49
  }
50
50
 
51
- /** Asserts that matchEvents is true, and prints the actual/expected output if not */
51
+ /**
52
+ * Asserts that matchEvents is true, and prints the actual/expected output if not.
53
+ */
52
54
  assertMatch(
53
55
  expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
54
56
  message?: string,
55
57
  inlineDetailsProp: boolean = false,
56
- ) {
58
+ ): void {
57
59
  const actualEvents = this.events;
58
60
  if (!this.matchEvents(expectedEvents, inlineDetailsProp)) {
59
61
  throw new Error(`${message}
@@ -85,12 +87,14 @@ ${JSON.stringify(actualEvents)}`);
85
87
  return matchedExpectedEventCount > 0;
86
88
  }
87
89
 
88
- /** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */
90
+ /**
91
+ * Asserts that matchAnyEvent is true, and prints the actual/expected output if not.
92
+ */
89
93
  assertMatchAny(
90
94
  expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
91
95
  message?: string,
92
96
  inlineDetailsProp: boolean = false,
93
- ) {
97
+ ): void {
94
98
  const actualEvents = this.events;
95
99
  if (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {
96
100
  throw new Error(`${message}
@@ -120,12 +124,14 @@ ${JSON.stringify(actualEvents)}`);
120
124
  );
121
125
  }
122
126
 
123
- /** Asserts that matchEvents is true, and prints the actual/expected output if not */
127
+ /**
128
+ * Asserts that matchEvents is true, and prints the actual/expected output if not
129
+ */
124
130
  assertMatchStrict(
125
131
  expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
126
132
  message?: string,
127
133
  inlineDetailsProp: boolean = false,
128
- ) {
134
+ ): void {
129
135
  const actualEvents = this.events;
130
136
  if (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {
131
137
  throw new Error(`${message}
@@ -137,12 +143,14 @@ ${JSON.stringify(actualEvents)}`);
137
143
  }
138
144
  }
139
145
 
140
- /** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
146
+ /**
147
+ * Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not
148
+ */
141
149
  assertMatchNone(
142
150
  disallowedEvents: Omit<ITelemetryBaseEvent, "category">[],
143
151
  message?: string,
144
152
  inlineDetailsProp: boolean = false,
145
- ) {
153
+ ): void {
146
154
  const actualEvents = this.events;
147
155
  if (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {
148
156
  throw new Error(`${message}
@@ -159,7 +167,7 @@ ${JSON.stringify(actualEvents)}`);
159
167
  inlineDetailsProp: boolean,
160
168
  ): number {
161
169
  let iExpectedEvent = 0;
162
- this.events.forEach((event) => {
170
+ for (const event of this.events) {
163
171
  if (
164
172
  iExpectedEvent < expectedEvents.length &&
165
173
  MockLogger.eventsMatch(event, expectedEvents[iExpectedEvent], inlineDetailsProp)
@@ -167,7 +175,7 @@ ${JSON.stringify(actualEvents)}`);
167
175
  // We found the next expected event; increment
168
176
  ++iExpectedEvent;
169
177
  }
170
- });
178
+ }
171
179
 
172
180
  // Remove the events so far; next call will just compare subsequent events from here
173
181
  this.events = [];
@@ -191,16 +199,19 @@ ${JSON.stringify(actualEvents)}`);
191
199
  if (inlineDetailsProp && details !== undefined) {
192
200
  assert(
193
201
  typeof details === "string",
202
+ // eslint-disable-next-line unicorn/numeric-separators-style
194
203
  0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,
195
204
  );
205
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
196
206
  const detailsExpanded = JSON.parse(details);
207
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
197
208
  return matchObjects({ ...actualForMatching, ...detailsExpanded }, expected);
198
209
  }
199
210
  return matchObjects(actual, expected);
200
211
  }
201
212
  }
202
213
 
203
- function matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPropertiesExt) {
214
+ function matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPropertiesExt): boolean {
204
215
  for (const [expectedKey, expectedValue] of Object.entries(expected)) {
205
216
  const actualValue = actual[expectedKey];
206
217
  if (