@fluidframework/telemetry-utils 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
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.
- package/.eslintrc.js +11 -13
- package/.mocharc.js +2 -2
- package/api-extractor.json +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -5
- package/dist/config.js.map +1 -1
- package/dist/debugLogger.d.ts.map +1 -1
- package/dist/debugLogger.js +12 -1
- package/dist/debugLogger.js.map +1 -1
- package/dist/errorLogging.d.ts +8 -7
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js +23 -20
- package/dist/errorLogging.js.map +1 -1
- package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/dist/eventEmitterWithErrorHandling.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/fluidErrorBase.d.ts.map +1 -1
- package/dist/fluidErrorBase.js +4 -4
- package/dist/fluidErrorBase.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +15 -4
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +69 -11
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +12 -2
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +24 -2
- package/dist/mockLogger.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/sampledTelemetryHelper.d.ts.map +1 -1
- package/dist/sampledTelemetryHelper.js.map +1 -1
- package/dist/telemetryTypes.d.ts +81 -0
- package/dist/telemetryTypes.d.ts.map +1 -0
- package/dist/telemetryTypes.js +7 -0
- package/dist/telemetryTypes.js.map +1 -0
- package/dist/thresholdCounter.d.ts.map +1 -1
- package/dist/thresholdCounter.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js.map +1 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +18 -5
- package/lib/config.js.map +1 -1
- package/lib/debugLogger.d.ts.map +1 -1
- package/lib/debugLogger.js +13 -2
- package/lib/debugLogger.js.map +1 -1
- package/lib/errorLogging.d.ts +8 -7
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js +23 -20
- package/lib/errorLogging.js.map +1 -1
- package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/lib/eventEmitterWithErrorHandling.js.map +1 -1
- package/lib/events.d.ts.map +1 -1
- package/lib/events.js.map +1 -1
- package/lib/fluidErrorBase.d.ts.map +1 -1
- package/lib/fluidErrorBase.js +4 -4
- package/lib/fluidErrorBase.js.map +1 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/logger.d.ts +15 -4
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js +69 -12
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +12 -2
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +24 -2
- package/lib/mockLogger.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/sampledTelemetryHelper.d.ts.map +1 -1
- package/lib/sampledTelemetryHelper.js.map +1 -1
- package/lib/telemetryTypes.d.ts +81 -0
- package/lib/telemetryTypes.d.ts.map +1 -0
- package/lib/telemetryTypes.js +6 -0
- package/lib/telemetryTypes.js.map +1 -0
- package/lib/thresholdCounter.d.ts.map +1 -1
- package/lib/thresholdCounter.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js.map +1 -1
- package/package.json +49 -48
- package/prettier.config.cjs +1 -1
- package/src/config.ts +185 -173
- package/src/debugLogger.ts +128 -111
- package/src/errorLogging.ts +306 -300
- package/src/eventEmitterWithErrorHandling.ts +16 -12
- package/src/events.ts +26 -26
- package/src/fluidErrorBase.ts +42 -38
- package/src/index.ts +29 -9
- package/src/logger.ts +568 -500
- package/src/mockLogger.ts +118 -88
- package/src/packageVersion.ts +1 -1
- package/src/sampledTelemetryHelper.ts +122 -122
- package/src/telemetryTypes.ts +96 -0
- package/src/thresholdCounter.ts +34 -34
- package/src/utils.ts +15 -15
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +9 -13
package/src/logger.ts
CHANGED
|
@@ -4,48 +4,53 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
import {
|
|
25
|
-
isILoggingError,
|
|
26
|
-
extractLogSafeErrorProperties,
|
|
27
|
-
generateStack,
|
|
21
|
+
isILoggingError,
|
|
22
|
+
extractLogSafeErrorProperties,
|
|
23
|
+
generateStack,
|
|
24
|
+
isTaggedTelemetryPropertyValue,
|
|
28
25
|
} from "./errorLogging";
|
|
26
|
+
import {
|
|
27
|
+
ITaggedTelemetryPropertyTypeExt,
|
|
28
|
+
ITelemetryEventExt,
|
|
29
|
+
ITelemetryGenericEventExt,
|
|
30
|
+
ITelemetryLoggerExt,
|
|
31
|
+
ITelemetryPerformanceEventExt,
|
|
32
|
+
TelemetryEventPropertyTypeExt,
|
|
33
|
+
} from "./telemetryTypes";
|
|
29
34
|
|
|
30
35
|
/**
|
|
31
36
|
* Broad classifications to be applied to individual properties as they're prepared to be logged to telemetry.
|
|
32
37
|
* Please do not modify existing entries for backwards compatibility.
|
|
33
38
|
*/
|
|
34
39
|
export enum TelemetryDataTag {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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",
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
export type TelemetryEventPropertyTypes = TelemetryEventPropertyType | ITaggedTelemetryPropertyType;
|
|
42
47
|
|
|
43
48
|
export interface ITelemetryLoggerPropertyBag {
|
|
44
|
-
|
|
49
|
+
[index: string]: TelemetryEventPropertyTypes | (() => TelemetryEventPropertyTypes);
|
|
45
50
|
}
|
|
46
|
-
export interface ITelemetryLoggerPropertyBags{
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
export interface ITelemetryLoggerPropertyBags {
|
|
52
|
+
all?: ITelemetryLoggerPropertyBag;
|
|
53
|
+
error?: ITelemetryLoggerPropertyBag;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
/**
|
|
@@ -53,170 +58,178 @@ export interface ITelemetryLoggerPropertyBags{
|
|
|
53
58
|
* encoding in one place schemas for various types of Fluid telemetry events.
|
|
54
59
|
* Creates sub-logger that appends properties to all events
|
|
55
60
|
*/
|
|
56
|
-
export abstract class TelemetryLogger implements
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
61
|
+
export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
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
|
+
}
|
|
220
233
|
}
|
|
221
234
|
|
|
222
235
|
/**
|
|
@@ -224,46 +237,45 @@ export abstract class TelemetryLogger implements ITelemetryLogger {
|
|
|
224
237
|
* container-runtime. Issue: #8191
|
|
225
238
|
* TaggedLoggerAdapter class can add tag handling to your logger.
|
|
226
239
|
*/
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
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
|
+
}
|
|
267
279
|
}
|
|
268
280
|
|
|
269
281
|
/**
|
|
@@ -272,81 +284,78 @@ export abstract class TelemetryLogger implements ITelemetryLogger {
|
|
|
272
284
|
* Creates sub-logger that appends properties to all events
|
|
273
285
|
*/
|
|
274
286
|
export class ChildLogger extends TelemetryLogger {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
public send(event: ITelemetryBaseEvent): void {
|
|
348
|
-
this.baseLogger.send(this.prepareEvent(event));
|
|
349
|
-
}
|
|
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
|
+
}
|
|
350
359
|
}
|
|
351
360
|
|
|
352
361
|
/**
|
|
@@ -355,41 +364,39 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
355
364
|
* Implements ITelemetryBaseLogger (through static create() method)
|
|
356
365
|
*/
|
|
357
366
|
export class MultiSinkLogger extends TelemetryLogger {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
});
|
|
392
|
-
}
|
|
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
|
+
}
|
|
393
400
|
}
|
|
394
401
|
|
|
395
402
|
/**
|
|
@@ -399,129 +406,135 @@ export class MultiSinkLogger extends TelemetryLogger {
|
|
|
399
406
|
* success / failure tracking, including duration (on success).
|
|
400
407
|
*/
|
|
401
408
|
export interface IPerformanceEventMarkers {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
409
|
+
start?: true;
|
|
410
|
+
end?: true;
|
|
411
|
+
cancel?: "generic" | "error"; // tells wether to issue "generic" or "error" category cancel event
|
|
405
412
|
}
|
|
406
413
|
|
|
407
414
|
/**
|
|
408
415
|
* Helper class to log performance events
|
|
409
416
|
*/
|
|
410
417
|
export class PerformanceEvent {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
+
}
|
|
525
538
|
}
|
|
526
539
|
|
|
527
540
|
/**
|
|
@@ -529,37 +542,34 @@ export class PerformanceEvent {
|
|
|
529
542
|
* It can be used in places where logger instance is required, but events should be not send over.
|
|
530
543
|
*/
|
|
531
544
|
export class TelemetryUTLogger implements ITelemetryLogger {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
console.error(error);
|
|
561
|
-
throw error;
|
|
562
|
-
}
|
|
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
|
+
}
|
|
563
573
|
}
|
|
564
574
|
|
|
565
575
|
/**
|
|
@@ -567,14 +577,14 @@ export class TelemetryUTLogger implements ITelemetryLogger {
|
|
|
567
577
|
* It can be used in places where logger instance is required, but events should be not send over.
|
|
568
578
|
*/
|
|
569
579
|
export class BaseTelemetryNullLogger implements ITelemetryBaseLogger {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
+
}
|
|
578
588
|
}
|
|
579
589
|
|
|
580
590
|
/**
|
|
@@ -582,8 +592,66 @@ export class BaseTelemetryNullLogger implements ITelemetryBaseLogger {
|
|
|
582
592
|
* It can be used in places where logger instance is required, but events should be not send over.
|
|
583
593
|
*/
|
|
584
594
|
export class TelemetryNullLogger implements ITelemetryLogger {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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 {}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Takes in an event object, and converts all of its values to a basePropertyType.
|
|
603
|
+
* In the case of an invalid property type, the value will be converted to an error string.
|
|
604
|
+
* @param event - Event with fields you want to stringify.
|
|
605
|
+
*/
|
|
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;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Takes in value, and does one of 4 things.
|
|
620
|
+
* if value is of primitive type - returns the original value.
|
|
621
|
+
* If the value is an array of primitives - returns a stringified version of the array.
|
|
622
|
+
* If the value is an object of type ITaggedTelemetryPropertyType - returns the object
|
|
623
|
+
* with its values recursively converted to base property Type.
|
|
624
|
+
* If none of these cases are reached - returns an error string
|
|
625
|
+
* @param x - value passed in to convert to a base property type
|
|
626
|
+
*/
|
|
627
|
+
export function convertToBasePropertyType(
|
|
628
|
+
x: TelemetryEventPropertyTypeExt | ITaggedTelemetryPropertyTypeExt,
|
|
629
|
+
): TelemetryEventPropertyType | ITaggedTelemetryPropertyType {
|
|
630
|
+
return isTaggedTelemetryPropertyValue(x)
|
|
631
|
+
? {
|
|
632
|
+
value: convertToBasePropertyTypeUntagged(x.value),
|
|
633
|
+
tag: x.tag,
|
|
634
|
+
}
|
|
635
|
+
: convertToBasePropertyTypeUntagged(x);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function convertToBasePropertyTypeUntagged(
|
|
639
|
+
x: TelemetryEventPropertyTypeExt,
|
|
640
|
+
): TelemetryEventPropertyType {
|
|
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
|
+
}
|
|
589
657
|
}
|