@fluidframework/telemetry-utils 2.0.0-internal.3.0.0 → 2.0.0-internal.3.1.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 (97) hide show
  1. package/.eslintrc.js +11 -13
  2. package/.mocharc.js +2 -2
  3. package/api-extractor.json +2 -2
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +3 -3
  6. package/dist/config.js.map +1 -1
  7. package/dist/debugLogger.d.ts.map +1 -1
  8. package/dist/debugLogger.js.map +1 -1
  9. package/dist/errorLogging.d.ts +5 -5
  10. package/dist/errorLogging.d.ts.map +1 -1
  11. package/dist/errorLogging.js +20 -18
  12. package/dist/errorLogging.js.map +1 -1
  13. package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
  14. package/dist/eventEmitterWithErrorHandling.js.map +1 -1
  15. package/dist/events.d.ts.map +1 -1
  16. package/dist/events.js.map +1 -1
  17. package/dist/fluidErrorBase.d.ts.map +1 -1
  18. package/dist/fluidErrorBase.js +4 -4
  19. package/dist/fluidErrorBase.js.map +1 -1
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/logger.d.ts.map +1 -1
  24. package/dist/logger.js +13 -12
  25. package/dist/logger.js.map +1 -1
  26. package/dist/mockLogger.d.ts +5 -5
  27. package/dist/mockLogger.d.ts.map +1 -1
  28. package/dist/mockLogger.js +5 -5
  29. package/dist/mockLogger.js.map +1 -1
  30. package/dist/packageVersion.d.ts +1 -1
  31. package/dist/packageVersion.js +1 -1
  32. package/dist/packageVersion.js.map +1 -1
  33. package/dist/sampledTelemetryHelper.d.ts.map +1 -1
  34. package/dist/sampledTelemetryHelper.js.map +1 -1
  35. package/dist/telemetryTypes.d.ts.map +1 -1
  36. package/dist/telemetryTypes.js.map +1 -1
  37. package/dist/thresholdCounter.d.ts.map +1 -1
  38. package/dist/thresholdCounter.js.map +1 -1
  39. package/dist/utils.d.ts.map +1 -1
  40. package/dist/utils.js.map +1 -1
  41. package/lib/config.d.ts.map +1 -1
  42. package/lib/config.js +3 -3
  43. package/lib/config.js.map +1 -1
  44. package/lib/debugLogger.d.ts.map +1 -1
  45. package/lib/debugLogger.js +1 -1
  46. package/lib/debugLogger.js.map +1 -1
  47. package/lib/errorLogging.d.ts +5 -5
  48. package/lib/errorLogging.d.ts.map +1 -1
  49. package/lib/errorLogging.js +20 -18
  50. package/lib/errorLogging.js.map +1 -1
  51. package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
  52. package/lib/eventEmitterWithErrorHandling.js.map +1 -1
  53. package/lib/events.d.ts.map +1 -1
  54. package/lib/events.js.map +1 -1
  55. package/lib/fluidErrorBase.d.ts.map +1 -1
  56. package/lib/fluidErrorBase.js +4 -4
  57. package/lib/fluidErrorBase.js.map +1 -1
  58. package/lib/index.d.ts +2 -2
  59. package/lib/index.d.ts.map +1 -1
  60. package/lib/index.js +2 -2
  61. package/lib/index.js.map +1 -1
  62. package/lib/logger.d.ts.map +1 -1
  63. package/lib/logger.js +14 -13
  64. package/lib/logger.js.map +1 -1
  65. package/lib/mockLogger.d.ts +5 -5
  66. package/lib/mockLogger.d.ts.map +1 -1
  67. package/lib/mockLogger.js +5 -5
  68. package/lib/mockLogger.js.map +1 -1
  69. package/lib/packageVersion.d.ts +1 -1
  70. package/lib/packageVersion.js +1 -1
  71. package/lib/packageVersion.js.map +1 -1
  72. package/lib/sampledTelemetryHelper.d.ts.map +1 -1
  73. package/lib/sampledTelemetryHelper.js.map +1 -1
  74. package/lib/telemetryTypes.d.ts.map +1 -1
  75. package/lib/telemetryTypes.js.map +1 -1
  76. package/lib/thresholdCounter.d.ts.map +1 -1
  77. package/lib/thresholdCounter.js.map +1 -1
  78. package/lib/utils.d.ts.map +1 -1
  79. package/lib/utils.js.map +1 -1
  80. package/package.json +107 -110
  81. package/prettier.config.cjs +1 -1
  82. package/src/config.ts +173 -172
  83. package/src/debugLogger.ts +118 -111
  84. package/src/errorLogging.ts +302 -299
  85. package/src/eventEmitterWithErrorHandling.ts +16 -12
  86. package/src/events.ts +26 -26
  87. package/src/fluidErrorBase.ts +42 -38
  88. package/src/index.ts +26 -16
  89. package/src/logger.ts +541 -533
  90. package/src/mockLogger.ts +113 -107
  91. package/src/packageVersion.ts +1 -1
  92. package/src/sampledTelemetryHelper.ts +122 -122
  93. package/src/telemetryTypes.ts +37 -37
  94. package/src/thresholdCounter.ts +34 -34
  95. package/src/utils.ts +15 -15
  96. package/tsconfig.esnext.json +6 -6
  97. package/tsconfig.json +9 -13
package/src/logger.ts CHANGED
@@ -4,36 +4,32 @@
4
4
  */
5
5
 
6
6
  import {
7
- ITelemetryBaseEvent,
8
- ITelemetryBaseLogger,
9
- ITelemetryErrorEvent,
10
- ITelemetryGenericEvent,
11
- ITelemetryLogger,
12
- ITelemetryPerformanceEvent,
13
- ITelemetryProperties,
14
- TelemetryEventPropertyType,
15
- ITaggedTelemetryPropertyType,
16
- TelemetryEventCategory,
7
+ ITelemetryBaseEvent,
8
+ ITelemetryBaseLogger,
9
+ ITelemetryErrorEvent,
10
+ ITelemetryGenericEvent,
11
+ ITelemetryLogger,
12
+ ITelemetryPerformanceEvent,
13
+ ITelemetryProperties,
14
+ TelemetryEventPropertyType,
15
+ ITaggedTelemetryPropertyType,
16
+ TelemetryEventCategory,
17
17
  } from "@fluidframework/common-definitions";
