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