@fluidframework/telemetry-utils 2.0.0-dev-rc.5.0.0.271717 → 2.0.0-dev-rc.5.0.0.272889
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.cjs +1 -1
- package/api-extractor/api-extractor-lint-bundle.json +5 -0
- package/api-extractor/api-extractor-lint-legacy.cjs.json +5 -0
- package/api-extractor/api-extractor-lint-legacy.esm.json +5 -0
- package/api-extractor/api-extractor-lint-public.cjs.json +5 -0
- package/api-extractor/api-extractor-lint-public.esm.json +5 -0
- package/api-extractor.json +1 -1
- package/api-report/telemetry-utils.alpha.api.md +13 -28
- package/api-report/telemetry-utils.beta.api.md +7 -7
- package/api-report/telemetry-utils.public.api.md +7 -7
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/error.d.ts +5 -5
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/errorLogging.d.ts +1 -1
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js +21 -8
- 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.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +3 -5
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +34 -7
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +31 -10
- package/dist/mockLogger.js.map +1 -1
- package/dist/sampledTelemetryHelper.d.ts +6 -2
- package/dist/sampledTelemetryHelper.d.ts.map +1 -1
- package/dist/sampledTelemetryHelper.js +10 -2
- package/dist/sampledTelemetryHelper.js.map +1 -1
- package/dist/telemetryEventBatcher.d.ts +4 -27
- package/dist/telemetryEventBatcher.d.ts.map +1 -1
- package/dist/telemetryEventBatcher.js +5 -28
- package/dist/telemetryEventBatcher.js.map +1 -1
- package/dist/telemetryTypes.d.ts +32 -18
- package/dist/telemetryTypes.d.ts.map +1 -1
- package/dist/telemetryTypes.js.map +1 -1
- package/dist/thresholdCounter.d.ts +1 -1
- package/dist/thresholdCounter.d.ts.map +1 -1
- package/dist/thresholdCounter.js.map +1 -1
- package/dist/utils.d.ts +13 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +16 -1
- package/dist/utils.js.map +1 -1
- package/lib/config.d.ts +2 -2
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/error.d.ts +5 -5
- package/lib/error.d.ts.map +1 -1
- package/lib/error.js.map +1 -1
- package/lib/errorLogging.d.ts +1 -1
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js +21 -8
- 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.map +1 -1
- package/lib/index.d.ts +8 -8
- 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 +3 -5
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +34 -7
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +29 -9
- package/lib/mockLogger.js.map +1 -1
- package/lib/sampledTelemetryHelper.d.ts +6 -2
- package/lib/sampledTelemetryHelper.d.ts.map +1 -1
- package/lib/sampledTelemetryHelper.js +10 -2
- package/lib/sampledTelemetryHelper.js.map +1 -1
- package/lib/telemetryEventBatcher.d.ts +4 -27
- package/lib/telemetryEventBatcher.d.ts.map +1 -1
- package/lib/telemetryEventBatcher.js +5 -28
- package/lib/telemetryEventBatcher.js.map +1 -1
- package/lib/telemetryTypes.d.ts +32 -18
- package/lib/telemetryTypes.d.ts.map +1 -1
- package/lib/telemetryTypes.js.map +1 -1
- package/lib/thresholdCounter.d.ts +1 -1
- package/lib/thresholdCounter.d.ts.map +1 -1
- package/lib/thresholdCounter.js.map +1 -1
- package/lib/utils.d.ts +13 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +14 -0
- package/lib/utils.js.map +1 -1
- package/package.json +18 -9
- package/src/config.ts +16 -16
- package/src/error.ts +13 -13
- package/src/errorLogging.ts +31 -15
- package/src/eventEmitterWithErrorHandling.ts +3 -3
- package/src/index.ts +17 -12
- package/src/logger.ts +21 -21
- package/src/mockLogger.ts +71 -21
- package/src/sampledTelemetryHelper.ts +15 -5
- package/src/telemetryEventBatcher.ts +6 -47
- package/src/telemetryTypes.ts +38 -19
- package/src/thresholdCounter.ts +1 -1
- package/src/utils.ts +17 -2
- package/tsdoc.json +4 -0
package/src/config.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import type {
|
|
7
7
|
ConfigTypes,
|
|
8
8
|
IConfigProviderBase,
|
|
9
9
|
ITelemetryBaseLogger,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import { Lazy } from "@fluidframework/core-utils/internal";
|
|
12
12
|
|
|
13
13
|
import { createChildLogger, tagCodeArtifacts } from "./logger.js";
|
|
14
|
-
import { ITelemetryLoggerExt } from "./telemetryTypes.js";
|
|
14
|
+
import type { ITelemetryLoggerExt } from "./telemetryTypes.js";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Explicitly typed interface for reading configurations.
|
|
@@ -193,7 +193,7 @@ export class CachedConfigProvider implements IConfigProvider {
|
|
|
193
193
|
private readonly configCache = new Map<string, StronglyTypedValue>();
|
|
194
194
|
private readonly orderedBaseProviders: (IConfigProviderBase | undefined)[];
|
|
195
195
|
|
|
196
|
-
constructor(
|
|
196
|
+
public constructor(
|
|
197
197
|
private readonly logger?: ITelemetryBaseLogger,
|
|
198
198
|
...orderedBaseProviders: (IConfigProviderBase | undefined)[]
|
|
199
199
|
) {
|
|
@@ -216,26 +216,26 @@ export class CachedConfigProvider implements IConfigProvider {
|
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
|
-
getBoolean(name: string): boolean | undefined {
|
|
219
|
+
public getBoolean(name: string): boolean | undefined {
|
|
220
220
|
return this.getCacheEntry(name)?.boolean;
|
|
221
221
|
}
|
|
222
|
-
getNumber(name: string): number | undefined {
|
|
222
|
+
public getNumber(name: string): number | undefined {
|
|
223
223
|
return this.getCacheEntry(name)?.number;
|
|
224
224
|
}
|
|
225
|
-
getString(name: string): string | undefined {
|
|
225
|
+
public getString(name: string): string | undefined {
|
|
226
226
|
return this.getCacheEntry(name)?.string;
|
|
227
227
|
}
|
|
228
|
-
getBooleanArray(name: string): boolean[] | undefined {
|
|
228
|
+
public getBooleanArray(name: string): boolean[] | undefined {
|
|
229
229
|
return this.getCacheEntry(name)?.["boolean[]"];
|
|
230
230
|
}
|
|
231
|
-
getNumberArray(name: string): number[] | undefined {
|
|
231
|
+
public getNumberArray(name: string): number[] | undefined {
|
|
232
232
|
return this.getCacheEntry(name)?.["number[]"];
|
|
233
233
|
}
|
|
234
|
-
getStringArray(name: string): string[] | undefined {
|
|
234
|
+
public getStringArray(name: string): string[] | undefined {
|
|
235
235
|
return this.getCacheEntry(name)?.["string[]"];
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
getRawConfig(name: string): ConfigTypes {
|
|
238
|
+
public getRawConfig(name: string): ConfigTypes {
|
|
239
239
|
return this.getCacheEntry(name)?.raw;
|
|
240
240
|
}
|
|
241
241
|
|
|
@@ -279,9 +279,9 @@ export interface MonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLo
|
|
|
279
279
|
*
|
|
280
280
|
* @internal
|
|
281
281
|
*/
|
|
282
|
-
export function loggerIsMonitoringContext<
|
|
283
|
-
|
|
284
|
-
): obj is L & MonitoringContext<L> {
|
|
282
|
+
export function loggerIsMonitoringContext<
|
|
283
|
+
L extends ITelemetryBaseLogger = ITelemetryLoggerExt,
|
|
284
|
+
>(obj: L): obj is L & MonitoringContext<L> {
|
|
285
285
|
const maybeConfig = obj as Partial<MonitoringContext<L>> | undefined;
|
|
286
286
|
return isConfigProviderBase(maybeConfig?.config) && maybeConfig?.logger !== undefined;
|
|
287
287
|
}
|
|
@@ -291,9 +291,9 @@ export function loggerIsMonitoringContext<L extends ITelemetryBaseLogger = ITele
|
|
|
291
291
|
*
|
|
292
292
|
* @internal
|
|
293
293
|
*/
|
|
294
|
-
export function loggerToMonitoringContext<
|
|
295
|
-
|
|
296
|
-
): MonitoringContext<L> {
|
|
294
|
+
export function loggerToMonitoringContext<
|
|
295
|
+
L extends ITelemetryBaseLogger = ITelemetryLoggerExt,
|
|
296
|
+
>(logger: L): MonitoringContext<L> {
|
|
297
297
|
if (loggerIsMonitoringContext<L>(logger)) {
|
|
298
298
|
return logger;
|
|
299
299
|
}
|
package/src/error.ts
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IErrorBase, ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
|
|
6
|
+
import type { IErrorBase, ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
|
|
7
7
|
import {
|
|
8
8
|
FluidErrorTypes,
|
|
9
|
-
IGenericError,
|
|
10
|
-
IUsageError,
|
|
9
|
+
type IGenericError,
|
|
10
|
+
type IUsageError,
|
|
11
11
|
} from "@fluidframework/core-interfaces/internal";
|
|
12
|
-
import { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
|
|
12
|
+
import type { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
LoggingError,
|
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
normalizeError,
|
|
19
19
|
wrapError,
|
|
20
20
|
} from "./errorLogging.js";
|
|
21
|
-
import { IFluidErrorBase } from "./fluidErrorBase.js";
|
|
22
|
-
import { ITelemetryPropertiesExt } from "./telemetryTypes.js";
|
|
21
|
+
import type { IFluidErrorBase } from "./fluidErrorBase.js";
|
|
22
|
+
import type { ITelemetryPropertiesExt } from "./telemetryTypes.js";
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Throws a UsageError with the given message if the condition is not met.
|
|
@@ -46,7 +46,7 @@ export function validatePrecondition(
|
|
|
46
46
|
* @internal
|
|
47
47
|
*/
|
|
48
48
|
export class GenericError extends LoggingError implements IGenericError, IFluidErrorBase {
|
|
49
|
-
readonly errorType = FluidErrorTypes.genericError;
|
|
49
|
+
public readonly errorType = FluidErrorTypes.genericError;
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Create a new GenericError
|
|
@@ -54,7 +54,7 @@ export class GenericError extends LoggingError implements IGenericError, IFluidE
|
|
|
54
54
|
* @param error - inner error object
|
|
55
55
|
* @param props - Telemetry props to include when the error is logged
|
|
56
56
|
*/
|
|
57
|
-
constructor(
|
|
57
|
+
public constructor(
|
|
58
58
|
message: string,
|
|
59
59
|
// TODO: Use `unknown` instead (API breaking change because error is not just an input parameter, but a public member of the class)
|
|
60
60
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
|
@@ -72,9 +72,9 @@ export class GenericError extends LoggingError implements IGenericError, IFluidE
|
|
|
72
72
|
* @internal
|
|
73
73
|
*/
|
|
74
74
|
export class UsageError extends LoggingError implements IUsageError, IFluidErrorBase {
|
|
75
|
-
readonly errorType = FluidErrorTypes.usageError;
|
|
75
|
+
public readonly errorType = FluidErrorTypes.usageError;
|
|
76
76
|
|
|
77
|
-
constructor(message: string, props?: ITelemetryBaseProperties) {
|
|
77
|
+
public constructor(message: string, props?: ITelemetryBaseProperties) {
|
|
78
78
|
super(message, { ...props, usageError: true });
|
|
79
79
|
}
|
|
80
80
|
}
|
|
@@ -86,10 +86,10 @@ export class UsageError extends LoggingError implements IUsageError, IFluidError
|
|
|
86
86
|
* @internal
|
|
87
87
|
*/
|
|
88
88
|
export class DataCorruptionError extends LoggingError implements IErrorBase, IFluidErrorBase {
|
|
89
|
-
readonly errorType = FluidErrorTypes.dataCorruptionError;
|
|
90
|
-
readonly canRetry = false;
|
|
89
|
+
public readonly errorType = FluidErrorTypes.dataCorruptionError;
|
|
90
|
+
public readonly canRetry = false;
|
|
91
91
|
|
|
92
|
-
constructor(message: string, props: ITelemetryBaseProperties) {
|
|
92
|
+
public constructor(message: string, props: ITelemetryBaseProperties) {
|
|
93
93
|
super(message, { ...props, dataProcessingError: 1 });
|
|
94
94
|
}
|
|
95
95
|
}
|
package/src/errorLogging.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { ITelemetryBaseProperties, Tagged } from "@fluidframework/core-inte
|
|
|
7
7
|
import type { ILoggingError } from "@fluidframework/core-interfaces/internal";
|
|
8
8
|
import { v4 as uuid } from "uuid";
|
|
9
9
|
|
|
10
|
-
import { IFluidErrorBase, hasErrorInstanceId, isFluidError } from "./fluidErrorBase.js";
|
|
10
|
+
import { type IFluidErrorBase, hasErrorInstanceId, isFluidError } from "./fluidErrorBase.js";
|
|
11
11
|
import { convertToBasePropertyType } from "./logger.js";
|
|
12
12
|
import type {
|
|
13
13
|
ITelemetryLoggerExt,
|
|
@@ -157,7 +157,12 @@ export function normalizeError(
|
|
|
157
157
|
|
|
158
158
|
const errorTelemetryProps = LoggingError.typeCheck(error)
|
|
159
159
|
? error.getTelemetryProperties()
|
|
160
|
-
: {
|
|
160
|
+
: {
|
|
161
|
+
untrustedOrigin: 1, // This will let us filter errors that did not originate from our own codebase
|
|
162
|
+
// FUTURE: Once 2.0 becomes LTS, switch to this more explicit property name
|
|
163
|
+
// Consider using a string to distinguish cases like "dependency" v. "callback"
|
|
164
|
+
// errorRunningExternalCode: 1,
|
|
165
|
+
};
|
|
161
166
|
|
|
162
167
|
fluidError.addTelemetryProperties({
|
|
163
168
|
...errorTelemetryProps,
|
|
@@ -221,7 +226,10 @@ export function wrapError<T extends LoggingError>(
|
|
|
221
226
|
innerError: unknown,
|
|
222
227
|
newErrorFn: (message: string) => T,
|
|
223
228
|
): T {
|
|
224
|
-
const { message, stack } = extractLogSafeErrorProperties(
|
|
229
|
+
const { message, stack } = extractLogSafeErrorProperties(
|
|
230
|
+
innerError,
|
|
231
|
+
false /* sanitizeStack */,
|
|
232
|
+
);
|
|
225
233
|
|
|
226
234
|
const newError = newErrorFn(message);
|
|
227
235
|
|
|
@@ -231,7 +239,12 @@ export function wrapError<T extends LoggingError>(
|
|
|
231
239
|
|
|
232
240
|
// Mark external errors with untrustedOrigin flag
|
|
233
241
|
if (isExternalError(innerError)) {
|
|
234
|
-
newError.addTelemetryProperties({
|
|
242
|
+
newError.addTelemetryProperties({
|
|
243
|
+
untrustedOrigin: 1,
|
|
244
|
+
// FUTURE: Once 2.0 becomes LTS, switch to this more explicit property name
|
|
245
|
+
// Consider using a string to distinguish cases like "dependency" v. "callback"
|
|
246
|
+
// errorRunningExternalCode: 1,
|
|
247
|
+
});
|
|
235
248
|
}
|
|
236
249
|
|
|
237
250
|
// Reuse errorInstanceId
|
|
@@ -243,7 +256,7 @@ export function wrapError<T extends LoggingError>(
|
|
|
243
256
|
}
|
|
244
257
|
|
|
245
258
|
// Lastly, copy over all other telemetry properties. Note these will not overwrite existing properties
|
|
246
|
-
// This will include the untrustedOrigin
|
|
259
|
+
// This will include the untrustedOrigin/errorRunningExternalCode info if the inner error itself was created from an external error
|
|
247
260
|
if (isILoggingError(innerError)) {
|
|
248
261
|
newError.addTelemetryProperties(innerError.getTelemetryProperties());
|
|
249
262
|
}
|
|
@@ -308,11 +321,14 @@ export function overwriteStack(error: IFluidErrorBase | LoggingError, stack: str
|
|
|
308
321
|
*/
|
|
309
322
|
export function isExternalError(error: unknown): boolean {
|
|
310
323
|
// LoggingErrors are an internal FF error type. However, an external error can be converted
|
|
311
|
-
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin flag to
|
|
312
|
-
// determine whether the original error was
|
|
324
|
+
// into a LoggingError if it is normalized. In this case we must use the untrustedOrigin/errorRunningExternalCode flag to
|
|
325
|
+
// determine whether the original error was in fact external.
|
|
313
326
|
if (LoggingError.typeCheck(error)) {
|
|
314
327
|
if ((error as NormalizedLoggingError).errorType === NORMALIZED_ERROR_TYPE) {
|
|
315
|
-
|
|
328
|
+
const props = error.getTelemetryProperties();
|
|
329
|
+
// NOTE: errorRunningExternalCode is not currently used - once this "read" code reaches LTS,
|
|
330
|
+
// we can switch to writing this more explicit property
|
|
331
|
+
return props.untrustedOrigin === 1 || !!props.errorRunningExternalCode;
|
|
316
332
|
}
|
|
317
333
|
return false;
|
|
318
334
|
}
|
|
@@ -331,6 +347,8 @@ export function isTaggedTelemetryPropertyValue(
|
|
|
331
347
|
return typeof (x as Partial<Tagged<unknown>>)?.tag === "string";
|
|
332
348
|
}
|
|
333
349
|
|
|
350
|
+
// TODO: Use `unknown` instead (API breaking change)
|
|
351
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
334
352
|
/**
|
|
335
353
|
* Borrowed from
|
|
336
354
|
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples}
|
|
@@ -340,8 +358,6 @@ export function isTaggedTelemetryPropertyValue(
|
|
|
340
358
|
*
|
|
341
359
|
* @internal
|
|
342
360
|
*/
|
|
343
|
-
// TODO: Use `unknown` instead (API breaking change)
|
|
344
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
345
361
|
export const getCircularReplacer = (): ((key: string, value: unknown) => any) => {
|
|
346
362
|
const seen = new WeakSet();
|
|
347
363
|
return (key: string, value: unknown): any => {
|
|
@@ -370,10 +386,10 @@ export class LoggingError
|
|
|
370
386
|
implements ILoggingError, Omit<IFluidErrorBase, "errorType">
|
|
371
387
|
{
|
|
372
388
|
private _errorInstanceId = uuid();
|
|
373
|
-
get errorInstanceId(): string {
|
|
389
|
+
public get errorInstanceId(): string {
|
|
374
390
|
return this._errorInstanceId;
|
|
375
391
|
}
|
|
376
|
-
overwriteErrorInstanceId(id: string): void {
|
|
392
|
+
public overwriteErrorInstanceId(id: string): void {
|
|
377
393
|
this._errorInstanceId = id;
|
|
378
394
|
}
|
|
379
395
|
|
|
@@ -383,7 +399,7 @@ export class LoggingError
|
|
|
383
399
|
* @param props - telemetry props to include on the error for when it's logged
|
|
384
400
|
* @param omitPropsFromLogging - properties by name to omit from telemetry props
|
|
385
401
|
*/
|
|
386
|
-
constructor(
|
|
402
|
+
public constructor(
|
|
387
403
|
message: string,
|
|
388
404
|
props?: ITelemetryBaseProperties,
|
|
389
405
|
private readonly omitPropsFromLogging: Set<string> = new Set(),
|
|
@@ -464,9 +480,9 @@ export const NORMALIZED_ERROR_TYPE = "genericError";
|
|
|
464
480
|
class NormalizedLoggingError extends LoggingError {
|
|
465
481
|
// errorType "genericError" is used as a default value throughout the code.
|
|
466
482
|
// Note that this matches ContainerErrorTypes/DriverErrorTypes' genericError
|
|
467
|
-
errorType = NORMALIZED_ERROR_TYPE;
|
|
483
|
+
public readonly errorType = NORMALIZED_ERROR_TYPE;
|
|
468
484
|
|
|
469
|
-
constructor(errorProps: Pick<IFluidErrorBase, "message" | "stack">) {
|
|
485
|
+
public constructor(errorProps: Pick<IFluidErrorBase, "message" | "stack">) {
|
|
470
486
|
super(errorProps.message);
|
|
471
487
|
|
|
472
488
|
if (errorProps.stack !== undefined) {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { EventEmitterEventType, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
7
|
-
import { IEvent } from "@fluidframework/core-interfaces";
|
|
6
|
+
import { type EventEmitterEventType, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
7
|
+
import type { IEvent } from "@fluidframework/core-interfaces";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Event Emitter helper class
|
|
@@ -20,7 +20,7 @@ import { IEvent } from "@fluidframework/core-interfaces";
|
|
|
20
20
|
export class EventEmitterWithErrorHandling<
|
|
21
21
|
TEvent extends IEvent = IEvent,
|
|
22
22
|
> extends TypedEventEmitter<TEvent> {
|
|
23
|
-
constructor(
|
|
23
|
+
public constructor(
|
|
24
24
|
// TODO: use `unknown` instead (breaking API change)
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
26
|
private readonly errorHandler: (eventName: EventEmitterEventType, error: any) => void,
|
package/src/index.ts
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
export {
|
|
7
7
|
createChildMonitoringContext,
|
|
8
|
-
MonitoringContext,
|
|
8
|
+
type MonitoringContext,
|
|
9
9
|
sessionStorageConfigProvider,
|
|
10
10
|
mixinMonitoringContext,
|
|
11
|
-
IConfigProvider,
|
|
11
|
+
type IConfigProvider,
|
|
12
12
|
loggerToMonitoringContext,
|
|
13
13
|
wrapConfigProviderWithDefaults,
|
|
14
14
|
} from "./config.js";
|
|
@@ -25,7 +25,7 @@ export {
|
|
|
25
25
|
generateErrorWithStack,
|
|
26
26
|
generateStack,
|
|
27
27
|
getCircularReplacer,
|
|
28
|
-
IFluidErrorAnnotations,
|
|
28
|
+
type IFluidErrorAnnotations,
|
|
29
29
|
isExternalError,
|
|
30
30
|
isILoggingError,
|
|
31
31
|
isTaggedTelemetryPropertyValue,
|
|
@@ -43,29 +43,34 @@ export {
|
|
|
43
43
|
raiseConnectedEvent,
|
|
44
44
|
safeRaiseEvent,
|
|
45
45
|
} from "./events.js";
|
|
46
|
-
export { hasErrorInstanceId, IFluidErrorBase, isFluidError } from "./fluidErrorBase.js";
|
|
46
|
+
export { hasErrorInstanceId, type IFluidErrorBase, isFluidError } from "./fluidErrorBase.js";
|
|
47
47
|
export {
|
|
48
48
|
eventNamespaceSeparator,
|
|
49
49
|
createChildLogger,
|
|
50
50
|
createMultiSinkLogger,
|
|
51
51
|
formatTick,
|
|
52
|
-
IPerformanceEventMarkers,
|
|
53
|
-
ITelemetryLoggerPropertyBag,
|
|
54
|
-
ITelemetryLoggerPropertyBags,
|
|
55
|
-
MultiSinkLoggerProperties,
|
|
52
|
+
type IPerformanceEventMarkers,
|
|
53
|
+
type ITelemetryLoggerPropertyBag,
|
|
54
|
+
type ITelemetryLoggerPropertyBags,
|
|
55
|
+
type MultiSinkLoggerProperties,
|
|
56
56
|
numberFromString,
|
|
57
57
|
PerformanceEvent,
|
|
58
58
|
TaggedLoggerAdapter,
|
|
59
59
|
tagData,
|
|
60
60
|
tagCodeArtifacts,
|
|
61
61
|
TelemetryDataTag,
|
|
62
|
-
TelemetryEventPropertyTypes,
|
|
62
|
+
type TelemetryEventPropertyTypes,
|
|
63
63
|
} from "./logger.js";
|
|
64
|
-
export { MockLogger } from "./mockLogger.js";
|
|
64
|
+
export { createMockLoggerExt, type IMockLoggerExt, MockLogger } from "./mockLogger.js";
|
|
65
65
|
export { ThresholdCounter } from "./thresholdCounter.js";
|
|
66
66
|
export { SampledTelemetryHelper } from "./sampledTelemetryHelper.js";
|
|
67
|
-
export { createSampledLogger, IEventSampler, ISampledTelemetryLogger } from "./utils.js";
|
|
68
67
|
export {
|
|
68
|
+
createSampledLogger,
|
|
69
|
+
type IEventSampler,
|
|
70
|
+
type ISampledTelemetryLogger,
|
|
71
|
+
measure,
|
|
72
|
+
} from "./utils.js";
|
|
73
|
+
export type {
|
|
69
74
|
TelemetryEventPropertyTypeExt,
|
|
70
75
|
ITelemetryEventExt,
|
|
71
76
|
ITelemetryGenericEventExt,
|
|
@@ -76,4 +81,4 @@ export {
|
|
|
76
81
|
ITelemetryPropertiesExt,
|
|
77
82
|
TelemetryEventCategory,
|
|
78
83
|
} from "./telemetryTypes.js";
|
|
79
|
-
export {
|
|
84
|
+
export { TelemetryEventBatcher } from "./telemetryEventBatcher.js";
|
package/src/logger.ts
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
import { performance } from "@fluid-internal/client-utils";
|
|
7
7
|
import {
|
|
8
|
-
ITelemetryBaseEvent,
|
|
9
|
-
ITelemetryBaseLogger,
|
|
8
|
+
type ITelemetryBaseEvent,
|
|
9
|
+
type ITelemetryBaseLogger,
|
|
10
10
|
LogLevel,
|
|
11
|
-
Tagged,
|
|
12
|
-
TelemetryBaseEventPropertyType,
|
|
11
|
+
type Tagged,
|
|
12
|
+
type TelemetryBaseEventPropertyType,
|
|
13
13
|
} from "@fluidframework/core-interfaces";
|
|
14
14
|
|
|
15
15
|
import {
|
|
@@ -23,8 +23,8 @@ import {
|
|
|
23
23
|
isILoggingError,
|
|
24
24
|
isTaggedTelemetryPropertyValue,
|
|
25
25
|
} from "./errorLogging.js";
|
|
26
|
-
import {
|
|
27
|
-
|
|
26
|
+
import type {
|
|
27
|
+
ITelemetryErrorEventExt,
|
|
28
28
|
ITelemetryEventExt,
|
|
29
29
|
ITelemetryGenericEventExt,
|
|
30
30
|
ITelemetryLoggerExt,
|
|
@@ -60,9 +60,10 @@ export type TelemetryEventPropertyTypes = ITelemetryPropertiesExt[string];
|
|
|
60
60
|
/**
|
|
61
61
|
* @alpha
|
|
62
62
|
*/
|
|
63
|
-
export
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
export type ITelemetryLoggerPropertyBag = Record<
|
|
64
|
+
string,
|
|
65
|
+
TelemetryEventPropertyTypes | (() => TelemetryEventPropertyTypes)
|
|
66
|
+
>;
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
69
|
* @alpha
|
|
@@ -273,10 +274,9 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
273
274
|
return this.extendProperties(newEvent, includeErrorProps);
|
|
274
275
|
}
|
|
275
276
|
|
|
276
|
-
private extendProperties<
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
): T {
|
|
277
|
+
private extendProperties<
|
|
278
|
+
T extends ITelemetryLoggerPropertyBag = ITelemetryLoggerPropertyBag,
|
|
279
|
+
>(toExtend: T, includeErrorProps: boolean): T {
|
|
280
280
|
const eventLike: ITelemetryLoggerPropertyBag = toExtend;
|
|
281
281
|
if (this.properties) {
|
|
282
282
|
const properties: (undefined | ITelemetryLoggerPropertyBag)[] = [];
|
|
@@ -421,8 +421,8 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
421
421
|
baseLogger.namespace === undefined
|
|
422
422
|
? namespace
|
|
423
423
|
: namespace === undefined
|
|
424
|
-
|
|
425
|
-
|
|
424
|
+
? baseLogger.namespace
|
|
425
|
+
: `${baseLogger.namespace}${TelemetryLogger.eventNamespaceSeparator}${namespace}`;
|
|
426
426
|
|
|
427
427
|
const child = new ChildLogger(
|
|
428
428
|
baseLogger.baseLogger,
|
|
@@ -533,7 +533,7 @@ export class MultiSinkLogger extends TelemetryLogger {
|
|
|
533
533
|
* @param loggers - The list of loggers to use as sinks
|
|
534
534
|
* @param tryInheritProperties - Will attempted to copy those loggers properties to this loggers if they are of a known type e.g. one from this package
|
|
535
535
|
*/
|
|
536
|
-
constructor(
|
|
536
|
+
public constructor(
|
|
537
537
|
namespace?: string,
|
|
538
538
|
properties?: ITelemetryLoggerPropertyBags,
|
|
539
539
|
loggers: ITelemetryBaseLogger[] = [],
|
|
@@ -855,7 +855,7 @@ export function convertToBasePropertyType(
|
|
|
855
855
|
? {
|
|
856
856
|
value: convertToBasePropertyTypeUntagged(x.value),
|
|
857
857
|
tag: x.tag,
|
|
858
|
-
|
|
858
|
+
}
|
|
859
859
|
: convertToBasePropertyTypeUntagged(x);
|
|
860
860
|
}
|
|
861
861
|
|
|
@@ -920,11 +920,11 @@ export const tagData = <
|
|
|
920
920
|
? () => {
|
|
921
921
|
value: ReturnType<V[P]>;
|
|
922
922
|
tag: T;
|
|
923
|
-
|
|
923
|
+
}
|
|
924
924
|
: {
|
|
925
925
|
value: Exclude<V[P], undefined>;
|
|
926
926
|
tag: T;
|
|
927
|
-
|
|
927
|
+
})
|
|
928
928
|
| (V[P] extends undefined ? undefined : never);
|
|
929
929
|
} =>
|
|
930
930
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
@@ -982,10 +982,10 @@ export const tagCodeArtifacts = <
|
|
|
982
982
|
? () => {
|
|
983
983
|
value: ReturnType<T[P]>;
|
|
984
984
|
tag: TelemetryDataTag.CodeArtifact;
|
|
985
|
-
|
|
985
|
+
}
|
|
986
986
|
: {
|
|
987
987
|
value: Exclude<T[P], undefined>;
|
|
988
988
|
tag: TelemetryDataTag.CodeArtifact;
|
|
989
|
-
|
|
989
|
+
})
|
|
990
990
|
| (T[P] extends undefined ? undefined : never);
|
|
991
991
|
} => tagData<TelemetryDataTag.CodeArtifact, T>(TelemetryDataTag.CodeArtifact, values);
|
package/src/mockLogger.ts
CHANGED
|
@@ -4,36 +4,55 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
ITelemetryBaseEvent,
|
|
8
|
-
ITelemetryBaseLogger,
|
|
7
|
+
type ITelemetryBaseEvent,
|
|
8
|
+
type ITelemetryBaseLogger,
|
|
9
9
|
LogLevel,
|
|
10
10
|
} from "@fluidframework/core-interfaces";
|
|
11
11
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
12
12
|
|
|
13
13
|
import { createChildLogger } from "./logger.js";
|
|
14
|
-
import {
|
|
14
|
+
import type {
|
|
15
|
+
ITelemetryEventExt,
|
|
16
|
+
ITelemetryLoggerExt,
|
|
17
|
+
ITelemetryPropertiesExt,
|
|
18
|
+
} from "./telemetryTypes.js";
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
21
|
+
* Mock {@link @fluidframework/core-interfaces#ITelemetryBaseLogger} implementation.
|
|
22
|
+
*
|
|
23
|
+
* Records events sent to it, and then can walk back over those events, searching for a set of expected events to
|
|
24
|
+
* match against the logged events.
|
|
19
25
|
*
|
|
20
26
|
* @alpha
|
|
21
27
|
*/
|
|
22
28
|
export class MockLogger implements ITelemetryBaseLogger {
|
|
23
|
-
|
|
29
|
+
// TODO: don't expose mutability to external consumers
|
|
30
|
+
public events: ITelemetryBaseEvent[] = [];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.minLogLevel}
|
|
34
|
+
*/
|
|
35
|
+
public readonly minLogLevel: LogLevel;
|
|
24
36
|
|
|
25
|
-
constructor(
|
|
37
|
+
public constructor(minLogLevel?: LogLevel) {
|
|
38
|
+
this.minLogLevel = minLogLevel ?? LogLevel.default;
|
|
39
|
+
}
|
|
26
40
|
|
|
27
|
-
clear(): void {
|
|
41
|
+
public clear(): void {
|
|
28
42
|
this.events = [];
|
|
29
43
|
}
|
|
30
44
|
|
|
31
|
-
toTelemetryLogger(): ITelemetryLoggerExt {
|
|
45
|
+
public toTelemetryLogger(): ITelemetryLoggerExt {
|
|
32
46
|
return createChildLogger({ logger: this });
|
|
33
47
|
}
|
|
34
48
|
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
/**
|
|
50
|
+
* {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.send}
|
|
51
|
+
*/
|
|
52
|
+
public send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void {
|
|
53
|
+
if (logLevel ?? LogLevel.default >= this.minLogLevel) {
|
|
54
|
+
this.events.push(event);
|
|
55
|
+
}
|
|
37
56
|
}
|
|
38
57
|
|
|
39
58
|
/**
|
|
@@ -44,7 +63,7 @@ export class MockLogger implements ITelemetryBaseLogger {
|
|
|
44
63
|
* These event objects may be subsets of the logged events.
|
|
45
64
|
* Note: category is omitted from the type because it's usually uninteresting and tedious to type.
|
|
46
65
|
*/
|
|
47
|
-
matchEvents(
|
|
66
|
+
public matchEvents(
|
|
48
67
|
expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
|
|
49
68
|
inlineDetailsProp: boolean = false,
|
|
50
69
|
): boolean {
|
|
@@ -60,7 +79,7 @@ export class MockLogger implements ITelemetryBaseLogger {
|
|
|
60
79
|
/**
|
|
61
80
|
* Asserts that matchEvents is true, and prints the actual/expected output if not.
|
|
62
81
|
*/
|
|
63
|
-
assertMatch(
|
|
82
|
+
public assertMatch(
|
|
64
83
|
expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
|
|
65
84
|
message?: string,
|
|
66
85
|
inlineDetailsProp: boolean = false,
|
|
@@ -85,7 +104,7 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
85
104
|
* Note: category is omitted from the type because it's usually uninteresting and tedious to type.
|
|
86
105
|
* @returns if any of the expected events is found.
|
|
87
106
|
*/
|
|
88
|
-
matchAnyEvent(
|
|
107
|
+
public matchAnyEvent(
|
|
89
108
|
expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
|
|
90
109
|
inlineDetailsProp: boolean = false,
|
|
91
110
|
): boolean {
|
|
@@ -99,7 +118,7 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
99
118
|
/**
|
|
100
119
|
* Asserts that matchAnyEvent is true, and prints the actual/expected output if not.
|
|
101
120
|
*/
|
|
102
|
-
assertMatchAny(
|
|
121
|
+
public assertMatchAny(
|
|
103
122
|
expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
|
|
104
123
|
message?: string,
|
|
105
124
|
inlineDetailsProp: boolean = false,
|
|
@@ -123,7 +142,7 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
123
142
|
* These event objects may be subsets of the logged events.
|
|
124
143
|
* Note: category is omitted from the type because it's usually uninteresting and tedious to type.
|
|
125
144
|
*/
|
|
126
|
-
matchEventStrict(
|
|
145
|
+
public matchEventStrict(
|
|
127
146
|
expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
|
|
128
147
|
inlineDetailsProp: boolean = false,
|
|
129
148
|
): boolean {
|
|
@@ -136,7 +155,7 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
136
155
|
/**
|
|
137
156
|
* Asserts that matchEvents is true, and prints the actual/expected output if not
|
|
138
157
|
*/
|
|
139
|
-
assertMatchStrict(
|
|
158
|
+
public assertMatchStrict(
|
|
140
159
|
expectedEvents: Omit<ITelemetryBaseEvent, "category">[],
|
|
141
160
|
message?: string,
|
|
142
161
|
inlineDetailsProp: boolean = false,
|
|
@@ -155,7 +174,7 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
155
174
|
/**
|
|
156
175
|
* Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not
|
|
157
176
|
*/
|
|
158
|
-
assertMatchNone(
|
|
177
|
+
public assertMatchNone(
|
|
159
178
|
disallowedEvents: Omit<ITelemetryBaseEvent, "category">[],
|
|
160
179
|
message?: string,
|
|
161
180
|
inlineDetailsProp: boolean = false,
|
|
@@ -187,7 +206,7 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
187
206
|
}
|
|
188
207
|
|
|
189
208
|
// Remove the events so far; next call will just compare subsequent events from here
|
|
190
|
-
this.
|
|
209
|
+
this.clear();
|
|
191
210
|
|
|
192
211
|
// Return the count of matched events.
|
|
193
212
|
return iExpectedEvent;
|
|
@@ -208,7 +227,6 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
208
227
|
if (inlineDetailsProp && details !== undefined) {
|
|
209
228
|
assert(
|
|
210
229
|
typeof details === "string",
|
|
211
|
-
// eslint-disable-next-line unicorn/numeric-separators-style
|
|
212
230
|
0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,
|
|
213
231
|
);
|
|
214
232
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
@@ -220,7 +238,10 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
220
238
|
}
|
|
221
239
|
}
|
|
222
240
|
|
|
223
|
-
function matchObjects(
|
|
241
|
+
function matchObjects(
|
|
242
|
+
actual: ITelemetryPropertiesExt,
|
|
243
|
+
expected: ITelemetryPropertiesExt,
|
|
244
|
+
): boolean {
|
|
224
245
|
for (const [expectedKey, expectedValue] of Object.entries(expected)) {
|
|
225
246
|
const actualValue = actual[expectedKey];
|
|
226
247
|
if (
|
|
@@ -245,3 +266,32 @@ function matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPrope
|
|
|
245
266
|
}
|
|
246
267
|
return true;
|
|
247
268
|
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Mock {@link ITelemetryLoggerExt} implementation.
|
|
272
|
+
*
|
|
273
|
+
* @remarks Can be created via {@link createMockLoggerExt}.
|
|
274
|
+
*
|
|
275
|
+
* @internal
|
|
276
|
+
*/
|
|
277
|
+
export interface IMockLoggerExt extends ITelemetryLoggerExt {
|
|
278
|
+
/**
|
|
279
|
+
* Gets the events that have been logged so far.
|
|
280
|
+
*/
|
|
281
|
+
events(): readonly ITelemetryEventExt[];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Creates an {@link IMockLoggerExt}.
|
|
286
|
+
*
|
|
287
|
+
* @internal
|
|
288
|
+
*/
|
|
289
|
+
export function createMockLoggerExt(minLogLevel?: LogLevel): IMockLoggerExt {
|
|
290
|
+
const mockLogger = new MockLogger(minLogLevel);
|
|
291
|
+
const childLogger = createChildLogger({ logger: mockLogger });
|
|
292
|
+
Object.assign(childLogger, {
|
|
293
|
+
events: (): readonly ITelemetryEventExt[] =>
|
|
294
|
+
mockLogger.events.map((e) => e as ITelemetryEventExt),
|
|
295
|
+
});
|
|
296
|
+
return childLogger as IMockLoggerExt;
|
|
297
|
+
}
|