18
18
  import { performance } from "@fluidframework/common-utils";
19
+ import { CachedConfigProvider, loggerIsMonitoringContext, mixinMonitoringContext } from "./config";
19
20
  import {
20
- CachedConfigProvider,
21
- loggerIsMonitoringContext,
22
- mixinMonitoringContext,
23
- } from "./config";
24
- import {
25
- isILoggingError,
26
- extractLogSafeErrorProperties,
27
- generateStack,
28
- isTaggedTelemetryPropertyValue,
21
+ isILoggingError,
22
+ extractLogSafeErrorProperties,
23
+ generateStack,
24
+ isTaggedTelemetryPropertyValue,
29
25
  } from "./errorLogging";
30
26
  import {
31
- ITaggedTelemetryPropertyTypeExt,
32
- ITelemetryEventExt,
33
- ITelemetryGenericEventExt,
34
- ITelemetryLoggerExt,
35
- ITelemetryPerformanceEventExt,
36
- TelemetryEventPropertyTypeExt,
27
+ ITaggedTelemetryPropertyTypeExt,
28
+ ITelemetryEventExt,
29
+ ITelemetryGenericEventExt,
30
+ ITelemetryLoggerExt,
31
+ ITelemetryPerformanceEventExt,
32
+ TelemetryEventPropertyTypeExt,
37
33
  } from "./telemetryTypes";
38
34
 
39
35
  /**
@@ -41,20 +37,20 @@ import {
41
37
  * Please do not modify existing entries for backwards compatibility.
42
38
  */
43
39
  export enum TelemetryDataTag {
44
- /** Data containing terms or IDs from code packages that may have been dynamically loaded */
45
- CodeArtifact = "CodeArtifact",
46
- /** Personal data of a variety of classifications that pertains to the user */
47
- UserData = "UserData",
40
+ /** Data containing terms or IDs from code packages that may have been dynamically loaded */
41
+ CodeArtifact = "CodeArtifact",
42
+ /** Personal data of a variety of classifications that pertains to the user */
43
+ UserData = "UserData",
48
44
  }
49
45
 
50
46
  export type TelemetryEventPropertyTypes = TelemetryEventPropertyType | ITaggedTelemetryPropertyType;
51
47
 
52
48
  export interface ITelemetryLoggerPropertyBag {
53
- [index: string]: TelemetryEventPropertyTypes | (() => TelemetryEventPropertyTypes);
49
+ [index: string]: TelemetryEventPropertyTypes | (() => TelemetryEventPropertyTypes);
54
50
  }
