@fluidframework/telemetry-utils 2.0.0-internal.6.1.1 → 2.0.0-internal.6.3.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 +59 -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 +34 -18
  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 +3 -3
  16. package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
  17. package/dist/eventEmitterWithErrorHandling.js +10 -3
  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 +2 -1
  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 +38 -22
  31. package/dist/logger.d.ts.map +1 -1
  32. package/dist/logger.js +68 -21
  33. package/dist/logger.js.map +1 -1
  34. package/dist/mockLogger.d.ts +17 -6
  35. package/dist/mockLogger.d.ts.map +1 -1
  36. package/dist/mockLogger.js +22 -9
  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 +13 -11
  41. package/dist/sampledTelemetryHelper.js.map +1 -1
  42. package/dist/telemetryTypes.d.ts +20 -6
  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 +34 -18
  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 +3 -3
  62. package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
  63. package/lib/eventEmitterWithErrorHandling.js +9 -2
  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 +2 -1
  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 +38 -22
  77. package/lib/logger.d.ts.map +1 -1
  78. package/lib/logger.js +64 -17
  79. package/lib/logger.js.map +1 -1
  80. package/lib/mockLogger.d.ts +17 -6
  81. package/lib/mockLogger.d.ts.map +1 -1
  82. package/lib/mockLogger.js +22 -9
  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 +11 -9
  87. package/lib/sampledTelemetryHelper.js.map +1 -1
  88. package/lib/telemetryTypes.d.ts +20 -6
  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 +15 -18
  97. package/src/config.ts +12 -7
  98. package/src/error.ts +202 -0
  99. package/src/errorLogging.ts +90 -52
  100. package/src/eventEmitterWithErrorHandling.ts +5 -3
  101. package/src/events.ts +3 -3
  102. package/src/fluidErrorBase.ts +62 -26
  103. package/src/index.ts +8 -0
  104. package/src/logger.ts +143 -45
  105. package/src/mockLogger.ts +33 -16
  106. package/src/sampledTelemetryHelper.ts +18 -14
  107. package/src/telemetryTypes.ts +29 -6
  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,
@@ -70,4 +77,5 @@ export {
70
77
  ITelemetryLoggerExt,
71
78
  ITaggedTelemetryPropertyTypeExt,
72
79
  ITelemetryPropertiesExt,
80
+ TelemetryEventCategory,
73
81
  } from "./telemetryTypes";
package/src/logger.ts CHANGED
@@ -10,11 +10,12 @@ import {
10
10
  ITelemetryGenericEvent,
11
11
  ITelemetryPerformanceEvent,
12
12
  ITelemetryProperties,
13
- TelemetryEventPropertyType,
14
- ITaggedTelemetryPropertyType,
15
- TelemetryEventCategory,
13
+ TelemetryBaseEventPropertyType as TelemetryEventPropertyType,
14
+ LogLevel,
15
+ Tagged,
16
+ ITelemetryBaseProperties,
16
17
  } from "@fluidframework/core-interfaces";
17
- import { IsomorphicPerformance, performance } from "@fluidframework/common-utils";
18
+ import { IsomorphicPerformance, performance } from "@fluid-internal/client-utils";
18
19
  import { CachedConfigProvider, loggerIsMonitoringContext, mixinMonitoringContext } from "./config";
