@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
package/src/mockLogger.ts CHANGED
@@ -3,9 +3,13 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryBaseEvent, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
7
- import { assert } from "@fluidframework/common-utils";
8
- import { ITelemetryPropertiesExt } from "./telemetryTypes";
6
+ import {
7
+ ITelemetryBaseEvent,
8
+ ITelemetryBaseLogger,
9
+ LogLevel,
10
+ } from "@fluidframework/core-interfaces";
11
+ import { assert } from "@fluidframework/core-utils";
12
+ import { ITelemetryLoggerExt, ITelemetryPropertiesExt } from "./telemetryTypes";
9
13
  import { createChildLogger } from "./logger";
10
14
 
11
15
  /**
@@ -15,11 +19,13 @@ import { createChildLogger } from "./logger";
15
19
  export class MockLogger implements ITelemetryBaseLogger {
16
20
  events: ITelemetryBaseEvent[] = [];
17
21
 
18
- clear() {
22
+ constructor(public readonly minLogLevel?: LogLevel) {}
23
+
24
+ clear(): void {
19
25
  this.events = [];
20
26
  }
21
27
 
22
- toTelemetryLogger() {
28
+ toTelemetryLogger(): ITelemetryLoggerExt {
23
29
  return createChildLogger({ logger: this });
24
30
  }
25
31
 
@@ -48,12 +54,14 @@ export class MockLogger implements ITelemetryBaseLogger {
48
54
  return unmatchedExpectedEventCount === 0;
49
55
  }
50
56
 
51
- /** Asserts that matchEvents is true, and prints the actual/expected output if not */
57
+ /**
58
+ * Asserts that matchEvents is true, and prints the actual/expected output if not.
59
+ */
52
60
  assertMatch(
53
61
  expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
54
62
  message?: string,
55
63
  inlineDetailsProp: boolean = false,
56
- ) {
64
+ ): void {
57
65
  const actualEvents = this.events;
58
66
  if (!this.matchEvents(expectedEvents, inlineDetailsProp)) {
59
67
  throw new Error(`${message}
@@ -85,12 +93,14 @@ ${JSON.stringify(actualEvents)}`);
85
93
  return matchedExpectedEventCount > 0;
86
94
  }
87
95
 
88
- /** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */
96
+ /**
97
+ * Asserts that matchAnyEvent is true, and prints the actual/expected output if not.
98
+ */
89
99
  assertMatchAny(
90
100
  expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
91
101
  message?: string,
92
102
  inlineDetailsProp: boolean = false,
93
- ) {
103
+ ): void {
94
104
  const actualEvents = this.events;
95
105
  if (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {
96
106
  throw new Error(`${message}
@@ -120,12 +130,14 @@ ${JSON.stringify(actualEvents)}`);
120
130
  );
121
131
  }
122
132
 
123
- /** Asserts that matchEvents is true, and prints the actual/expected output if not */
133
+ /**
134
+ * Asserts that matchEvents is true, and prints the actual/expected output if not
135
+ */
124
136
  assertMatchStrict(
125
137
  expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
126
138
  message?: string,
127
139
  inlineDetailsProp: boolean = false,
128
- ) {
140
+ ): void {
129
141
  const actualEvents = this.events;
130
142
  if (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {
131
143
  throw new Error(`${message}
@@ -137,12 +149,14 @@ ${JSON.stringify(actualEvents)}`);
137
149
  }
138
150
  }
139
151
 
140
- /** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */
152
+ /**
153
+ * Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not
154
+ */
141
155
  assertMatchNone(
142
156
  disallowedEvents: Omit<ITelemetryBaseEvent, "category">[],
143
157
  message?: string,
144
158
  inlineDetailsProp: boolean = false,
145
- ) {
159
+ ): void {
146
160
  const actualEvents = this.events;
147
161
  if (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {
148
162
  throw new Error(`${message}
@@ -159,7 +173,7 @@ ${JSON.stringify(actualEvents)}`);
159
173
  inlineDetailsProp: boolean,
160
174
  ): number {
161
175
  let iExpectedEvent = 0;
162
- this.events.forEach((event) => {
176
+ for (const event of this.events) {
163
177
  if (
164
178
  iExpectedEvent < expectedEvents.length &&
165
179
  MockLogger.eventsMatch(event, expectedEvents[iExpectedEvent], inlineDetailsProp)
@@ -167,7 +181,7 @@ ${JSON.stringify(actualEvents)}`);
167
181
  // We found the next expected event; increment
168
182
  ++iExpectedEvent;
169
183
  }
170
- });
184
+ }
171
185
 
172
186
  // Remove the events so far; next call will just compare subsequent events from here
173
187
  this.events = [];
@@ -191,16 +205,19 @@ ${JSON.stringify(actualEvents)}`);
191
205
  if (inlineDetailsProp && details !== undefined) {
192
206
  assert(
193
207
  typeof details === "string",
208
+ // eslint-disable-next-line unicorn/numeric-separators-style
194
209
  0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,
195
210
  );
211
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
196
212
  const detailsExpanded = JSON.parse(details);
213
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
197
214
  return matchObjects({ ...actualForMatching, ...detailsExpanded }, expected);
198
215
  }
199
216
  return matchObjects(actual, expected);
200
217
  }
201
218
  }
202
219
 
203
- function matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPropertiesExt) {
220
+ function matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPropertiesExt): boolean {
204
221
  for (const [expectedKey, expectedValue] of Object.entries(expected)) {
205
222
  const actualValue = actual[expectedKey];
206
223
  if (
@@ -9,14 +9,17 @@ import {
9
9
  ITelemetryProperties,
10
10
  IDisposable,
11
11
  } from "@fluidframework/core-interfaces";
12
- import { performance } from "@fluidframework/common-utils";
12
+ import { performance } from "@fluid-internal/client-utils";
13
13
  import { ITelemetryLoggerExt } from "./telemetryTypes";
14
14
 
15
+ /**
16
+ * @privateRemarks
17
+ *
18
+ * The names of the properties in this interface are the ones that will get stamped in the
19
+ * telemetry event, changes should be considered carefully. The optional properties should
20
+ * only be populated if 'includeAggregateMetrics' is true.
21
+ */
15
22
  interface Measurements {
16
- // The names of the properties in this interface are the ones that will get stamped in the
17
- // telemetry event, changes should be considered carefully. The optional properties should
18
- // only be populated if 'includeAggregateMetrics' is true.
19
-
20
23
  /**
21
24
  * The duration of the latest execution.
22
25
  */
@@ -45,7 +48,7 @@ interface Measurements {
45
48
 
46
49
  /**
47
50
  * Helper class that executes a specified code block and writes an
48
- * {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified
51
+ * {@link @fluidframework/core-interfaces#ITelemetryPerformanceEvent} to a specified logger every time a specified
49
52
  * number of executions is reached (or when the class is disposed). The `duration` field in the telemetry event is
50
53
  * the duration of the latest execution (sample) of the specified function. See the documentation of the
51
54
  * `includeAggregateMetrics` parameter for additional details that can be included.
@@ -82,12 +85,13 @@ export class SampledTelemetryHelper implements IDisposable {
82
85
  ) {}
83
86
 
84
87
  /**
85
- * @param codeToMeasure -
86
- * The code to be executed and measured.
87
- * @param bucket -
88
- * A key to track executions of the code block separately. Each different value of this parameter has a separate
89
- * set of executions and metrics tracked by the class. If no such distinction needs to be made, do not provide a
90
- * value.
88
+ * Executes the specified code and keeps track of execution time statistics.
89
+ * If it's been called enough times (the sampleThreshold for the class) then it generates a log message with the necessary information.
90
+ *
91
+ * @param codeToMeasure - The code to be executed and measured.
92
+ * @param bucket - A key to track executions of the code block separately.
93
+ * Each different value of this parameter has a separate set of executions and metrics tracked by the class.
94
+ * If no such distinction needs to be made, do not provide a value.
91
95
  * @returns Whatever the passed-in code block returns.
92
96
  */
93
97
  public measure<T>(codeToMeasure: () => T, bucket: string = ""): T {
@@ -116,7 +120,7 @@ export class SampledTelemetryHelper implements IDisposable {
116
120
  return returnValue;
117
121
  }
118
122
 
119
- private flushBucket(bucket: string) {
123
+ private flushBucket(bucket: string): void {
120
124
  const measurements = this.measurementsMap.get(bucket);
121
125
  if (measurements === undefined) {
122
126
  return;
@@ -137,6 +141,6 @@ export class SampledTelemetryHelper implements IDisposable {
137
141
  }
138
142
 
139
143
  public dispose(error?: Error | undefined): void {
140
- this.measurementsMap.forEach((_, k) => this.flushBucket(k));
144
+ for (const [k] of this.measurementsMap.entries()) this.flushBucket(k);
141
145
  }
142
146
  }
@@ -3,11 +3,20 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryBaseLogger, TelemetryEventCategory } from "@fluidframework/core-interfaces";
6
+ import { ITelemetryBaseLogger, LogLevel, Tagged } from "@fluidframework/core-interfaces";
7
+
8
+ /**
9
+ * The categories FF uses when instrumenting the code.
10
+ *
11
+ * generic - Informational log event
12
+ * error - Error log event, ideally 0 of these are logged during a session
13
+ * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking
14
+ */
15
+ export type TelemetryEventCategory = "generic" | "error" | "performance";
7
16
 
8
17
  /**
9
18
  * Property types that can be logged.
10
- * Includes extra types beyond TelemetryEventPropertyType (which will be deprecated in favor of this one)
19
+ * Includes extra types beyond TelemetryBaseEventPropertyType, which must be converted before sending to a base logger
11
20
  */
12
21
  export type TelemetryEventPropertyTypeExt =
13
22
  | string
@@ -24,6 +33,8 @@ export type TelemetryEventPropertyTypeExt =
24
33
  * A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used
25
34
  * to mark pieces of information that should be organized or handled differently by loggers in various first or third
26
35
  * party scenarios. For example, tags are used to mark personal information that should not be stored in logs.
36
+ *
37
+ * @deprecated Use Tagged<TelemetryEventPropertyTypeExt>
27
38
  */
28
39
  export interface ITaggedTelemetryPropertyTypeExt {
29
40
  value: TelemetryEventPropertyTypeExt;
@@ -34,7 +45,7 @@ export interface ITaggedTelemetryPropertyTypeExt {
34
45
  * JSON-serializable properties, which will be logged with telemetry.
35
46
  */
36
47
  export interface ITelemetryPropertiesExt {
37
- [index: string]: TelemetryEventPropertyTypeExt | ITaggedTelemetryPropertyTypeExt;
48
+ [index: string]: TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>;
38
49
  }
39
50
 
40
51
  /**
@@ -83,18 +94,30 @@ export interface ITelemetryLoggerExt extends ITelemetryBaseLogger {
83
94
  * Send information telemetry event
84
95
  * @param event - Event to send
85
96
  * @param error - optional error object to log
97
+ * @param logLevel - optional level of the log.
86
98
  */
87
- sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: any): void;
99
+ sendTelemetryEvent(
100
+ event: ITelemetryGenericEventExt,
101
+ error?: unknown,
102
+ logLevel?: typeof LogLevel.verbose | typeof LogLevel.default,
103
+ ): void;
88
104
 
89
105
  /**
90
106
  * Send error telemetry event
91
107
  * @param event - Event to send
108
+ * @param error - optional error object to log
92
109
  */
93
- sendErrorEvent(event: ITelemetryErrorEventExt, error?: any): void;
110
+ sendErrorEvent(event: ITelemetryErrorEventExt, error?: unknown): void;
94
111
 
95
112
  /**
96
113
  * Send performance telemetry event
97
114
  * @param event - Event to send
115
+ * @param error - optional error object to log
116
+ * @param logLevel - optional level of the log.
98
117
  */
99
- sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: any): void;
118
+ sendPerformanceEvent(
119
+ event: ITelemetryPerformanceEventExt,
120
+ error?: unknown,
121
+ logLevel?: typeof LogLevel.verbose | typeof LogLevel.default,
122
+ ): void;
100
123
  }
@@ -19,7 +19,7 @@ export class ThresholdCounter {
19
19
  /**
20
20
  * Sends the value if it's above the treshold.
21
21
  */
22
- public send(eventName: string, value: number) {
22
+ public send(eventName: string, value: number): void {
23
23
  if (value < this.threshold) {
24
24
  return;
25
25
  }
@@ -36,7 +36,7 @@ export class ThresholdCounter {
36
36
  * To be used in scenarios where we'd like to record a
37
37
  * threshold violation while reducing telemetry noise.
38
38
  */
39
- public sendIfMultiple(eventName: string, value: number) {
39
+ public sendIfMultiple(eventName: string, value: number): void {
40
40
  if (value === this.thresholdMultiple) {
41
41
  this.logger.sendPerformanceEvent({
42
42
  eventName,
package/src/utils.ts CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  * @returns - The outcome of the condition
17
17
  */
18
18
  export function logIfFalse(
19
- condition: any,
19
+ condition: unknown,
20
20
  logger: ITelemetryBaseLogger,
21
21
  event: string | ITelemetryGenericEvent,
22
22
  ): condition is true {