55
- export interface ITelemetryLoggerPropertyBags{
56
- all?: ITelemetryLoggerPropertyBag;
57
- error?: ITelemetryLoggerPropertyBag;
51
+ export interface ITelemetryLoggerPropertyBags {
52
+ all?: ITelemetryLoggerPropertyBag;
53
+ error?: ITelemetryLoggerPropertyBag;
58
54
  }
59
55
 
60
56
  /**
@@ -63,169 +59,177 @@ export interface ITelemetryLoggerPropertyBags{
63
59
  * Creates sub-logger that appends properties to all events
64
60
  */
65
61
  export abstract class TelemetryLogger implements ITelemetryLoggerExt {
66
- public static readonly eventNamespaceSeparator = ":";
67
-
68
- public static formatTick(tick: number): number {
69
- return Math.floor(tick);
70
- }
71
-
72
- /**
73
- * Attempts to parse number from string.
74
- * If fails,returns original string.
75
- * Used to make telemetry data typed (and support math operations, like comparison),
76
- * in places where we do expect numbers (like contentsize/duration property in http header)
77
- */
78
- public static numberFromString(str: string | null | undefined): string | number | undefined {
79
- if (str === undefined || str === null) {
80
- return undefined;
81
- }
82
- const num = Number(str);
83
- return Number.isNaN(num) ? str : num;
84
- }
85
-
86
- public static sanitizePkgName(name: string) {
87
- return name.replace("@", "").replace("/", "-");
88
- }
89
-
90
- /**
91
- * Take an unknown error object and add the appropriate info from it to the event. Message and stack will be copied
92
- * over from the error object, along with other telemetry properties if it's an ILoggingError.
93
- * @param event - Event being logged
94
- * @param error - Error to extract info from
95
- * @param fetchStack - Whether to fetch the current callstack if error.stack is undefined
96
- */
97
- public static prepareErrorObject(event: ITelemetryBaseEvent, error: any, fetchStack: boolean) {
98
- const { message, errorType, stack } = extractLogSafeErrorProperties(error, true /* sanitizeStack */);
99
- // First, copy over error message, stack, and errorType directly (overwrite if present on event)
100
- event.stack = stack;
101
- event.error = message; // Note that the error message goes on the 'error' field
102
- event.errorType = errorType;
103
-
104
- if (isILoggingError(error)) {
105
- // Add any other telemetry properties from the LoggingError
106
- const telemetryProp = error.getTelemetryProperties();
107
- for (const key of Object.keys(telemetryProp)) {
108
- if (event[key] !== undefined) {
109
- // Don't overwrite existing properties on the event
110
- continue;
111
- }
112
- event[key] = telemetryProp[key];
113
- }
114
- }
115
-
116
- // Collect stack if we were not able to extract it from error
117
- if (event.stack === undefined && fetchStack) {
118
- event.stack = generateStack();
119
- }
120
- }
121
-
122
- public constructor(
123
- protected readonly namespace?: string,
124
- protected readonly properties?: ITelemetryLoggerPropertyBags) {
125
- }
126
-
127
- /**
128
- * Send an event with the logger
129
- *
130
- * @param event - the event to send
131
- */
132
- public abstract send(event: ITelemetryBaseEvent): void;
133
-
134
- /**
135
- * Send a telemetry event with the logger
136
- *
137
- * @param event - the event to send
138
- * @param error - optional error object to log
139
- */
140
- public sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: any) {
141
- this.sendTelemetryEventCore({ ...event, category: event.category ?? "generic" }, error);
142
- }
143
-
144
- /**
145
- * Send a telemetry event with the logger
146
- *
147
- * @param event - the event to send
148
- * @param error - optional error object to log
149
- */
150
- protected sendTelemetryEventCore(
151
- event: ITelemetryGenericEventExt & { category: TelemetryEventCategory; },
152
- error?: any) {
153
- const newEvent = convertToBaseEvent(event);
154
- if (error !== undefined) {
155
- TelemetryLogger.prepareErrorObject(newEvent, error, false);
156
- }
157
-
158
- // Will include Nan & Infinity, but probably we do not care
159
- if (typeof newEvent.duration === "number") {
160
- newEvent.duration = TelemetryLogger.formatTick(newEvent.duration);
161
- }
162
-
163
- this.send(newEvent);
164
- }
165
-
166
- /**
167
- * Send an error telemetry event with the logger
168
- *
169
- * @param event - the event to send
170
- * @param error - optional error object to log
171
- */
172
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
173
- this.sendTelemetryEventCore({
174
- // ensure the error field has some value,
175
- // this can and will be overridden by event, or error
176
- error: event.eventName,
177
- ...event,
178
- category: "error",
179
- }, error);
180
- }
181
-
182
- /**
183
- * Send a performance telemetry event with the logger
184
- *
185
- * @param event - Event to send
186
- * @param error - optional error object to log
187
- */
188
- public sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: any): void {
189
- const perfEvent = {
190
- ...event,
191
- category: event.category ?? "performance",
192
- };
193
-
194
- this.sendTelemetryEventCore(perfEvent, error);
195
- }
196
-
197
- protected prepareEvent(event: ITelemetryBaseEvent): ITelemetryBaseEvent {
198
- const includeErrorProps = event.category === "error" || event.error !== undefined;
199
- const newEvent: ITelemetryBaseEvent = {
200
- ...event,
201
- };
202
- if (this.namespace !== undefined) {
203
- newEvent.eventName = `${this.namespace}${TelemetryLogger.eventNamespaceSeparator}${newEvent.eventName}`;
204
- }
205
- if (this.properties) {
206
- const properties: (undefined | ITelemetryLoggerPropertyBag)[] = [];
207
- properties.push(this.properties.all);
208
- if (includeErrorProps) {
209
- properties.push(this.properties.error);
210
- }
211
- for (const props of properties) {
212
- if (props !== undefined) {
213
- for (const key of Object.keys(props)) {
214
- if (event[key] !== undefined) {
215
- continue;
216
- }
217
- const getterOrValue = props[key];
218
- // If this throws, hopefully it is handled elsewhere
219
- const value = typeof getterOrValue === "function" ? getterOrValue() : getterOrValue;
220
- if (value !== undefined) {
221
- newEvent[key] = value;
222
- }
223
- }
224
- }
225
- }
226
- }
227
- return newEvent;
228
- }
62
+ public static readonly eventNamespaceSeparator = ":";
63
+
64
+ public static formatTick(tick: number): number {
65
+ return Math.floor(tick);
66
+ }
67
+
68
+ /**
69
+ * Attempts to parse number from string.
70
+ * If fails,returns original string.
71
+ * Used to make telemetry data typed (and support math operations, like comparison),
72
+ * in places where we do expect numbers (like contentsize/duration property in http header)
73
+ */
74
+ public static numberFromString(str: string | null | undefined): string | number | undefined {
75
+ if (str === undefined || str === null) {
76
+ return undefined;
77
+ }
78
+ const num = Number(str);
79
+ return Number.isNaN(num) ? str : num;
80
+ }
81
+
82
+ public static sanitizePkgName(name: string) {
83
+ return name.replace("@", "").replace("/", "-");
84
+ }
85
+
86
+ /**
87
+ * Take an unknown error object and add the appropriate info from it to the event. Message and stack will be copied
88
+ * over from the error object, along with other telemetry properties if it's an ILoggingError.
89
+ * @param event - Event being logged
90
+ * @param error - Error to extract info from
91
+ * @param fetchStack - Whether to fetch the current callstack if error.stack is undefined
92
+ */
93
+ public static prepareErrorObject(event: ITelemetryBaseEvent, error: any, fetchStack: boolean) {
94
+ const { message, errorType, stack } = extractLogSafeErrorProperties(
95
+ error,
96
+ true /* sanitizeStack */,
97
+ );
98
+ // First, copy over error message, stack, and errorType directly (overwrite if present on event)
99
+ event.stack = stack;
100
+ event.error = message; // Note that the error message goes on the 'error' field
101
+ event.errorType = errorType;
102
+
103
+ if (isILoggingError(error)) {
104
+ // Add any other telemetry properties from the LoggingError
105
+ const telemetryProp = error.getTelemetryProperties();
106
+ for (const key of Object.keys(telemetryProp)) {
107
+ if (event[key] !== undefined) {
108
+ // Don't overwrite existing properties on the event
109
+ continue;
110
+ }
111
+ event[key] = telemetryProp[key];
112
+ }
113
+ }
114
+
115
+ // Collect stack if we were not able to extract it from error
116
+ if (event.stack === undefined && fetchStack) {
117
+ event.stack = generateStack();
118
+ }
119
+ }
120
+
121
+ public constructor(
122
+ protected readonly namespace?: string,
123
+ protected readonly properties?: ITelemetryLoggerPropertyBags,
124
+ ) {}
125
+
126
+ /**
127
+ * Send an event with the logger
128
+ *
129
+ * @param event - the event to send
130
+ */
131
+ public abstract send(event: ITelemetryBaseEvent): void;
132
+
133
+ /**
134
+ * Send a telemetry event with the logger
135
+ *
136
+ * @param event - the event to send
137
+ * @param error - optional error object to log
138
+ */
139
+ public sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: any) {
140
+ this.sendTelemetryEventCore({ ...event, category: event.category ?? "generic" }, error);
141
+ }
142
+
143
+ /**
144
+ * Send a telemetry event with the logger
145
+ *
146
+ * @param event - the event to send
147
+ * @param error - optional error object to log
148
+ */
149
+ protected sendTelemetryEventCore(
150
+ event: ITelemetryGenericEventExt & { category: TelemetryEventCategory },
151
+ error?: any,
152
+ ) {
153
+ const newEvent = convertToBaseEvent(event);
154
+ if (error !== undefined) {
155
+ TelemetryLogger.prepareErrorObject(newEvent, error, false);
156
+ }
157
+
158
+ // Will include Nan & Infinity, but probably we do not care
159
+ if (typeof newEvent.duration === "number") {
160
+ newEvent.duration = TelemetryLogger.formatTick(newEvent.duration);
161
+ }
162
+
163
+ this.send(newEvent);
164
+ }
165
+
166
+ /**
167
+ * Send an error telemetry event with the logger
168
+ *
169
+ * @param event - the event to send
170
+ * @param error - optional error object to log
171
+ */
172
+ public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
173
+ this.sendTelemetryEventCore(
174
+ {
175
+ // ensure the error field has some value,
176
+ // this can and will be overridden by event, or error
177
+ error: event.eventName,
178
+ ...event,
179
+ category: "error",
180
+ },
181
+ error,
182
+ );
183
+ }
184
+
185
+ /**
186
+ * Send a performance telemetry event with the logger
187
+ *
188
+ * @param event - Event to send
189
+ * @param error - optional error object to log
190
+ */
191
+ public sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: any): void {
192
+ const perfEvent = {
193
+ ...event,
194
+ category: event.category ?? "performance",
195
+ };
196
+
197
+ this.sendTelemetryEventCore(perfEvent, error);
198
+ }
199
+
200
+ protected prepareEvent(event: ITelemetryBaseEvent): ITelemetryBaseEvent {
201
+ const includeErrorProps = event.category === "error" || event.error !== undefined;
202
+ const newEvent: ITelemetryBaseEvent = {
203
+ ...event,
204
+ };
205
+ if (this.namespace !== undefined) {
206
+ newEvent.eventName = `${this.namespace}${TelemetryLogger.eventNamespaceSeparator}${newEvent.eventName}`;
207
+ }
208
+ if (this.properties) {
209
+ const properties: (undefined | ITelemetryLoggerPropertyBag)[] = [];
210
+ properties.push(this.properties.all);
211
+ if (includeErrorProps) {
212
+ properties.push(this.properties.error);
213
+ }
214
+ for (const props of properties) {
215
+ if (props !== undefined) {
216
+ for (const key of Object.keys(props)) {
217
+ if (event[key] !== undefined) {
218
+ continue;
219
+ }
220
+ const getterOrValue = props[key];
221
+ // If this throws, hopefully it is handled elsewhere
222
+ const value =
223
+ typeof getterOrValue === "function" ? getterOrValue() : getterOrValue;
224
+ if (value !== undefined) {
225
+ newEvent[key] = value;
226
+ }
227
+ }
228
+ }
229
+ }
230
+ }
231
+ return newEvent;
232
+ }
229
233
  }