19
20
  import {
20
21
  isILoggingError,
@@ -23,12 +24,12 @@ import {
23
24
  isTaggedTelemetryPropertyValue,
24
25
  } from "./errorLogging";
25
26
  import {
26
- ITaggedTelemetryPropertyTypeExt,
27
27
  ITelemetryEventExt,
28
28
  ITelemetryGenericEventExt,
29
29
  ITelemetryLoggerExt,
30
30
  ITelemetryPerformanceEventExt,
31
31
  TelemetryEventPropertyTypeExt,
32
+ TelemetryEventCategory,
32
33
  } from "./telemetryTypes";
33
34
 
34
35
  export interface Memory {
@@ -43,13 +44,17 @@ export interface PerformanceWithMemory extends IsomorphicPerformance {
43
44
  * Please do not modify existing entries for backwards compatibility.
44
45
  */
45
46
  export enum TelemetryDataTag {
46
- /** Data containing terms or IDs from code packages that may have been dynamically loaded */
47
+ /**
48
+ * Data containing terms or IDs from code packages that may have been dynamically loaded
49
+ */
47
50
  CodeArtifact = "CodeArtifact",
48
- /** Personal data of a variety of classifications that pertains to the user */
51
+ /**
52
+ * Personal data of a variety of classifications that pertains to the user
53
+ */
49
54
  UserData = "UserData",
50
55
  }
51
56
 
52
- export type TelemetryEventPropertyTypes = TelemetryEventPropertyType | ITaggedTelemetryPropertyType;
57
+ export type TelemetryEventPropertyTypes = ITelemetryBaseProperties[string];
53
58
 
54
59
  export interface ITelemetryLoggerPropertyBag {
55
60
  [index: string]: TelemetryEventPropertyTypes | (() => TelemetryEventPropertyTypes);
@@ -65,6 +70,7 @@ export interface ITelemetryLoggerPropertyBags {
65
70
  * Used to make telemetry data typed (and support math operations, like comparison),
66
71
  * in places where we do expect numbers (like contentsize/duration property in http header)
67
72
  */
73
+ // eslint-disable-next-line @rushstack/no-new-null
68
74
  export function numberFromString(str: string | null | undefined): string | number | undefined {
69
75
  if (str === undefined || str === null) {
70
76
  return undefined;
@@ -83,12 +89,11 @@ export const eventNamespaceSeparator = ":" as const;
83
89
  * TelemetryLogger class contains various helper telemetry methods,
84
90
  * encoding in one place schemas for various types of Fluid telemetry events.
85
91
  * Creates sub-logger that appends properties to all events
86
- *
87
92
  */
88
93
  export abstract class TelemetryLogger implements ITelemetryLoggerExt {
89
94
  public static readonly eventNamespaceSeparator = eventNamespaceSeparator;
90
95
 
91
- public static sanitizePkgName(name: string) {
96
+ public static sanitizePkgName(name: string): string {
92
97
  return name.replace("@", "").replace("/", "-");
93
98
  }
94
99
 
@@ -99,7 +104,11 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
99
104
  * @param error - Error to extract info from
100
105
  * @param fetchStack - Whether to fetch the current callstack if error.stack is undefined
101
106
  */
102
- public static prepareErrorObject(event: ITelemetryBaseEvent, error: any, fetchStack: boolean) {
107
+ public static prepareErrorObject(
108
+ event: ITelemetryBaseEvent,
109
+ error: unknown,
110
+ fetchStack: boolean,
111
+ ): void {
103
112
  const { message, errorType, stack } = extractLogSafeErrorProperties(
104
113
  error,
105
114
  true /* sanitizeStack */,
@@ -137,16 +146,26 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
137
146
  *
138
147
  * @param event - the event to send
139
148
  */
140
- public abstract send(event: ITelemetryBaseEvent): void;
149
+ public abstract send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void;
141
150
 
142
151
  /**
143
152
  * Send a telemetry event with the logger
144
153
  *
145
154
  * @param event - the event to send
146
155
  * @param error - optional error object to log
156
+ * @param logLevel - optional level of the log. It category of event is set as error,
157
+ * then the logLevel will be upgraded to be an error.
147
158
  */
148
- public sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: any) {
149
- this.sendTelemetryEventCore({ ...event, category: event.category ?? "generic" }, error);
159
+ public sendTelemetryEvent(
160
+ event: ITelemetryGenericEventExt,
161
+ error?: unknown,
162
+ logLevel: typeof LogLevel.verbose | typeof LogLevel.default = LogLevel.default,
163
+ ): void {
164
+ this.sendTelemetryEventCore(
165
+ { ...event, category: event.category ?? "generic" },
166
+ error,
167
+ event.category === "error" ? LogLevel.error : logLevel,
168
+ );
150
169
  }
151
170
 
152
171
  /**
@@ -154,11 +173,13 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
154
173
  *
155
174
  * @param event - the event to send
156
175
  * @param error - optional error object to log
176
+ * @param logLevel - optional level of the log.
157
177
  */
158
178
  protected sendTelemetryEventCore(
159
179
  event: ITelemetryGenericEventExt & { category: TelemetryEventCategory },
160
- error?: any,
161
- ) {
180
+ error?: unknown,
181
+ logLevel?: LogLevel,
182
+ ): void {
162
183
  const newEvent = convertToBaseEvent(event);
163
184
  if (error !== undefined) {
164
185
  TelemetryLogger.prepareErrorObject(newEvent, error, false);
@@ -169,7 +190,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
169
190
  newEvent.duration = formatTick(newEvent.duration);
170
191
  }
171
192
 
172
- this.send(newEvent);
193
+ this.send(newEvent, logLevel);
173
194
  }
174
195
 
175
196
  /**
@@ -178,7 +199,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
178
199
  * @param event - the event to send
179
200
  * @param error - optional error object to log
180
201
  */
181
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
202
+ public sendErrorEvent(event: ITelemetryErrorEvent, error?: unknown): void {
182
203
  this.sendTelemetryEventCore(
183
204
  {
184
205
  // ensure the error field has some value,
@@ -188,6 +209,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
188
209
  category: "error",
189
210
  },
190
211
  error,
212
+ LogLevel.error,
191
213
  );
192
214
  }
193
215
 
@@ -196,14 +218,24 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
196
218
  *
197
219
  * @param event - Event to send
198
220
  * @param error - optional error object to log
221
+ * @param logLevel - optional level of the log. It category of event is set as error,
222
+ * then the logLevel will be upgraded to be an error.
199
223
  */
200
- public sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: any): void {
224
+ public sendPerformanceEvent(
225
+ event: ITelemetryPerformanceEventExt,
226
+ error?: unknown,
227
+ logLevel: typeof LogLevel.verbose | typeof LogLevel.default = LogLevel.default,
228
+ ): void {
201
229
  const perfEvent = {
202
230
  ...event,
203
231
  category: event.category ?? "performance",
204
232
  };
205
233
 
206
- this.sendTelemetryEventCore(perfEvent, error);
234
+ this.sendTelemetryEventCore(
235
+ perfEvent,
236
+ error,
237
+ perfEvent.category === "error" ? LogLevel.error : logLevel,
238
+ );
207
239
  }
208
240
 
209
241
  protected prepareEvent(event: ITelemetryBaseEvent): ITelemetryBaseEvent {
@@ -220,7 +252,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
220
252
  private extendProperties<T extends ITelemetryLoggerPropertyBag = ITelemetryLoggerPropertyBag>(
221
253
  toExtend: T,
222
254
  includeErrorProps: boolean,
223
- ) {
255
+ ): T {
224
256
  const eventLike: ITelemetryLoggerPropertyBag = toExtend;
225
257
  if (this.properties) {
226
258
  const properties: (undefined | ITelemetryLoggerPropertyBag)[] = [];
@@ -257,7 +289,10 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
257
289
  export class TaggedLoggerAdapter implements ITelemetryBaseLogger {
258
290
  public constructor(private readonly logger: ITelemetryBaseLogger) {}
259
291
 
260
- public send(eventWithTagsMaybe: ITelemetryBaseEvent) {
292
+ /**
293
+ * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.send}
294
+ */
295
+ public send(eventWithTagsMaybe: ITelemetryBaseEvent): void {
261
296
  const newEvent: ITelemetryBaseEvent = {
262
297
  category: eventWithTagsMaybe.category,
263
298
  eventName: eventWithTagsMaybe.eventName,
@@ -368,7 +403,11 @@ export class ChildLogger extends TelemetryLogger {
368
403
  return child;
369
404
  }
370
405
 
371
- return new ChildLogger(baseLogger ? baseLogger : { send() {} }, namespace, properties);
406
+ return new ChildLogger(
407
+ baseLogger ? baseLogger : { send(): void {} },
408
+ namespace,
409
+ properties,
410
+ );
372
411
  }
373
412
 
374
413
  private constructor(
@@ -384,13 +423,27 @@ export class ChildLogger extends TelemetryLogger {
384
423
  }
385
424
  }
386
425
 
426
+ public get minLogLevel(): LogLevel | undefined {
427
+ return this.baseLogger.minLogLevel;
428
+ }
429
+
430
+ private shouldFilterOutEvent(event: ITelemetryBaseEvent, logLevel?: LogLevel): boolean {
431
+ const eventLogLevel = logLevel ?? LogLevel.default;
432
+ const configLogLevel = this.baseLogger.minLogLevel ?? LogLevel.default;
433
+ // Filter out in case event log level is below what is wanted in config.
434
+ return eventLogLevel < configLogLevel;
435
+ }
436
+
387
437
  /**
388
438
  * Send an event with the logger
389
439
  *
390
440
  * @param event - the event to send
391
441
  */
392
- public send(event: ITelemetryBaseEvent): void {
393
- this.baseLogger.send(this.prepareEvent(event));
442
+ public send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void {
443
+ if (this.shouldFilterOutEvent(event, logLevel)) {
444
+ return;
445
+ }
446
+ this.baseLogger.send(this.prepareEvent(event), logLevel);
394
447
  }
395
448
  }
396
449
 
@@ -419,6 +472,9 @@ export function createMultiSinkLogger(props: {
419
472
  */
420
473
  export class MultiSinkLogger extends TelemetryLogger {
421
474
  protected loggers: ITelemetryBaseLogger[];
475
+ // This is minimum of minLlogLevel of all loggers.
476
+ private _minLogLevelOfAllLoggers: LogLevel;
477
+
422
478
  /**
423
479
  * Create multiple sink logger (i.e. logger that sends events to multiple sinks)
424
480
  * @param namespace - Telemetry event name prefix to add to all events
@@ -438,8 +494,11 @@ export class MultiSinkLogger extends TelemetryLogger {
438
494
  loggers
439
495
  .filter((l): l is this => l instanceof TelemetryLogger)
440
496
  .map((l) => l.properties ?? {})
497
+ // eslint-disable-next-line unicorn/no-array-for-each
441
498
  .forEach((cv) => {
499
+ // eslint-disable-next-line unicorn/no-array-for-each
442
500
  Object.keys(cv).forEach((k) => {
501
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
443
502
  merge[k] = { ...cv[k], ...merge?.[k] };
444
503
  });
445
504
  });
@@ -447,15 +506,33 @@ export class MultiSinkLogger extends TelemetryLogger {
447
506
 
448
507
  super(namespace, realProperties);
449
508
  this.loggers = loggers;
509
+ this._minLogLevelOfAllLoggers = LogLevel.default;
510
+ this.calculateMinLogLevel();
511
+ }
512
+
513
+ public get minLogLevel(): LogLevel {
514
+ return this._minLogLevelOfAllLoggers;
515
+ }
516
+
517
+ private calculateMinLogLevel(): void {
518
+ if (this.loggers.length > 0) {
519
+ const logLevels: LogLevel[] = [];
520
+ for (const logger of this.loggers) {
521
+ logLevels.push(logger.minLogLevel ?? LogLevel.default);
522
+ }
523
+ this._minLogLevelOfAllLoggers = Math.min(...logLevels) as LogLevel;
524
+ }
450
525
  }
451
526
 
452
527
  /**
453
528
  * Add logger to send all events to
454
529
  * @param logger - Logger to add
455
530
  */
456
- public addLogger(logger?: ITelemetryBaseLogger) {
531
+ public addLogger(logger?: ITelemetryBaseLogger): void {
457
532
  if (logger !== undefined && logger !== null) {
458
533
  this.loggers.push(logger);
534
+ // Update in case the logLevel of added logger is less than the current.
535
+ this.calculateMinLogLevel();
459
536
  }
460
537
  }
461
538
 
@@ -466,9 +543,9 @@ export class MultiSinkLogger extends TelemetryLogger {
466
543
  */
467
544
  public send(event: ITelemetryBaseEvent): void {
468
545
  const newEvent = this.prepareEvent(event);
469
- this.loggers.forEach((logger: ITelemetryBaseLogger) => {
546
+ for (const logger of this.loggers) {
470
547
  logger.send(newEvent);
471
- });
548
+ }
472
549
  }
473
550
  }
474
551
 
@@ -493,7 +570,7 @@ export class PerformanceEvent {
493
570
  event: ITelemetryGenericEvent,
494
571
  markers?: IPerformanceEventMarkers,
495
572
  recordHeapSize: boolean = false,
496
- ) {
573
+ ): PerformanceEvent {
497
574
  return new PerformanceEvent(logger, event, markers, recordHeapSize);
498
575
  }
499
576
 
@@ -502,7 +579,7 @@ export class PerformanceEvent {
502
579
  event: ITelemetryGenericEvent,
503
580
  callback: (event: PerformanceEvent) => T,
504
581
  markers?: IPerformanceEventMarkers,
505
- ) {
582
+ ): T {
506
583
  const perfEvent = PerformanceEvent.start(logger, event, markers);
507
584
  try {
508
585
  const ret = callback(perfEvent);
@@ -520,7 +597,7 @@ export class PerformanceEvent {
520
597
  callback: (event: PerformanceEvent) => Promise<T>,
521
598
  markers?: IPerformanceEventMarkers,
522
599
  recordHeapSize?: boolean,
523
- ) {
600
+ ): Promise<T> {
524
601
  const perfEvent = PerformanceEvent.start(logger, event, markers, recordHeapSize);
525
602
  try {
526
603
  const ret = await callback(perfEvent);
@@ -532,7 +609,7 @@ export class PerformanceEvent {
532
609
  }
533
610
  }
534
611
 
535
- public get duration() {
612
+ public get duration(): number {
536
613
  return performance.now() - this.startTime;
537
614
  }
538
615
 
@@ -552,6 +629,7 @@ export class PerformanceEvent {
552
629
  this.reportEvent("start");
553
630
  }
554
631
 
632
+ // eslint-disable-next-line unicorn/no-null
555
633
  if (typeof window === "object" && window != null && window.performance?.mark) {
556
634
  this.startMark = `${event.eventName}-start`;
557
635
  window.performance.mark(this.startMark);
@@ -562,7 +640,7 @@ export class PerformanceEvent {
562
640
  this.reportEvent(eventNameSuffix, props);
563
641
  }
564
642
 
565
- private autoEnd() {
643
+ private autoEnd(): void {
566
644
  // Event might have been cancelled or ended in the callback
567
645
  if (this.event && this.markers.end) {
568
646
  this.reportEvent("end");
@@ -577,7 +655,7 @@ export class PerformanceEvent {
577
655
  this.event = undefined;
578
656
  }
579
657
 
580
- private performanceEndMark() {
658
+ private performanceEndMark(): void {
581
659
  if (this.startMark && this.event) {
582
660
  const endMark = `${this.event.eventName}-end`;
583
661
  window.performance.mark(endMark);
@@ -586,7 +664,7 @@ export class PerformanceEvent {
586
664
  }
587
665
  }
588
666
 
589
- public cancel(props?: ITelemetryProperties, error?: any): void {
667
+ public cancel(props?: ITelemetryProperties, error?: unknown): void {
590
668
  if (this.markers.cancel !== undefined) {
591
669
  this.reportEvent("cancel", { category: this.markers.cancel, ...props }, error);
592
670
  }
@@ -596,7 +674,11 @@ export class PerformanceEvent {
596
674
  /**
597
675
  * Report the event, if it hasn't already been reported.
598
676
  */
599
- public reportEvent(eventNameSuffix: string, props?: ITelemetryProperties, error?: any) {
677
+ public reportEvent(
678
+ eventNameSuffix: string,
679
+ props?: ITelemetryProperties,
680
+ error?: unknown,
681
+ ): void {
600
682
  // There are strange sequences involving multiple Promise chains
601
683
  // where the event can be cancelled and then later a callback is invoked
602
684
  // and the caller attempts to end directly, e.g. issue #3936. Just return.
@@ -637,9 +719,9 @@ export class PerformanceEvent {
637
719
  */
638
720
  export class TelemetryNullLogger implements ITelemetryLoggerExt {
639
721
  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 {}
722
+ public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: unknown): void {}
723
+ public sendErrorEvent(event: ITelemetryErrorEvent, error?: unknown): void {}
724
+ public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: unknown): void {}
643
725
  }
644
726
 
645
727
  /**
@@ -662,15 +744,15 @@ function convertToBaseEvent({
662
744
  /**
663
745
  * Takes in value, and does one of 4 things.
664
746
  * if value is of primitive type - returns the original value.
665
- * If the value is an array of primitives - returns a stringified version of the array.
666
- * If the value is an object of type ITaggedTelemetryPropertyType - returns the object
747
+ * If the value is a flat array or object - returns a stringified version of the array/object.
748
+ * If the value is an object of type Tagged<TelemetryEventPropertyType> - returns the object
667
749
  * with its values recursively converted to base property Type.
668
750
  * If none of these cases are reached - returns an error string
669
751
  * @param x - value passed in to convert to a base property type
670
752
  */
671
753
  export function convertToBasePropertyType(
672
- x: TelemetryEventPropertyTypeExt | ITaggedTelemetryPropertyTypeExt,
673
- ): TelemetryEventPropertyType | ITaggedTelemetryPropertyType {
754
+ x: TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>,
755
+ ): TelemetryEventPropertyType | Tagged<TelemetryEventPropertyType> {
674
756
  return isTaggedTelemetryPropertyValue(x)
675
757
  ? {
676
758
  value: convertToBasePropertyTypeUntagged(x.value),
@@ -706,9 +788,17 @@ export const tagData = <
706
788
  >(
707
789
  tag: T,
708
790
  values: V,
709
- ) =>
791
+ ): {
792
+ [P in keyof V]:
793
+ | {
794
+ value: Exclude<V[P], undefined>;
795
+ tag: T;
796
+ }
797
+ | (V[P] extends undefined ? undefined : never);
798
+ } =>
710
799
  (Object.entries(values) as [keyof V, V[keyof V]][])
711
800
  .filter((e): e is [keyof V, Exclude<V[keyof V], undefined>] => e[1] !== undefined)
801
+ // eslint-disable-next-line unicorn/no-array-reduce
712
802
  .reduce<{
713
803
  [P in keyof V]:
714
804
  | (V[P] extends undefined ? undefined : never)
@@ -716,8 +806,16 @@ export const tagData = <
716
806
  }>((pv, cv) => {
717
807
  pv[cv[0]] = { tag, value: cv[1] };
718
808
  return pv;
809
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
719
810
  }, {} as any);
720
811
 
721
812
  export const tagCodeArtifacts = <T extends Record<string, TelemetryEventPropertyTypeExt>>(
722
813
  values: T,
723
- ) => tagData(TelemetryDataTag.CodeArtifact, values);
814
+ ): {
815
+ [P in keyof T]:
816
+ | {
817
+ value: Exclude<T[P], undefined>;
818
+ tag: TelemetryDataTag.CodeArtifact;
819
+ }
820
+ | (T[P] extends undefined ? undefined : never);
821
+ } => tagData(TelemetryDataTag.CodeArtifact, values);