@fluidframework/telemetry-utils 2.0.0-internal.6.1.1 → 2.0.0-internal.6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +2 -1
- package/CHANGELOG.md +59 -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 +34 -18
- 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 +3 -3
- package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/dist/eventEmitterWithErrorHandling.js +10 -3
- 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 +2 -1
- 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 +38 -22
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +68 -21
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +17 -6
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +22 -9
- 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 +13 -11
- package/dist/sampledTelemetryHelper.js.map +1 -1
- package/dist/telemetryTypes.d.ts +20 -6
- 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 +34 -18
- 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 +3 -3
- package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/lib/eventEmitterWithErrorHandling.js +9 -2
- 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 +2 -1
- 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 +38 -22
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js +64 -17
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +17 -6
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +22 -9
- 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 +11 -9
- package/lib/sampledTelemetryHelper.js.map +1 -1
- package/lib/telemetryTypes.d.ts +20 -6
- 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 +15 -18
- package/src/config.ts +12 -7
- package/src/error.ts +202 -0
- package/src/errorLogging.ts +90 -52
- package/src/eventEmitterWithErrorHandling.ts +5 -3
- package/src/events.ts +3 -3
- package/src/fluidErrorBase.ts +62 -26
- package/src/index.ts +8 -0
- package/src/logger.ts +143 -45
- package/src/mockLogger.ts +33 -16
- package/src/sampledTelemetryHelper.ts +18 -14
- package/src/telemetryTypes.ts +29 -6
- 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,
|
|
@@ -70,4 +77,5 @@ export {
|
|
|
70
77
|
ITelemetryLoggerExt,
|
|
71
78
|
ITaggedTelemetryPropertyTypeExt,
|
|
72
79
|
ITelemetryPropertiesExt,
|
|
80
|
+
TelemetryEventCategory,
|
|
73
81
|
} from "./telemetryTypes";
|
package/src/logger.ts
CHANGED
|
@@ -10,11 +10,12 @@ import {
|
|
|
10
10
|
ITelemetryGenericEvent,
|
|
11
11
|
ITelemetryPerformanceEvent,
|
|
12
12
|
ITelemetryProperties,
|
|
13
|
-
TelemetryEventPropertyType,
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
TelemetryBaseEventPropertyType as TelemetryEventPropertyType,
|
|
14
|
+
LogLevel,
|
|
15
|
+
Tagged,
|
|
16
|
+
ITelemetryBaseProperties,
|
|
16
17
|
} from "@fluidframework/core-interfaces";
|
|
17
|
-
import { IsomorphicPerformance, performance } from "@
|
|
18
|
+
import { IsomorphicPerformance, performance } from "@fluid-internal/client-utils";
|
|
18
19
|
import { CachedConfigProvider, loggerIsMonitoringContext, mixinMonitoringContext } from "./config";
|
|
19
20
|
import {
|
|
20
21
|
isILoggingError,
|
|
@@ -23,12 +24,12 @@ import {
|
|
|
23
24
|
isTaggedTelemetryPropertyValue,
|
|
24
25
|
} from "./errorLogging";
|
|
25
26
|
import {
|
|
26
|
-
ITaggedTelemetryPropertyTypeExt,
|
|
27
27
|
ITelemetryEventExt,
|
|
28
28
|
ITelemetryGenericEventExt,
|
|
29
29
|
ITelemetryLoggerExt,
|
|
30
30
|
ITelemetryPerformanceEventExt,
|
|
31
31
|
TelemetryEventPropertyTypeExt,
|
|
32
|
+
TelemetryEventCategory,
|
|
32
33
|
} from "./telemetryTypes";
|
|
33
34
|
|
|
34
35
|
export interface Memory {
|
|
@@ -43,13 +44,17 @@ export interface PerformanceWithMemory extends IsomorphicPerformance {
|
|
|
43
44
|
* Please do not modify existing entries for backwards compatibility.
|
|
44
45
|
*/
|
|
45
46
|
export enum TelemetryDataTag {
|
|
46
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Data containing terms or IDs from code packages that may have been dynamically loaded
|
|
49
|
+
*/
|
|
47
50
|
CodeArtifact = "CodeArtifact",
|
|
48
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Personal data of a variety of classifications that pertains to the user
|
|
53
|
+
*/
|
|
49
54
|
UserData = "UserData",
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
export type TelemetryEventPropertyTypes =
|
|
57
|
+
export type TelemetryEventPropertyTypes = ITelemetryBaseProperties[string];
|
|
53
58
|
|
|
54
59
|
export interface ITelemetryLoggerPropertyBag {
|
|
55
60
|
[index: string]: TelemetryEventPropertyTypes | (() => TelemetryEventPropertyTypes);
|
|
@@ -65,6 +70,7 @@ export interface ITelemetryLoggerPropertyBags {
|
|
|
65
70
|
* Used to make telemetry data typed (and support math operations, like comparison),
|
|
66
71
|
* in places where we do expect numbers (like contentsize/duration property in http header)
|
|
67
72
|
*/
|
|
73
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
68
74
|
export function numberFromString(str: string | null | undefined): string | number | undefined {
|
|
69
75
|
if (str === undefined || str === null) {
|
|
70
76
|
return undefined;
|
|
@@ -83,12 +89,11 @@ export const eventNamespaceSeparator = ":" as const;
|
|
|
83
89
|
* TelemetryLogger class contains various helper telemetry methods,
|
|
84
90
|
* encoding in one place schemas for various types of Fluid telemetry events.
|
|
85
91
|
* Creates sub-logger that appends properties to all events
|
|
86
|
-
*
|
|
87
92
|
*/
|
|
88
93
|
export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
89
94
|
public static readonly eventNamespaceSeparator = eventNamespaceSeparator;
|
|
90
95
|
|
|
91
|
-
public static sanitizePkgName(name: string) {
|
|
96
|
+
public static sanitizePkgName(name: string): string {
|
|
92
97
|
return name.replace("@", "").replace("/", "-");
|
|
93
98
|
}
|
|
94
99
|
|
|
@@ -99,7 +104,11 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
99
104
|
* @param error - Error to extract info from
|
|
100
105
|
* @param fetchStack - Whether to fetch the current callstack if error.stack is undefined
|
|
101
106
|
*/
|
|
102
|
-
public static prepareErrorObject(
|
|
107
|
+
public static prepareErrorObject(
|
|
108
|
+
event: ITelemetryBaseEvent,
|
|
109
|
+
error: unknown,
|
|
110
|
+
fetchStack: boolean,
|
|
111
|
+
): void {
|
|
103
112
|
const { message, errorType, stack } = extractLogSafeErrorProperties(
|
|
104
113
|
error,
|
|
105
114
|
true /* sanitizeStack */,
|
|
@@ -137,16 +146,26 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
137
146
|
*
|
|
138
147
|
* @param event - the event to send
|
|
139
148
|
*/
|
|
140
|
-
public abstract send(event: ITelemetryBaseEvent): void;
|
|
149
|
+
public abstract send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void;
|
|
141
150
|
|
|
142
151
|
/**
|
|
143
152
|
* Send a telemetry event with the logger
|
|
144
153
|
*
|
|
145
154
|
* @param event - the event to send
|
|
146
155
|
* @param error - optional error object to log
|
|
156
|
+
* @param logLevel - optional level of the log. It category of event is set as error,
|
|
157
|
+
* then the logLevel will be upgraded to be an error.
|
|
147
158
|
*/
|
|
148
|
-
public sendTelemetryEvent(
|
|
149
|
-
|
|
159
|
+
public sendTelemetryEvent(
|
|
160
|
+
event: ITelemetryGenericEventExt,
|
|
161
|
+
error?: unknown,
|
|
162
|
+
logLevel: typeof LogLevel.verbose | typeof LogLevel.default = LogLevel.default,
|
|
163
|
+
): void {
|
|
164
|
+
this.sendTelemetryEventCore(
|
|
165
|
+
{ ...event, category: event.category ?? "generic" },
|
|
166
|
+
error,
|
|
167
|
+
event.category === "error" ? LogLevel.error : logLevel,
|
|
168
|
+
);
|
|
150
169
|
}
|
|
151
170
|
|
|
152
171
|
/**
|
|
@@ -154,11 +173,13 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
154
173
|
*
|
|
155
174
|
* @param event - the event to send
|
|
156
175
|
* @param error - optional error object to log
|
|
176
|
+
* @param logLevel - optional level of the log.
|
|
157
177
|
*/
|
|
158
178
|
protected sendTelemetryEventCore(
|
|
159
179
|
event: ITelemetryGenericEventExt & { category: TelemetryEventCategory },
|
|
160
|
-
error?:
|
|
161
|
-
|
|
180
|
+
error?: unknown,
|
|
181
|
+
logLevel?: LogLevel,
|
|
182
|
+
): void {
|
|
162
183
|
const newEvent = convertToBaseEvent(event);
|
|
163
184
|
if (error !== undefined) {
|
|
164
185
|
TelemetryLogger.prepareErrorObject(newEvent, error, false);
|
|
@@ -169,7 +190,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
169
190
|
newEvent.duration = formatTick(newEvent.duration);
|
|
170
191
|
}
|
|
171
192
|
|
|
172
|
-
this.send(newEvent);
|
|
193
|
+
this.send(newEvent, logLevel);
|
|
173
194
|
}
|
|
174
195
|
|
|
175
196
|
/**
|
|
@@ -178,7 +199,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
178
199
|
* @param event - the event to send
|
|
179
200
|
* @param error - optional error object to log
|
|
180
201
|
*/
|
|
181
|
-
public sendErrorEvent(event: ITelemetryErrorEvent, error?:
|
|
202
|
+
public sendErrorEvent(event: ITelemetryErrorEvent, error?: unknown): void {
|
|
182
203
|
this.sendTelemetryEventCore(
|
|
183
204
|
{
|
|
184
205
|
// ensure the error field has some value,
|
|
@@ -188,6 +209,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
188
209
|
category: "error",
|
|
189
210
|
},
|
|
190
211
|
error,
|
|
212
|
+
LogLevel.error,
|
|
191
213
|
);
|
|
192
214
|
}
|
|
193
215
|
|
|
@@ -196,14 +218,24 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
196
218
|
*
|
|
197
219
|
* @param event - Event to send
|
|
198
220
|
* @param error - optional error object to log
|
|
221
|
+
* @param logLevel - optional level of the log. It category of event is set as error,
|
|
222
|
+
* then the logLevel will be upgraded to be an error.
|
|
199
223
|
*/
|
|
200
|
-
public sendPerformanceEvent(
|
|
224
|
+
public sendPerformanceEvent(
|
|
225
|
+
event: ITelemetryPerformanceEventExt,
|
|
226
|
+
error?: unknown,
|
|
227
|
+
logLevel: typeof LogLevel.verbose | typeof LogLevel.default = LogLevel.default,
|
|
228
|
+
): void {
|
|
201
229
|
const perfEvent = {
|
|
202
230
|
...event,
|
|
203
231
|
category: event.category ?? "performance",
|
|
204
232
|
};
|
|
205
233
|
|
|
206
|
-
this.sendTelemetryEventCore(
|
|
234
|
+
this.sendTelemetryEventCore(
|
|
235
|
+
perfEvent,
|
|
236
|
+
error,
|
|
237
|
+
perfEvent.category === "error" ? LogLevel.error : logLevel,
|
|
238
|
+
);
|
|
207
239
|
}
|
|
208
240
|
|
|
209
241
|
protected prepareEvent(event: ITelemetryBaseEvent): ITelemetryBaseEvent {
|
|
@@ -220,7 +252,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
220
252
|
private extendProperties<T extends ITelemetryLoggerPropertyBag = ITelemetryLoggerPropertyBag>(
|
|
221
253
|
toExtend: T,
|
|
222
254
|
includeErrorProps: boolean,
|
|
223
|
-
) {
|
|
255
|
+
): T {
|
|
224
256
|
const eventLike: ITelemetryLoggerPropertyBag = toExtend;
|
|
225
257
|
if (this.properties) {
|
|
226
258
|
const properties: (undefined | ITelemetryLoggerPropertyBag)[] = [];
|
|
@@ -257,7 +289,10 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
257
289
|
export class TaggedLoggerAdapter implements ITelemetryBaseLogger {
|
|
258
290
|
public constructor(private readonly logger: ITelemetryBaseLogger) {}
|
|
259
291
|
|
|
260
|
-
|
|
292
|
+
/**
|
|
293
|
+
* {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.send}
|
|
294
|
+
*/
|
|
295
|
+
public send(eventWithTagsMaybe: ITelemetryBaseEvent): void {
|
|
261
296
|
const newEvent: ITelemetryBaseEvent = {
|
|
262
297
|
category: eventWithTagsMaybe.category,
|
|
263
298
|
eventName: eventWithTagsMaybe.eventName,
|
|
@@ -368,7 +403,11 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
368
403
|
return child;
|
|
369
404
|
}
|
|
370
405
|
|
|
371
|
-
return new ChildLogger(
|
|
406
|
+
return new ChildLogger(
|
|
407
|
+
baseLogger ? baseLogger : { send(): void {} },
|
|
408
|
+
namespace,
|
|
409
|
+
properties,
|
|
410
|
+
);
|
|
372
411
|
}
|
|
373
412
|
|
|
374
413
|
private constructor(
|
|
@@ -384,13 +423,27 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
384
423
|
}
|
|
385
424
|
}
|
|
386
425
|
|
|
426
|
+
public get minLogLevel(): LogLevel | undefined {
|
|
427
|
+
return this.baseLogger.minLogLevel;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private shouldFilterOutEvent(event: ITelemetryBaseEvent, logLevel?: LogLevel): boolean {
|
|
431
|
+
const eventLogLevel = logLevel ?? LogLevel.default;
|
|
432
|
+
const configLogLevel = this.baseLogger.minLogLevel ?? LogLevel.default;
|
|
433
|
+
// Filter out in case event log level is below what is wanted in config.
|
|
434
|
+
return eventLogLevel < configLogLevel;
|
|
435
|
+
}
|
|
436
|
+
|
|
387
437
|
/**
|
|
388
438
|
* Send an event with the logger
|
|
389
439
|
*
|
|
390
440
|
* @param event - the event to send
|
|
391
441
|
*/
|
|
392
|
-
public send(event: ITelemetryBaseEvent): void {
|
|
393
|
-
|
|
442
|
+
public send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void {
|
|
443
|
+
if (this.shouldFilterOutEvent(event, logLevel)) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
this.baseLogger.send(this.prepareEvent(event), logLevel);
|
|
394
447
|
}
|
|
395
448
|
}
|
|
396
449
|
|
|
@@ -419,6 +472,9 @@ export function createMultiSinkLogger(props: {
|
|
|
419
472
|
*/
|
|
420
473
|
export class MultiSinkLogger extends TelemetryLogger {
|
|
421
474
|
protected loggers: ITelemetryBaseLogger[];
|
|
475
|
+
// This is minimum of minLlogLevel of all loggers.
|
|
476
|
+
private _minLogLevelOfAllLoggers: LogLevel;
|
|
477
|
+
|
|
422
478
|
/**
|
|
423
479
|
* Create multiple sink logger (i.e. logger that sends events to multiple sinks)
|
|
424
480
|
* @param namespace - Telemetry event name prefix to add to all events
|
|
@@ -438,8 +494,11 @@ export class MultiSinkLogger extends TelemetryLogger {
|
|
|
438
494
|
loggers
|
|
439
495
|
.filter((l): l is this => l instanceof TelemetryLogger)
|
|
440
496
|
.map((l) => l.properties ?? {})
|
|
497
|
+
// eslint-disable-next-line unicorn/no-array-for-each
|
|
441
498
|
.forEach((cv) => {
|
|
499
|
+
// eslint-disable-next-line unicorn/no-array-for-each
|
|
442
500
|
Object.keys(cv).forEach((k) => {
|
|
501
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
443
502
|
merge[k] = { ...cv[k], ...merge?.[k] };
|
|
444
503
|
});
|
|
445
504
|
});
|
|
@@ -447,15 +506,33 @@ export class MultiSinkLogger extends TelemetryLogger {
|
|
|
447
506
|
|
|
448
507
|
super(namespace, realProperties);
|
|
449
508
|
this.loggers = loggers;
|
|
509
|
+
this._minLogLevelOfAllLoggers = LogLevel.default;
|
|
510
|
+
this.calculateMinLogLevel();
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
public get minLogLevel(): LogLevel {
|
|
514
|
+
return this._minLogLevelOfAllLoggers;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
private calculateMinLogLevel(): void {
|
|
518
|
+
if (this.loggers.length > 0) {
|
|
519
|
+
const logLevels: LogLevel[] = [];
|
|
520
|
+
for (const logger of this.loggers) {
|
|
521
|
+
logLevels.push(logger.minLogLevel ?? LogLevel.default);
|
|
522
|
+
}
|
|
523
|
+
this._minLogLevelOfAllLoggers = Math.min(...logLevels) as LogLevel;
|
|
524
|
+
}
|
|
450
525
|
}
|
|
451
526
|
|
|
452
527
|
/**
|
|
453
528
|
* Add logger to send all events to
|
|
454
529
|
* @param logger - Logger to add
|
|
455
530
|
*/
|
|
456
|
-
public addLogger(logger?: ITelemetryBaseLogger) {
|
|
531
|
+
public addLogger(logger?: ITelemetryBaseLogger): void {
|
|
457
532
|
if (logger !== undefined && logger !== null) {
|
|
458
533
|
this.loggers.push(logger);
|
|
534
|
+
// Update in case the logLevel of added logger is less than the current.
|
|
535
|
+
this.calculateMinLogLevel();
|
|
459
536
|
}
|
|
460
537
|
}
|
|
461
538
|
|
|
@@ -466,9 +543,9 @@ export class MultiSinkLogger extends TelemetryLogger {
|
|
|
466
543
|
*/
|
|
467
544
|
public send(event: ITelemetryBaseEvent): void {
|
|
468
545
|
const newEvent = this.prepareEvent(event);
|
|
469
|
-
this.loggers
|
|
546
|
+
for (const logger of this.loggers) {
|
|
470
547
|
logger.send(newEvent);
|
|
471
|
-
}
|
|
548
|
+
}
|
|
472
549
|
}
|
|
473
550
|
}
|
|
474
551
|
|
|
@@ -493,7 +570,7 @@ export class PerformanceEvent {
|
|
|
493
570
|
event: ITelemetryGenericEvent,
|
|
494
571
|
markers?: IPerformanceEventMarkers,
|
|
495
572
|
recordHeapSize: boolean = false,
|
|
496
|
-
) {
|
|
573
|
+
): PerformanceEvent {
|
|
497
574
|
return new PerformanceEvent(logger, event, markers, recordHeapSize);
|
|
498
575
|
}
|
|
499
576
|
|
|
@@ -502,7 +579,7 @@ export class PerformanceEvent {
|
|
|
502
579
|
event: ITelemetryGenericEvent,
|
|
503
580
|
callback: (event: PerformanceEvent) => T,
|
|
504
581
|
markers?: IPerformanceEventMarkers,
|
|
505
|
-
) {
|
|
582
|
+
): T {
|
|
506
583
|
const perfEvent = PerformanceEvent.start(logger, event, markers);
|
|
507
584
|
try {
|
|
508
585
|
const ret = callback(perfEvent);
|
|
@@ -520,7 +597,7 @@ export class PerformanceEvent {
|
|
|
520
597
|
callback: (event: PerformanceEvent) => Promise<T>,
|
|
521
598
|
markers?: IPerformanceEventMarkers,
|
|
522
599
|
recordHeapSize?: boolean,
|
|
523
|
-
) {
|
|
600
|
+
): Promise<T> {
|
|
524
601
|
const perfEvent = PerformanceEvent.start(logger, event, markers, recordHeapSize);
|
|
525
602
|
try {
|
|
526
603
|
const ret = await callback(perfEvent);
|
|
@@ -532,7 +609,7 @@ export class PerformanceEvent {
|
|
|
532
609
|
}
|
|
533
610
|
}
|
|
534
611
|
|
|
535
|
-
public get duration() {
|
|
612
|
+
public get duration(): number {
|
|
536
613
|
return performance.now() - this.startTime;
|
|
537
614
|
}
|
|
538
615
|
|
|
@@ -552,6 +629,7 @@ export class PerformanceEvent {
|
|
|
552
629
|
this.reportEvent("start");
|
|
553
630
|
}
|
|
554
631
|
|
|
632
|
+
// eslint-disable-next-line unicorn/no-null
|
|
555
633
|
if (typeof window === "object" && window != null && window.performance?.mark) {
|
|
556
634
|
this.startMark = `${event.eventName}-start`;
|
|
557
635
|
window.performance.mark(this.startMark);
|
|
@@ -562,7 +640,7 @@ export class PerformanceEvent {
|
|
|
562
640
|
this.reportEvent(eventNameSuffix, props);
|
|
563
641
|
}
|
|
564
642
|
|
|
565
|
-
private autoEnd() {
|
|
643
|
+
private autoEnd(): void {
|
|
566
644
|
// Event might have been cancelled or ended in the callback
|
|
567
645
|
if (this.event && this.markers.end) {
|
|
568
646
|
this.reportEvent("end");
|
|
@@ -577,7 +655,7 @@ export class PerformanceEvent {
|
|
|
577
655
|
this.event = undefined;
|
|
578
656
|
}
|
|
579
657
|
|
|
580
|
-
private performanceEndMark() {
|
|
658
|
+
private performanceEndMark(): void {
|
|
581
659
|
if (this.startMark && this.event) {
|
|
582
660
|
const endMark = `${this.event.eventName}-end`;
|
|
583
661
|
window.performance.mark(endMark);
|
|
@@ -586,7 +664,7 @@ export class PerformanceEvent {
|
|
|
586
664
|
}
|
|
587
665
|
}
|
|
588
666
|
|
|
589
|
-
public cancel(props?: ITelemetryProperties, error?:
|
|
667
|
+
public cancel(props?: ITelemetryProperties, error?: unknown): void {
|
|
590
668
|
if (this.markers.cancel !== undefined) {
|
|
591
669
|
this.reportEvent("cancel", { category: this.markers.cancel, ...props }, error);
|
|
592
670
|
}
|
|
@@ -596,7 +674,11 @@ export class PerformanceEvent {
|
|
|
596
674
|
/**
|
|
597
675
|
* Report the event, if it hasn't already been reported.
|
|
598
676
|
*/
|
|
599
|
-
public reportEvent(
|
|
677
|
+
public reportEvent(
|
|
678
|
+
eventNameSuffix: string,
|
|
679
|
+
props?: ITelemetryProperties,
|
|
680
|
+
error?: unknown,
|
|
681
|
+
): void {
|
|
600
682
|
// There are strange sequences involving multiple Promise chains
|
|
601
683
|
// where the event can be cancelled and then later a callback is invoked
|
|
602
684
|
// and the caller attempts to end directly, e.g. issue #3936. Just return.
|
|
@@ -637,9 +719,9 @@ export class PerformanceEvent {
|
|
|
637
719
|
*/
|
|
638
720
|
export class TelemetryNullLogger implements ITelemetryLoggerExt {
|
|
639
721
|
public send(event: ITelemetryBaseEvent): void {}
|
|
640
|
-
public sendTelemetryEvent(event: ITelemetryGenericEvent, error?:
|
|
641
|
-
public sendErrorEvent(event: ITelemetryErrorEvent, error?:
|
|
642
|
-
public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?:
|
|
722
|
+
public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: unknown): void {}
|
|
723
|
+
public sendErrorEvent(event: ITelemetryErrorEvent, error?: unknown): void {}
|
|
724
|
+
public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: unknown): void {}
|
|
643
725
|
}
|
|
644
726
|
|
|
645
727
|
/**
|
|
@@ -662,15 +744,15 @@ function convertToBaseEvent({
|
|
|
662
744
|
/**
|
|
663
745
|
* Takes in value, and does one of 4 things.
|
|
664
746
|
* if value is of primitive type - returns the original value.
|
|
665
|
-
* If the value is
|
|
666
|
-
* If the value is an object of type
|
|
747
|
+
* If the value is a flat array or object - returns a stringified version of the array/object.
|
|
748
|
+
* If the value is an object of type Tagged<TelemetryEventPropertyType> - returns the object
|
|
667
749
|
* with its values recursively converted to base property Type.
|
|
668
750
|
* If none of these cases are reached - returns an error string
|
|
669
751
|
* @param x - value passed in to convert to a base property type
|
|
670
752
|
*/
|
|
671
753
|
export function convertToBasePropertyType(
|
|
672
|
-
x: TelemetryEventPropertyTypeExt |
|
|
673
|
-
): TelemetryEventPropertyType |
|
|
754
|
+
x: TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>,
|
|
755
|
+
): TelemetryEventPropertyType | Tagged<TelemetryEventPropertyType> {
|
|
674
756
|
return isTaggedTelemetryPropertyValue(x)
|
|
675
757
|
? {
|
|
676
758
|
value: convertToBasePropertyTypeUntagged(x.value),
|
|
@@ -706,9 +788,17 @@ export const tagData = <
|
|
|
706
788
|
>(
|
|
707
789
|
tag: T,
|
|
708
790
|
values: V,
|
|
709
|
-
)
|
|
791
|
+
): {
|
|
792
|
+
[P in keyof V]:
|
|
793
|
+
| {
|
|
794
|
+
value: Exclude<V[P], undefined>;
|
|
795
|
+
tag: T;
|
|
796
|
+
}
|
|
797
|
+
| (V[P] extends undefined ? undefined : never);
|
|
798
|
+
} =>
|
|
710
799
|
(Object.entries(values) as [keyof V, V[keyof V]][])
|
|
711
800
|
.filter((e): e is [keyof V, Exclude<V[keyof V], undefined>] => e[1] !== undefined)
|
|
801
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
712
802
|
.reduce<{
|
|
713
803
|
[P in keyof V]:
|
|
714
804
|
| (V[P] extends undefined ? undefined : never)
|
|
@@ -716,8 +806,16 @@ export const tagData = <
|
|
|
716
806
|
}>((pv, cv) => {
|
|
717
807
|
pv[cv[0]] = { tag, value: cv[1] };
|
|
718
808
|
return pv;
|
|
809
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
719
810
|
}, {} as any);
|
|
720
811
|
|
|
721
812
|
export const tagCodeArtifacts = <T extends Record<string, TelemetryEventPropertyTypeExt>>(
|
|
722
813
|
values: T,
|
|
723
|
-
)
|
|
814
|
+
): {
|
|
815
|
+
[P in keyof T]:
|
|
816
|
+
| {
|
|
817
|
+
value: Exclude<T[P], undefined>;
|
|
818
|
+
tag: TelemetryDataTag.CodeArtifact;
|
|
819
|
+
}
|
|
820
|
+
| (T[P] extends undefined ? undefined : never);
|
|
821
|
+
} => tagData(TelemetryDataTag.CodeArtifact, values);
|