230
234
 
231
235
  /**
@@ -233,46 +237,45 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
233
237
  * container-runtime. Issue: #8191
234
238
  * TaggedLoggerAdapter class can add tag handling to your logger.
235
239
  */
236
- export class TaggedLoggerAdapter implements ITelemetryBaseLogger {
237
- public constructor(
238
- private readonly logger: ITelemetryBaseLogger) {
239
- }
240
-
241
- public send(eventWithTagsMaybe: ITelemetryBaseEvent) {
242
- const newEvent: ITelemetryBaseEvent = {
243
- category: eventWithTagsMaybe.category,
244
- eventName: eventWithTagsMaybe.eventName,
245
- };
246
- for (const key of Object.keys(eventWithTagsMaybe)) {
247
- const taggableProp = eventWithTagsMaybe[key];
248
- const { value, tag } = (typeof taggableProp === "object")
249
- ? taggableProp
250
- : { value: taggableProp, tag: undefined };
251
- switch (tag) {
252
- case undefined:
253
- // No tag means we can log plainly
254
- newEvent[key] = value;
255
- break;
256
- case "PackageData": // For back-compat
257
- case TelemetryDataTag.CodeArtifact:
258
- // For Microsoft applications, CodeArtifact is safe for now
259
- // (we don't load 3P code in 1P apps)
260
- newEvent[key] = value;
261
- break;
262
- case TelemetryDataTag.UserData:
263
- // Strip out anything tagged explicitly as PII.
264
- // Alternate strategy would be to hash these props
265
- newEvent[key] = "REDACTED (UserData)";
266
- break;
267
- default:
268
- // If we encounter a tag we don't recognize
269
- // then we must assume we should scrub.
270
- newEvent[key] = "REDACTED (unknown tag)";
271
- break;
272
- }
273
- }
274
- this.logger.send(newEvent);
275
- }
240
+ export class TaggedLoggerAdapter implements ITelemetryBaseLogger {
241
+ public constructor(private readonly logger: ITelemetryBaseLogger) {}
242
+
243
+ public send(eventWithTagsMaybe: ITelemetryBaseEvent) {
244
+ const newEvent: ITelemetryBaseEvent = {
245
+ category: eventWithTagsMaybe.category,
246
+ eventName: eventWithTagsMaybe.eventName,
247
+ };
248
+ for (const key of Object.keys(eventWithTagsMaybe)) {
249
+ const taggableProp = eventWithTagsMaybe[key];
250
+ const { value, tag } =
251
+ typeof taggableProp === "object"
252
+ ? taggableProp
253
+ : { value: taggableProp, tag: undefined };
254
+ switch (tag) {
255
+ case undefined:
256
+ // No tag means we can log plainly
257
+ newEvent[key] = value;
258
+ break;
259
+ case "PackageData": // For back-compat
260
+ case TelemetryDataTag.CodeArtifact:
261
+ // For Microsoft applications, CodeArtifact is safe for now
262
+ // (we don't load 3P code in 1P apps)
263
+ newEvent[key] = value;
264
+ break;
265
+ case TelemetryDataTag.UserData:
266
+ // Strip out anything tagged explicitly as PII.
267
+ // Alternate strategy would be to hash these props
268
+ newEvent[key] = "REDACTED (UserData)";
269
+ break;
270
+ default:
271
+ // If we encounter a tag we don't recognize
272
+ // then we must assume we should scrub.
273
+ newEvent[key] = "REDACTED (unknown tag)";
274
+ break;
275
+ }
276
+ }
277
+ this.logger.send(newEvent);
278
+ }
276
279
  }
277
280
 
278
281
  /**
@@ -281,81 +284,78 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
281
284
  * Creates sub-logger that appends properties to all events
282
285
  */
283
286
  export class ChildLogger extends TelemetryLogger {
284
- /**
285
- * Create child logger
286
- * @param baseLogger - Base logger to use to output events. If undefined, proper child logger
287
- * is created, but it does not send telemetry events anywhere.
288
- * @param namespace - Telemetry event name prefix to add to all events
289
- * @param properties - Base properties to add to all events
290
- * @param propertyGetters - Getters to add additional properties to all events
291
- */
292
- public static create(
293
- baseLogger?: ITelemetryBaseLogger,
294
- namespace?: string,
295
- properties?: ITelemetryLoggerPropertyBags): TelemetryLogger {
296
- // if we are creating a child of a child, rather than nest, which will increase
297
- // the callstack overhead, just generate a new logger that includes everything from the previous
298
- if (baseLogger instanceof ChildLogger) {
299
- const combinedProperties: ITelemetryLoggerPropertyBags = {};
300
- for (const extendedProps of [baseLogger.properties, properties]) {
301
- if (extendedProps !== undefined) {
302
- if (extendedProps.all !== undefined) {
303
- combinedProperties.all = {
304
- ... combinedProperties.all,
305
- ... extendedProps.all,
306
- };
307
- }
308
- if (extendedProps.error !== undefined) {
309
- combinedProperties.error = {
310
- ... combinedProperties.error,
311
- ... extendedProps.error,
312
- };
313
- }
314
- }
315
- }
316
-
317
- const combinedNamespace = baseLogger.namespace === undefined
318
- ? namespace
319
- : namespace === undefined
320
- ? baseLogger.namespace
321
- : `${baseLogger.namespace}${TelemetryLogger.eventNamespaceSeparator}${namespace}`;
322
-
323
- return new ChildLogger(
324
- baseLogger.baseLogger,
325
- combinedNamespace,
326
- combinedProperties,
327
- );
328
- }
329
-
330
- return new ChildLogger(
331
- baseLogger ? baseLogger : new BaseTelemetryNullLogger(),
332
- namespace,
333
- properties);
334
- }
335
-
336
- private constructor(
337
- protected readonly baseLogger: ITelemetryBaseLogger,
338
- namespace: string | undefined,
339
- properties: ITelemetryLoggerPropertyBags | undefined,
340
- ) {
341
- super(namespace, properties);
342
-
343
- // propagate the monitoring context
344
- if (loggerIsMonitoringContext(baseLogger)) {
345
- mixinMonitoringContext(
346
- this,
347
- new CachedConfigProvider(baseLogger.config));
348
- }
349
- }
350
-
351
- /**
352
- * Send an event with the logger
353
- *
354
- * @param event - the event to send
355
- */
356
- public send(event: ITelemetryBaseEvent): void {
357
- this.baseLogger.send(this.prepareEvent(event));
358
- }
287
+ /**
288
+ * Create child logger
289
+ * @param baseLogger - Base logger to use to output events. If undefined, proper child logger
290
+ * is created, but it does not send telemetry events anywhere.
291
+ * @param namespace - Telemetry event name prefix to add to all events
292
+ * @param properties - Base properties to add to all events
293
+ * @param propertyGetters - Getters to add additional properties to all events
294
+ */
295
+ public static create(
296
+ baseLogger?: ITelemetryBaseLogger,
297
+ namespace?: string,
298
+ properties?: ITelemetryLoggerPropertyBags,
299
+ ): TelemetryLogger {
300
+ // if we are creating a child of a child, rather than nest, which will increase
301
+ // the callstack overhead, just generate a new logger that includes everything from the previous
302
+ if (baseLogger instanceof ChildLogger) {
303
+ const combinedProperties: ITelemetryLoggerPropertyBags = {};
304
+ for (const extendedProps of [baseLogger.properties, properties]) {
305
+ if (extendedProps !== undefined) {
306
+ if (extendedProps.all !== undefined) {
307
+ combinedProperties.all = {
308
+ ...combinedProperties.all,
309
+ ...extendedProps.all,
310
+ };
311
+ }
312
+ if (extendedProps.error !== undefined) {
313
+ combinedProperties.error = {
314
+ ...combinedProperties.error,
315
+ ...extendedProps.error,
316
+ };
317
+ }
318
+ }
319
+ }
320
+
321
+ const combinedNamespace =
322
+ baseLogger.namespace === undefined
323
+ ? namespace
324
+ : namespace === undefined
325
+ ? baseLogger.namespace
326
+ : `${baseLogger.namespace}${TelemetryLogger.eventNamespaceSeparator}${namespace}`;
327
+
328
+ return new ChildLogger(baseLogger.baseLogger, combinedNamespace, combinedProperties);
329
+ }
330
+
331
+ return new ChildLogger(
332
+ baseLogger ? baseLogger : new BaseTelemetryNullLogger(),
333
+ namespace,
334
+ properties,
335
+ );
336
+ }
337
+
338
+ private constructor(
339
+ protected readonly baseLogger: ITelemetryBaseLogger,
340
+ namespace: string | undefined,
341
+ properties: ITelemetryLoggerPropertyBags | undefined,
342
+ ) {
343
+ super(namespace, properties);
344
+
345
+ // propagate the monitoring context
346
+ if (loggerIsMonitoringContext(baseLogger)) {
347
+ mixinMonitoringContext(this, new CachedConfigProvider(baseLogger.config));
348
+ }
349
+ }
350
+
351
+ /**
352
+ * Send an event with the logger
353
+ *
354
+ * @param event - the event to send
355
+ */
356
+ public send(event: ITelemetryBaseEvent): void {
357
+ this.baseLogger.send(this.prepareEvent(event));
358
+ }
359
359
  }
360
360
 
361
361
  /**
@@ -364,41 +364,39 @@ export class ChildLogger extends TelemetryLogger {
364
364
  * Implements ITelemetryBaseLogger (through static create() method)
365
365
  */
366
366
  export class MultiSinkLogger extends TelemetryLogger {
367
- protected loggers: ITelemetryBaseLogger[] = [];
368
-
369
- /**
370
- * Create multiple sink logger (i.e. logger that sends events to multiple sinks)
371
- * @param namespace - Telemetry event name prefix to add to all events
372
- * @param properties - Base properties to add to all events
373
- * @param propertyGetters - Getters to add additional properties to all events
374
- */
375
- constructor(
376
- namespace?: string,
377
- properties?: ITelemetryLoggerPropertyBags) {
378
- super(namespace, properties);
379
- }
380
-
381
- /**
382
- * Add logger to send all events to
383
- * @param logger - Logger to add
384
- */
385
- public addLogger(logger?: ITelemetryBaseLogger) {
386
- if (logger !== undefined && logger !== null) {
387
- this.loggers.push(logger);
388
- }
389
- }
390
-
391
- /**
392
- * Send an event to the loggers
393
- *
394
- * @param event - the event to send to all the registered logger
395
- */
396
- public send(event: ITelemetryBaseEvent): void {
397
- const newEvent = this.prepareEvent(event);
398
- this.loggers.forEach((logger: ITelemetryBaseLogger) => {
399
- logger.send(newEvent);
400
- });
401
- }
367
+ protected loggers: ITelemetryBaseLogger[] = [];
368
+
369
+ /**
370
+ * Create multiple sink logger (i.e. logger that sends events to multiple sinks)
371
+ * @param namespace - Telemetry event name prefix to add to all events
372
+ * @param properties - Base properties to add to all events
373
+ * @param propertyGetters - Getters to add additional properties to all events
374
+ */
375
+ constructor(namespace?: string, properties?: ITelemetryLoggerPropertyBags) {
376
+ super(namespace, properties);
377
+ }
378
+
379
+ /**
380
+ * Add logger to send all events to
381
+ * @param logger - Logger to add
382
+ */
383
+ public addLogger(logger?: ITelemetryBaseLogger) {
384
+ if (logger !== undefined && logger !== null) {
385
+ this.loggers.push(logger);
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Send an event to the loggers
391
+ *
392
+ * @param event - the event to send to all the registered logger
393
+ */
394
+ public send(event: ITelemetryBaseEvent): void {
395
+ const newEvent = this.prepareEvent(event);
396
+ this.loggers.forEach((logger: ITelemetryBaseLogger) => {
397
+ logger.send(newEvent);
398
+ });
399
+ }
402
400
  }
403
401
 
404
402
  /**
@@ -408,129 +406,135 @@ export class MultiSinkLogger extends TelemetryLogger {
408
406
  * success / failure tracking, including duration (on success).
409
407
  */
410
408
  export interface IPerformanceEventMarkers {
411
- start?: true;
412
- end?: true;
413
- cancel?: "generic" | "error"; // tells wether to issue "generic" or "error" category cancel event
409
+ start?: true;
410
+ end?: true;
411
+ cancel?: "generic" | "error"; // tells wether to issue "generic" or "error" category cancel event
414
412
  }
415
413
 
416
414
  /**
417
415
  * Helper class to log performance events
418
416
  */
419
417
  export class PerformanceEvent {
420
- public static start(logger: ITelemetryLogger, event: ITelemetryGenericEvent, markers?: IPerformanceEventMarkers) {
421
- return new PerformanceEvent(logger, event, markers);
422
- }
423
-
424
- public static timedExec<T>(
425
- logger: ITelemetryLogger,
426
- event: ITelemetryGenericEvent,
427
- callback: (event: PerformanceEvent) => T,
428
- markers?: IPerformanceEventMarkers,
429
- ) {
430
- const perfEvent = PerformanceEvent.start(logger, event, markers);
431
- try {
432
- const ret = callback(perfEvent);
433
- perfEvent.autoEnd();
434
- return ret;
435
- } catch (error) {
436
- perfEvent.cancel(undefined, error);
437
- throw error;
438
- }
439
- }
440
-
441
- public static async timedExecAsync<T>(
442
- logger: ITelemetryLogger,
443
- event: ITelemetryGenericEvent,
444
- callback: (event: PerformanceEvent) => Promise<T>,
445
- markers?: IPerformanceEventMarkers,
446
- ) {
447
- const perfEvent = PerformanceEvent.start(logger, event, markers);
448
- try {
449
- const ret = await callback(perfEvent);
450
- perfEvent.autoEnd();
451
- return ret;
452
- } catch (error) {
453
- perfEvent.cancel(undefined, error);
454
- throw error;
455
- }
456
- }
457
-
458
- public get duration() { return performance.now() - this.startTime; }
459
-
460
- private event?: ITelemetryGenericEvent;
461
- private readonly startTime = performance.now();
462
- private startMark?: string;
463
-
464
- protected constructor(
465
- private readonly logger: ITelemetryLogger,
466
- event: ITelemetryGenericEvent,
467
- private readonly markers: IPerformanceEventMarkers = { end: true, cancel: "generic" },
468
- ) {
469
- this.event = { ...event };
470
- if (this.markers.start) {
471
- this.reportEvent("start");
472
- }
473
-
474
- if (typeof window === "object" && window != null && window.performance?.mark) {
475
- this.startMark = `${event.eventName}-start`;
476
- window.performance.mark(this.startMark);
477
- }
478
- }
479
-
480
- public reportProgress(props?: ITelemetryProperties, eventNameSuffix: string = "update"): void {
481
- this.reportEvent(eventNameSuffix, props);
482
- }
483
-
484
- private autoEnd() {
485
- // Event might have been cancelled or ended in the callback
486
- if (this.event && this.markers.end) {
487
- this.reportEvent("end");
488
- }
489
- this.performanceEndMark();
490
- this.event = undefined;
491
- }
492
-
493
- public end(props?: ITelemetryProperties): void {
494
- this.reportEvent("end", props);
495
- this.performanceEndMark();
496
- this.event = undefined;
497
- }
498
-
499
- private performanceEndMark() {
500
- if (this.startMark && this.event) {
501
- const endMark = `${this.event.eventName}-end`;
502
- window.performance.mark(endMark);
503
- window.performance.measure(`${this.event.eventName}`, this.startMark, endMark);
504
- this.startMark = undefined;
505
- }
506
- }
507
-
508
- public cancel(props?: ITelemetryProperties, error?: any): void {
509
- if (this.markers.cancel !== undefined) {
510
- this.reportEvent("cancel", { category: this.markers.cancel, ...props }, error);
511
- }
512
- this.event = undefined;
513
- }
514
-
515
- /**
516
- * Report the event, if it hasn't already been reported.
517
- */
518
- public reportEvent(eventNameSuffix: string, props?: ITelemetryProperties, error?: any) {
519
- // There are strange sequences involving multiple Promise chains
520
- // where the event can be cancelled and then later a callback is invoked
521
- // and the caller attempts to end directly, e.g. issue #3936. Just return.
522
- if (!this.event) {
523
- return;
524
- }
525
-
526
- const event: ITelemetryPerformanceEvent = { ...this.event, ...props };
527
- event.eventName = `${event.eventName}_${eventNameSuffix}`;
528
- if (eventNameSuffix !== "start") {
529
- event.duration = this.duration;
530
- }
531
-
532
- this.logger.sendPerformanceEvent(event, error);
533
- }
418
+ public static start(
419
+ logger: ITelemetryLogger,
420
+ event: ITelemetryGenericEvent,
421
+ markers?: IPerformanceEventMarkers,
422
+ ) {
423
+ return new PerformanceEvent(logger, event, markers);
424
+ }
425
+
426
+ public static timedExec<T>(
427
+ logger: ITelemetryLogger,
428
+ event: ITelemetryGenericEvent,
429
+ callback: (event: PerformanceEvent) => T,
430
+ markers?: IPerformanceEventMarkers,
431
+ ) {
432
+ const perfEvent = PerformanceEvent.start(logger, event, markers);
433
+ try {
434
+ const ret = callback(perfEvent);
435
+ perfEvent.autoEnd();
436
+ return ret;
437
+ } catch (error) {
438
+ perfEvent.cancel(undefined, error);
439
+ throw error;
440
+ }
441
+ }
442
+
443
+ public static async timedExecAsync<T>(
444
+ logger: ITelemetryLogger,
445
+ event: ITelemetryGenericEvent,
446
+ callback: (event: PerformanceEvent) => Promise<T>,
447
+ markers?: IPerformanceEventMarkers,
448
+ ) {
449
+ const perfEvent = PerformanceEvent.start(logger, event, markers);
450
+ try {
451
+ const ret = await callback(perfEvent);
452
+ perfEvent.autoEnd();
453
+ return ret;
454
+ } catch (error) {
455
+ perfEvent.cancel(undefined, error);
456
+ throw error;
457
+ }
458
+ }
459
+
460
+ public get duration() {
461
+ return performance.now() - this.startTime;
462
+ }
463
+
464
+ private event?: ITelemetryGenericEvent;
465
+ private readonly startTime = performance.now();
466
+ private startMark?: string;
467
+
468
+ protected constructor(
469
+ private readonly logger: ITelemetryLogger,
470
+ event: ITelemetryGenericEvent,
471
+ private readonly markers: IPerformanceEventMarkers = { end: true, cancel: "generic" },
472
+ ) {
473
+ this.event = { ...event };
474
+ if (this.markers.start) {
475
+ this.reportEvent("start");
476
+ }
477
+
478
+ if (typeof window === "object" && window != null && window.performance?.mark) {
479
+ this.startMark = `${event.eventName}-start`;
480
+ window.performance.mark(this.startMark);
481
+ }
482
+ }
483
+
484
+ public reportProgress(props?: ITelemetryProperties, eventNameSuffix: string = "update"): void {
485
+ this.reportEvent(eventNameSuffix, props);
486
+ }
487
+
488
+ private autoEnd() {
489
+ // Event might have been cancelled or ended in the callback
490
+ if (this.event && this.markers.end) {
491
+ this.reportEvent("end");
492
+ }
493
+ this.performanceEndMark();
494
+ this.event = undefined;
495
+ }
496
+
497
+ public end(props?: ITelemetryProperties): void {
498
+ this.reportEvent("end", props);
499
+ this.performanceEndMark();
500
+ this.event = undefined;
501
+ }
502
+
503
+ private performanceEndMark() {
504
+ if (this.startMark && this.event) {
505
+ const endMark = `${this.event.eventName}-end`;
506
+ window.performance.mark(endMark);
507
+ window.performance.measure(`${this.event.eventName}`, this.startMark, endMark);
508
+ this.startMark = undefined;
509
+ }
510
+ }
511
+
512
+ public cancel(props?: ITelemetryProperties, error?: any): void {
513
+ if (this.markers.cancel !== undefined) {
514
+ this.reportEvent("cancel", { category: this.markers.cancel, ...props }, error);
515
+ }
516
+ this.event = undefined;
517
+ }
518
+
519
+ /**
520
+ * Report the event, if it hasn't already been reported.
521
+ */
522
+ public reportEvent(eventNameSuffix: string, props?: ITelemetryProperties, error?: any) {
523
+ // There are strange sequences involving multiple Promise chains
524
+ // where the event can be cancelled and then later a callback is invoked
525
+ // and the caller attempts to end directly, e.g. issue #3936. Just return.
526
+ if (!this.event) {
527
+ return;
528
+ }
529
+
530
+ const event: ITelemetryPerformanceEvent = { ...this.event, ...props };
531
+ event.eventName = `${event.eventName}_${eventNameSuffix}`;
532
+ if (eventNameSuffix !== "start") {
533
+ event.duration = this.duration;
534
+ }
535
+
536
+ this.logger.sendPerformanceEvent(event, error);
537
+ }
534
538
  }
535
539
 
536
540
  /**
@@ -538,37 +542,34 @@ export class PerformanceEvent {
538
542
  * It can be used in places where logger instance is required, but events should be not send over.
539
543
  */
540
544
  export class TelemetryUTLogger implements ITelemetryLogger {
541
- public send(event: ITelemetryBaseEvent): void {
542
- }
543
- public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any) {
544
- }
545
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
546
- this.reportError("errorEvent in UT logger!", event, error);
547
- }
548
- public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: any): void {
549
- }
550
- public logGenericError(eventName: string, error: any) {
551
- this.reportError(`genericError in UT logger!`, { eventName }, error);
552
- }
553
- public logException(event: ITelemetryErrorEvent, exception: any): void {
554
- this.reportError("exception in UT logger!", event, exception);
555
- }
556
- public debugAssert(condition: boolean, event?: ITelemetryErrorEvent): void {
557
- this.reportError("debugAssert in UT logger!");
558
- }
559
- public shipAssert(condition: boolean, event?: ITelemetryErrorEvent): void {
560
- this.reportError("shipAssert in UT logger!");
561
- }
562
-
563
- private reportError(message: string, event?: ITelemetryErrorEvent, err?: any) {
564
- const error = new Error(message);
565
- (error as any).error = error;
566
- (error as any).event = event;
567
- // report to console as exception can be eaten
568
- console.error(message);
569
- console.error(error);
570
- throw error;
571
- }
545
+ public send(event: ITelemetryBaseEvent): void {}
546
+ public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any) {}
547
+ public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
548
+ this.reportError("errorEvent in UT logger!", event, error);
549
+ }
550
+ public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: any): void {}
551
+ public logGenericError(eventName: string, error: any) {
552
+ this.reportError(`genericError in UT logger!`, { eventName }, error);
553
+ }
554
+ public logException(event: ITelemetryErrorEvent, exception: any): void {
555
+ this.reportError("exception in UT logger!", event, exception);
556
+ }
557
+ public debugAssert(condition: boolean, event?: ITelemetryErrorEvent): void {
558
+ this.reportError("debugAssert in UT logger!");
559
+ }
560
+ public shipAssert(condition: boolean, event?: ITelemetryErrorEvent): void {
561
+ this.reportError("shipAssert in UT logger!");
562
+ }
563
+
564
+ private reportError(message: string, event?: ITelemetryErrorEvent, err?: any) {
565
+ const error = new Error(message);
566
+ (error as any).error = error;
567
+ (error as any).event = event;
568
+ // report to console as exception can be eaten
569
+ console.error(message);
570
+ console.error(error);
571
+ throw error;
572
+ }
572
573
  }
573
574
 
574
575
  /**
@@ -576,14 +577,14 @@ export class TelemetryUTLogger implements ITelemetryLogger {
576
577
  * It can be used in places where logger instance is required, but events should be not send over.
577
578
  */
578
579
  export class BaseTelemetryNullLogger implements ITelemetryBaseLogger {
579
- /**
580
- * Send an event with the logger
581
- *
582
- * @param event - the event to send
583
- */
584
- public send(event: ITelemetryBaseEvent): void {
585
- return;
586
- }
580
+ /**
581
+ * Send an event with the logger
582
+ *
583
+ * @param event - the event to send
584
+ */
585
+ public send(event: ITelemetryBaseEvent): void {
586
+ return;
587
+ }
587
588
  }
588
589
 
589
590
  /**
@@ -591,10 +592,10 @@ export class BaseTelemetryNullLogger implements ITelemetryBaseLogger {
591
592
  * It can be used in places where logger instance is required, but events should be not send over.
592
593
  */
593
594
  export class TelemetryNullLogger implements ITelemetryLogger {
594
- public send(event: ITelemetryBaseEvent): void {}
595
- public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any): void {}
596
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any): void {}
597
- public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: any): void {}
595
+ public send(event: ITelemetryBaseEvent): void {}
596
+ public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any): void {}
597
+ public sendErrorEvent(event: ITelemetryErrorEvent, error?: any): void {}
598
+ public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: any): void {}
598
599
  }
599
600
 
600
601
  /**
@@ -602,12 +603,16 @@ export class TelemetryNullLogger implements ITelemetryLogger {
602
603
  * In the case of an invalid property type, the value will be converted to an error string.
603
604
  * @param event - Event with fields you want to stringify.
604
605
  */
605
- function convertToBaseEvent({ category, eventName, ...props }: ITelemetryEventExt): ITelemetryBaseEvent {
606
- const newEvent: ITelemetryBaseEvent = { category, eventName };
607
- for (const key of Object.keys(props)) {
608
- newEvent[key] = convertToBasePropertyType(props[key]);
609
- }
610
- return newEvent;
606
+ function convertToBaseEvent({
607
+ category,
608
+ eventName,
609
+ ...props
610
+ }: ITelemetryEventExt): ITelemetryBaseEvent {
611
+ const newEvent: ITelemetryBaseEvent = { category, eventName };
612
+ for (const key of Object.keys(props)) {
613
+ newEvent[key] = convertToBasePropertyType(props[key]);
614
+ }
615
+ return newEvent;
611
616
  }
612
617
 
613
618
  /**
@@ -620,30 +625,33 @@ function convertToBaseEvent({ category, eventName, ...props }: ITelemetryEventEx
620
625
  * @param x - value passed in to convert to a base property type
621
626
  */
622
627
  export function convertToBasePropertyType(
623
- x: TelemetryEventPropertyTypeExt | ITaggedTelemetryPropertyTypeExt,
628
+ x: TelemetryEventPropertyTypeExt | ITaggedTelemetryPropertyTypeExt,
624
629
  ): TelemetryEventPropertyType | ITaggedTelemetryPropertyType {
625
-
626
- return isTaggedTelemetryPropertyValue(x) ? {
627
- value: convertToBasePropertyTypeUntagged(x.value),
628
- tag: x.tag,
629
- } : convertToBasePropertyTypeUntagged(x);
630
+ return isTaggedTelemetryPropertyValue(x)
631
+ ? {
632
+ value: convertToBasePropertyTypeUntagged(x.value),
633
+ tag: x.tag,
634
+ }
635
+ : convertToBasePropertyTypeUntagged(x);
630
636
  }
631
637
 
632
638
  function convertToBasePropertyTypeUntagged(
633
- x: TelemetryEventPropertyTypeExt,
639
+ x: TelemetryEventPropertyTypeExt,
634
640
  ): TelemetryEventPropertyType {
635
- switch (typeof x) {
636
- case "string":
637
- case "number":
638
- case "boolean":
639
- case "undefined":
640
- return x;
641
- case "object":
642
- // We assume this is an array based on the input types
643
- return JSON.stringify(x);
644
- default:
645
- // should never reach this case based on the input types
646
- console.error(`convertToBasePropertyTypeUntagged: INVALID PROPERTY (typed as ${typeof x})`);
647
- return `INVALID PROPERTY (typed as ${typeof x})`;
648
- }
641
+ switch (typeof x) {
642
+ case "string":
643
+ case "number":
644
+ case "boolean":
645
+ case "undefined":
646
+ return x;
647
+ case "object":
648
+ // We assume this is an array based on the input types
649
+ return JSON.stringify(x);
650
+ default:
651
+ // should never reach this case based on the input types
652
+ console.error(
653
+ `convertToBasePropertyTypeUntagged: INVALID PROPERTY (typed as ${typeof x})`,
654
+ );
655
+ return `INVALID PROPERTY (typed as ${typeof x})`;
656
+ }
649
657
  }