@fluidframework/telemetry-utils 2.0.0-dev.4.4.0.162253 → 2.0.0-dev.5.2.0.169897
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/CHANGELOG.md +14 -0
- package/dist/config.d.ts +6 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/errorLogging.d.ts +3 -3
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js +13 -2
- package/dist/errorLogging.js.map +1 -1
- package/dist/events.d.ts +3 -3
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/logger.d.ts +16 -10
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +19 -9
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +3 -2
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +1 -1
- package/dist/mockLogger.js.map +1 -1
- package/dist/sampledTelemetryHelper.d.ts +3 -2
- package/dist/sampledTelemetryHelper.d.ts.map +1 -1
- package/dist/sampledTelemetryHelper.js.map +1 -1
- package/dist/telemetryTypes.d.ts +4 -1
- package/dist/telemetryTypes.d.ts.map +1 -1
- package/dist/telemetryTypes.js.map +1 -1
- package/dist/thresholdCounter.d.ts +2 -2
- package/dist/thresholdCounter.d.ts.map +1 -1
- package/dist/thresholdCounter.js.map +1 -1
- package/dist/tsdoc-metadata.json +11 -0
- package/lib/config.d.ts +6 -5
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/errorLogging.d.ts +3 -3
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js +13 -2
- package/lib/errorLogging.js.map +1 -1
- package/lib/events.d.ts +3 -3
- package/lib/events.d.ts.map +1 -1
- package/lib/events.js.map +1 -1
- package/lib/logger.d.ts +16 -10
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js +19 -9
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +3 -2
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +1 -1
- package/lib/mockLogger.js.map +1 -1
- package/lib/sampledTelemetryHelper.d.ts +3 -2
- package/lib/sampledTelemetryHelper.d.ts.map +1 -1
- package/lib/sampledTelemetryHelper.js.map +1 -1
- package/lib/telemetryTypes.d.ts +4 -1
- package/lib/telemetryTypes.d.ts.map +1 -1
- package/lib/telemetryTypes.js.map +1 -1
- package/lib/thresholdCounter.d.ts +2 -2
- package/lib/thresholdCounter.d.ts.map +1 -1
- package/lib/thresholdCounter.js.map +1 -1
- package/package.json +32 -12
- package/src/config.ts +6 -5
- package/src/errorLogging.ts +19 -5
- package/src/events.ts +3 -3
- package/src/logger.ts +35 -14
- package/src/mockLogger.ts +4 -3
- package/src/sampledTelemetryHelper.ts +2 -2
- package/src/telemetryTypes.ts +5 -1
- package/src/thresholdCounter.ts +2 -2
package/lib/mockLogger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger, ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { TelemetryLogger } from \"./logger\";\n\n/**\n * The MockLogger records events sent to it, and then can walk back over those events\n * searching for a set of expected events to match against the logged events.\n */\nexport class MockLogger extends TelemetryLogger implements ITelemetryLogger {\n\tevents: ITelemetryBaseEvent[] = [];\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tclear() {\n\t\tthis.events = [];\n\t}\n\n\tsend(event: ITelemetryBaseEvent): void {\n\t\tthis.events.push(event);\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEvents(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\t// How many expected events were left over? Hopefully none.\n\t\tconst unmatchedExpectedEventCount = expectedEvents.length - matchedExpectedEventCount;\n\t\treturn unmatchedExpectedEventCount === 0;\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatch(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEvents(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for any of the given\n\t * expected events.\n\t * @param expectedEvents - events that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t * @returns if any of the expected events is found.\n\t */\n\tmatchAnyEvent(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\treturn matchedExpectedEventCount > 0;\n\t}\n\n\t/** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */\n\tassertMatchAny(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking only for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to be the only events in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEventStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\treturn (\n\t\t\texpectedEvents.length === this.events.length &&\n\t\t\tthis.matchEvents(expectedEvents, inlineDetailsProp)\n\t\t);\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatchStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */\n\tassertMatchNone(\n\t\tdisallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\ndisallowed events:\n${JSON.stringify(disallowedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\tprivate getMatchedEventsCount(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean,\n\t): number {\n\t\tlet iExpectedEvent = 0;\n\t\tthis.events.forEach((event) => {\n\t\t\tif (\n\t\t\t\tiExpectedEvent < expectedEvents.length &&\n\t\t\t\tMockLogger.eventsMatch(event, expectedEvents[iExpectedEvent], inlineDetailsProp)\n\t\t\t) {\n\t\t\t\t// We found the next expected event; increment\n\t\t\t\t++iExpectedEvent;\n\t\t\t}\n\t\t});\n\n\t\t// Remove the events so far; next call will just compare subsequent events from here\n\t\tthis.events = [];\n\n\t\t// Return the count of matched events.\n\t\treturn iExpectedEvent;\n\t}\n\n\t/**\n\t * Ensure the expected event is a strict subset of the actual event\n\t */\n\tprivate static eventsMatch(\n\t\tactual: ITelemetryBaseEvent,\n\t\texpected: Omit<ITelemetryBaseEvent, \"category\">,\n\t\tinlineDetailsProp: boolean,\n\t): boolean {\n\t\tconst { details, ...actualForMatching } = actual;\n\t\tlet detailsExpanded = { details };\n\t\t// \"details\" is used in a lot of telemetry logs to group a bunch of properties together and stringify them.\n\t\t// Some of the properties in the expected event may be inside \"details\". So, if inlineDetailsProp is true,\n\t\t// extract the properties from \"details\" in the actual event and inline them in the actual event.\n\t\tif (inlineDetailsProp && details !== undefined) {\n\t\t\tassert(\n\t\t\t\ttypeof details === \"string\",\n\t\t\t\t\"Details should a JSON stringified string if inlineDetailsProp is true\",\n\t\t\t);\n\t\t\tdetailsExpanded = JSON.parse(details);\n\t\t}\n\t\tconst actualExpanded: ITelemetryBaseEvent = { ...actualForMatching, ...detailsExpanded };\n\t\tconst masked = { ...actualExpanded, ...expected };\n\t\treturn JSON.stringify(masked) === JSON.stringify(actualExpanded);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { TelemetryLogger } from \"./logger\";\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\n\n/**\n * The MockLogger records events sent to it, and then can walk back over those events\n * searching for a set of expected events to match against the logged events.\n */\nexport class MockLogger extends TelemetryLogger implements ITelemetryLoggerExt {\n\tevents: ITelemetryBaseEvent[] = [];\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tclear() {\n\t\tthis.events = [];\n\t}\n\n\tsend(event: ITelemetryBaseEvent): void {\n\t\tthis.events.push(event);\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEvents(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\t// How many expected events were left over? Hopefully none.\n\t\tconst unmatchedExpectedEventCount = expectedEvents.length - matchedExpectedEventCount;\n\t\treturn unmatchedExpectedEventCount === 0;\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatch(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEvents(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for any of the given\n\t * expected events.\n\t * @param expectedEvents - events that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t * @returns if any of the expected events is found.\n\t */\n\tmatchAnyEvent(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\treturn matchedExpectedEventCount > 0;\n\t}\n\n\t/** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */\n\tassertMatchAny(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking only for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to be the only events in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEventStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\treturn (\n\t\t\texpectedEvents.length === this.events.length &&\n\t\t\tthis.matchEvents(expectedEvents, inlineDetailsProp)\n\t\t);\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatchStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */\n\tassertMatchNone(\n\t\tdisallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\ndisallowed events:\n${JSON.stringify(disallowedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\tprivate getMatchedEventsCount(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean,\n\t): number {\n\t\tlet iExpectedEvent = 0;\n\t\tthis.events.forEach((event) => {\n\t\t\tif (\n\t\t\t\tiExpectedEvent < expectedEvents.length &&\n\t\t\t\tMockLogger.eventsMatch(event, expectedEvents[iExpectedEvent], inlineDetailsProp)\n\t\t\t) {\n\t\t\t\t// We found the next expected event; increment\n\t\t\t\t++iExpectedEvent;\n\t\t\t}\n\t\t});\n\n\t\t// Remove the events so far; next call will just compare subsequent events from here\n\t\tthis.events = [];\n\n\t\t// Return the count of matched events.\n\t\treturn iExpectedEvent;\n\t}\n\n\t/**\n\t * Ensure the expected event is a strict subset of the actual event\n\t */\n\tprivate static eventsMatch(\n\t\tactual: ITelemetryBaseEvent,\n\t\texpected: Omit<ITelemetryBaseEvent, \"category\">,\n\t\tinlineDetailsProp: boolean,\n\t): boolean {\n\t\tconst { details, ...actualForMatching } = actual;\n\t\tlet detailsExpanded = { details };\n\t\t// \"details\" is used in a lot of telemetry logs to group a bunch of properties together and stringify them.\n\t\t// Some of the properties in the expected event may be inside \"details\". So, if inlineDetailsProp is true,\n\t\t// extract the properties from \"details\" in the actual event and inline them in the actual event.\n\t\tif (inlineDetailsProp && details !== undefined) {\n\t\t\tassert(\n\t\t\t\ttypeof details === \"string\",\n\t\t\t\t0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,\n\t\t\t);\n\t\t\tdetailsExpanded = JSON.parse(details);\n\t\t}\n\t\tconst actualExpanded: ITelemetryBaseEvent = { ...actualForMatching, ...detailsExpanded };\n\t\tconst masked = { ...actualExpanded, ...expected };\n\t\treturn JSON.stringify(masked) === JSON.stringify(actualExpanded);\n\t}\n}\n"]}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { IDisposable, ITelemetryGenericEvent,
|
|
5
|
+
import { IDisposable, ITelemetryGenericEvent, ITelemetryProperties } from "@fluidframework/common-definitions";
|
|
6
|
+
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
6
7
|
/**
|
|
7
8
|
* Helper class that executes a specified code block and writes an
|
|
8
9
|
* {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified
|
|
@@ -36,7 +37,7 @@ export declare class SampledTelemetryHelper implements IDisposable {
|
|
|
36
37
|
* them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be
|
|
37
38
|
* ignored.
|
|
38
39
|
*/
|
|
39
|
-
constructor(eventBase: ITelemetryGenericEvent, logger:
|
|
40
|
+
constructor(eventBase: ITelemetryGenericEvent, logger: ITelemetryLoggerExt, sampleThreshold: number, includeAggregateMetrics?: boolean, perBucketProperties?: Map<string, ITelemetryProperties>);
|
|
40
41
|
/**
|
|
41
42
|
* @param codeToMeasure -
|
|
42
43
|
* The code to be executed and measured.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sampledTelemetryHelper.d.ts","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,WAAW,EACX,sBAAsB,
|
|
1
|
+
{"version":3,"file":"sampledTelemetryHelper.d.ts","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,WAAW,EACX,sBAAsB,EAEtB,oBAAoB,EACpB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAiCvD;;;;;;GAMG;AACH,qBAAa,sBAAuB,YAAW,WAAW;IAwBxD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IA3BrC,QAAQ,EAAE,OAAO,CAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IAEnE;;;;;;;;;;;;;;;;;OAiBG;gBAEe,SAAS,EAAE,sBAAsB,EACjC,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,oCAA0C;IAG/E;;;;;;;;OAQG;IACI,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,GAAE,MAAW,GAAG,CAAC;IA0BjE,OAAO,CAAC,WAAW;IAoBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAG/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAkC3D;;;;;;GAMG;AACH,MAAM,OAAO,sBAAsB;IAKlC;;;;;;;;;;;;;;;;;OAiBG;IACH,YACkB,SAAiC,EACjC,MAA2B,EAC3B,eAAuB,EACvB,0BAAmC,KAAK,EACxC,sBAAsB,IAAI,GAAG,EAAgC;QAJ7D,cAAS,GAAT,SAAS,CAAwB;QACjC,WAAM,GAAN,MAAM,CAAqB;QAC3B,oBAAe,GAAf,eAAe,CAAQ;QACvB,4BAAuB,GAAvB,uBAAuB,CAAiB;QACxC,wBAAmB,GAAnB,mBAAmB,CAA0C;QA3B/E,aAAQ,GAAY,KAAK,CAAC;QAET,oBAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;IA0BhE,CAAC;IAEJ;;;;;;;;OAQG;IACI,OAAO,CAAI,aAAsB,EAAE,SAAiB,EAAE;;QAC5D,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAE3C,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,SAAS,EAAE;YACpB,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;SACpC;QACD,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEtB,IAAI,IAAI,CAAC,uBAAuB,EAAE;YACjC,CAAC,CAAC,aAAa,GAAG,CAAC,MAAA,CAAC,CAAC,aAAa,mCAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YACpD,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAA,CAAC,CAAC,WAAW,mCAAI,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9D,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAA,CAAC,CAAC,WAAW,mCAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;SACvD;QAED,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACpC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;SACzB;QAED,OAAO,WAAW,CAAC;IACpB,CAAC;IAEO,WAAW,CAAC,MAAc;QACjC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,YAAY,KAAK,SAAS,EAAE;YAC/B,OAAO;SACP;QAED,IAAI,YAAY,CAAC,KAAK,KAAK,CAAC,EAAE;YAC7B,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAE9D,MAAM,cAAc,iDAChB,IAAI,CAAC,SAAS,GACd,gBAAgB,GAChB,YAAY,CACf,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SACpC;IACF,CAAC;IAEM,OAAO,CAAC,KAAyB;QACvC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tIDisposable,\n\tITelemetryGenericEvent,\n\tITelemetryPerformanceEvent,\n\tITelemetryProperties,\n} from \"@fluidframework/common-definitions\";\nimport { performance } from \"@fluidframework/common-utils\";\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\n\ninterface Measurements {\n\t// The names of the properties in this interface are the ones that will get stamped in the\n\t// telemetry event, changes should be considered carefully. The optional properties should\n\t// only be populated if 'includeAggregateMetrics' is true.\n\n\t/**\n\t * The duration of the latest execution.\n\t */\n\tduration: number;\n\n\t/**\n\t * The number of executions since the last time an event was generated.\n\t */\n\tcount: number;\n\n\t/**\n\t * Total duration across all the executions since the last event was generated.\n\t */\n\ttotalDuration?: number;\n\n\t/**\n\t * Min duration across all the executions since the last event was generated.\n\t */\n\tminDuration?: number;\n\n\t/**\n\t * Max duration across all the executions since the last event was generated.\n\t */\n\tmaxDuration?: number;\n}\n\n/**\n * Helper class that executes a specified code block and writes an\n * {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified\n * number of executions is reached (or when the class is disposed). The `duration` field in the telemetry event is\n * the duration of the latest execution (sample) of the specified function. See the documentation of the\n * `includeAggregateMetrics` parameter for additional details that can be included.\n */\nexport class SampledTelemetryHelper implements IDisposable {\n\tdisposed: boolean = false;\n\n\tprivate readonly measurementsMap = new Map<string, Measurements>();\n\n\t/**\n\t * @param eventBase -\n\t * Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger -\n\t * The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold -\n\t * Telemetry performance events will be generated every time we hit this many executions of the code block.\n\t * @param includeAggregateMetrics -\n\t * If set to `true`, the telemetry performance event will include aggregated metrics (total duration, min duration,\n\t * max duration) for all the executions in between generated events.\n\t * @param perBucketProperties -\n\t * Map of strings that represent different buckets (which can be specified when calling the 'measure' method), to\n\t * properties which should be added to the telemetry event for that bucket. If a bucket being measured does not\n\t * have an entry in this map, no additional properties will be added to its telemetry events. The following keys are\n\t * reserved for use by this class: \"duration\", \"count\", \"totalDuration\", \"minDuration\", \"maxDuration\". If any of\n\t * them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be\n\t * ignored.\n\t */\n\tpublic constructor(\n\t\tprivate readonly eventBase: ITelemetryGenericEvent,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly sampleThreshold: number,\n\t\tprivate readonly includeAggregateMetrics: boolean = false,\n\t\tprivate readonly perBucketProperties = new Map<string, ITelemetryProperties>(),\n\t) {}\n\n\t/**\n\t * @param codeToMeasure -\n\t * The code to be executed and measured.\n\t * @param bucket -\n\t * A key to track executions of the code block separately. Each different value of this parameter has a separate\n\t * set of executions and metrics tracked by the class. If no such distinction needs to be made, do not provide a\n\t * value.\n\t * @returns Whatever the passed-in code block returns.\n\t */\n\tpublic measure<T>(codeToMeasure: () => T, bucket: string = \"\"): T {\n\t\tconst start = performance.now();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performance.now() - start;\n\n\t\tlet m = this.measurementsMap.get(bucket);\n\t\tif (m === undefined) {\n\t\t\tm = { count: 0, duration: -1 };\n\t\t\tthis.measurementsMap.set(bucket, m);\n\t\t}\n\t\tm.count++;\n\t\tm.duration = duration;\n\n\t\tif (this.includeAggregateMetrics) {\n\t\t\tm.totalDuration = (m.totalDuration ?? 0) + duration;\n\t\t\tm.minDuration = Math.min(m.minDuration ?? duration, duration);\n\t\t\tm.maxDuration = Math.max(m.maxDuration ?? 0, duration);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate flushBucket(bucket: string) {\n\t\tconst measurements = this.measurementsMap.get(bucket);\n\t\tif (measurements === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (measurements.count !== 0) {\n\t\t\tconst bucketProperties = this.perBucketProperties.get(bucket);\n\n\t\t\tconst telemetryEvent: ITelemetryPerformanceEvent = {\n\t\t\t\t...this.eventBase,\n\t\t\t\t...bucketProperties, // If the bucket doesn't exist and this is undefined, things work as expected\n\t\t\t\t...measurements,\n\t\t\t};\n\n\t\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\t\t\tthis.measurementsMap.delete(bucket);\n\t\t}\n\t}\n\n\tpublic dispose(error?: Error | undefined): void {\n\t\tthis.measurementsMap.forEach((_, k) => this.flushBucket(k));\n\t}\n}\n"]}
|
package/lib/telemetryTypes.d.ts
CHANGED
|
@@ -7,7 +7,10 @@ import { ITelemetryBaseLogger, TelemetryEventCategory } from "@fluidframework/co
|
|
|
7
7
|
* Property types that can be logged.
|
|
8
8
|
* Includes extra types beyond TelemetryEventPropertyType (which will be deprecated in favor of this one)
|
|
9
9
|
*/
|
|
10
|
-
export declare type TelemetryEventPropertyTypeExt = string | number | boolean | undefined | (string | number | boolean)[]
|
|
10
|
+
export declare type TelemetryEventPropertyTypeExt = string | number | boolean | undefined | (string | number | boolean)[] | {
|
|
11
|
+
[key: string]: // Flat objects can have the same properties as the event itself
|
|
12
|
+
string | number | boolean | undefined | (string | number | boolean)[];
|
|
13
|
+
};
|
|
11
14
|
/**
|
|
12
15
|
* A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used
|
|
13
16
|
* to mark pieces of information that should be organized or handled differently by loggers in various first or third
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetryTypes.d.ts","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAElG;;;GAGG;AACH,oBAAY,6BAA6B,GACtC,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"telemetryTypes.d.ts","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAElG;;;GAGG;AACH,oBAAY,6BAA6B,GACtC,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,GAC7B;IACA,CAAC,GAAG,EAAE,MAAM,GACZ,AADe,gEAAgE;IAC/E,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;CACrE,CAAC;AAEL;;;;GAIG;AACH,MAAM,WAAW,+BAA+B;IAC/C,KAAK,EAAE,6BAA6B,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,CAAC,KAAK,EAAE,MAAM,GAAG,6BAA6B,GAAG,+BAA+B,CAAC;CACjF;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACvE,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,6BAA8B,SAAQ,yBAAyB;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,oBAAoB;IAChE;;;;OAIG;IACH,kBAAkB,CAAC,KAAK,EAAE,yBAAyB,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IAExE;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,uBAAuB,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;IAElE;;;OAGG;IACH,oBAAoB,CAAC,KAAK,EAAE,6BAA6B,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;CAC9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetryTypes.js","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseLogger, TelemetryEventCategory } from \"@fluidframework/common-definitions\";\n\n/**\n * Property types that can be logged.\n * Includes extra types beyond TelemetryEventPropertyType (which will be deprecated in favor of this one)\n */\nexport type TelemetryEventPropertyTypeExt =\n\t| string\n\t| number\n\t| boolean\n\t| undefined\n\t| (string | number | boolean)[];\n\n/**\n * A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used\n * to mark pieces of information that should be organized or handled differently by loggers in various first or third\n * party scenarios. For example, tags are used to mark personal information that should not be stored in logs.\n */\nexport interface ITaggedTelemetryPropertyTypeExt {\n\tvalue: TelemetryEventPropertyTypeExt;\n\ttag: string;\n}\n\n/**\n * JSON-serializable properties, which will be logged with telemetry.\n */\nexport interface ITelemetryPropertiesExt {\n\t[index: string]: TelemetryEventPropertyTypeExt | ITaggedTelemetryPropertyTypeExt;\n}\n\n/**\n * Interface for logging telemetry statements.\n * Can contain any number of properties that get serialized as json payload.\n * @param category - category of the event, like \"error\", \"performance\", \"generic\", etc.\n * @param eventName - name of the event.\n */\nexport interface ITelemetryEventExt extends ITelemetryPropertiesExt {\n\tcategory: string;\n\teventName: string;\n}\n\n/**\n * Informational (non-error) telemetry event\n * Maps to category = \"generic\"\n */\nexport interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n\tcategory?: TelemetryEventCategory;\n}\n\n/**\n * Error telemetry event.\n * Maps to category = \"error\"\n */\nexport interface ITelemetryErrorEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n}\n\n/**\n * Performance telemetry event.\n * Maps to category = \"performance\"\n */\nexport interface ITelemetryPerformanceEventExt extends ITelemetryGenericEventExt {\n\tduration?: number; // Duration of event (optional)\n}\n\n/**\n * An extended TelemetryLogger interface which allows for more lenient event types.\n * This interface is meant to be used internally within the Fluid Framework,\n * and ITelemetryBaseLogger should be used when loggers are passed between layers.\n */\nexport interface ITelemetryLoggerExt extends ITelemetryBaseLogger {\n\t/**\n\t * Send information telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t */\n\tsendTelemetryEvent(event: ITelemetryGenericEventExt, error?: any): void;\n\n\t/**\n\t * Send error telemetry event\n\t * @param event - Event to send\n\t */\n\tsendErrorEvent(event: ITelemetryErrorEventExt, error?: any): void;\n\n\t/**\n\t * Send performance telemetry event\n\t * @param event - Event to send\n\t */\n\tsendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: any): void;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"telemetryTypes.js","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseLogger, TelemetryEventCategory } from \"@fluidframework/common-definitions\";\n\n/**\n * Property types that can be logged.\n * Includes extra types beyond TelemetryEventPropertyType (which will be deprecated in favor of this one)\n */\nexport type TelemetryEventPropertyTypeExt =\n\t| string\n\t| number\n\t| boolean\n\t| undefined\n\t| (string | number | boolean)[]\n\t| {\n\t\t\t[key: string]: // Flat objects can have the same properties as the event itself\n\t\t\tstring | number | boolean | undefined | (string | number | boolean)[];\n\t };\n\n/**\n * A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used\n * to mark pieces of information that should be organized or handled differently by loggers in various first or third\n * party scenarios. For example, tags are used to mark personal information that should not be stored in logs.\n */\nexport interface ITaggedTelemetryPropertyTypeExt {\n\tvalue: TelemetryEventPropertyTypeExt;\n\ttag: string;\n}\n\n/**\n * JSON-serializable properties, which will be logged with telemetry.\n */\nexport interface ITelemetryPropertiesExt {\n\t[index: string]: TelemetryEventPropertyTypeExt | ITaggedTelemetryPropertyTypeExt;\n}\n\n/**\n * Interface for logging telemetry statements.\n * Can contain any number of properties that get serialized as json payload.\n * @param category - category of the event, like \"error\", \"performance\", \"generic\", etc.\n * @param eventName - name of the event.\n */\nexport interface ITelemetryEventExt extends ITelemetryPropertiesExt {\n\tcategory: string;\n\teventName: string;\n}\n\n/**\n * Informational (non-error) telemetry event\n * Maps to category = \"generic\"\n */\nexport interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n\tcategory?: TelemetryEventCategory;\n}\n\n/**\n * Error telemetry event.\n * Maps to category = \"error\"\n */\nexport interface ITelemetryErrorEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n}\n\n/**\n * Performance telemetry event.\n * Maps to category = \"performance\"\n */\nexport interface ITelemetryPerformanceEventExt extends ITelemetryGenericEventExt {\n\tduration?: number; // Duration of event (optional)\n}\n\n/**\n * An extended TelemetryLogger interface which allows for more lenient event types.\n * This interface is meant to be used internally within the Fluid Framework,\n * and ITelemetryBaseLogger should be used when loggers are passed between layers.\n */\nexport interface ITelemetryLoggerExt extends ITelemetryBaseLogger {\n\t/**\n\t * Send information telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t */\n\tsendTelemetryEvent(event: ITelemetryGenericEventExt, error?: any): void;\n\n\t/**\n\t * Send error telemetry event\n\t * @param event - Event to send\n\t */\n\tsendErrorEvent(event: ITelemetryErrorEventExt, error?: any): void;\n\n\t/**\n\t * Send performance telemetry event\n\t * @param event - Event to send\n\t */\n\tsendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: any): void;\n}\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
6
6
|
/**
|
|
7
7
|
* Utility counter which will send event only if the provided value
|
|
8
8
|
* is above a configured threshold
|
|
@@ -11,7 +11,7 @@ export declare class ThresholdCounter {
|
|
|
11
11
|
private readonly threshold;
|
|
12
12
|
private readonly logger;
|
|
13
13
|
private thresholdMultiple;
|
|
14
|
-
constructor(threshold: number, logger:
|
|
14
|
+
constructor(threshold: number, logger: ITelemetryLoggerExt, thresholdMultiple?: number);
|
|
15
15
|
/**
|
|
16
16
|
* Sends the value if it's above the treshold.
|
|
17
17
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thresholdCounter.d.ts","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"thresholdCounter.d.ts","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;GAGG;AACH,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,iBAAiB;gBAFR,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,mBAAmB,EACpC,iBAAiB,SAAY;IAGtC;;OAEG;IACI,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAU5C;;;;;;OAMG;IACI,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAUtD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAC5B,YACkB,SAAiB,EACjB,
|
|
1
|
+
{"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAC5B,YACkB,SAAiB,EACjB,MAA2B,EACpC,oBAAoB,SAAS;QAFpB,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAqB;QACpC,sBAAiB,GAAjB,iBAAiB,CAAY;IACnC,CAAC;IAEJ;;OAEG;IACI,IAAI,CAAC,SAAiB,EAAE,KAAa;QAC3C,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;YAC3B,OAAO;SACP;QACD,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,SAAS;YACT,KAAK;SACL,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,SAAiB,EAAE,KAAa;QACrD,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB,EAAE;YACrC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS;gBACT,KAAK;aACL,CAAC,CAAC;YACH,sCAAsC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;SACpD;IACF,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\n\n/**\n * Utility counter which will send event only if the provided value\n * is above a configured threshold\n */\nexport class ThresholdCounter {\n\tpublic constructor(\n\t\tprivate readonly threshold: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate thresholdMultiple = threshold,\n\t) {}\n\n\t/**\n\t * Sends the value if it's above the treshold.\n\t */\n\tpublic send(eventName: string, value: number) {\n\t\tif (value < this.threshold) {\n\t\t\treturn;\n\t\t}\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName,\n\t\t\tvalue,\n\t\t});\n\t}\n\n\t/**\n\t * Sends the value if it's above the threshold\n\t * and a multiple of the threshold.\n\t *\n\t * To be used in scenarios where we'd like to record a\n\t * threshold violation while reducing telemetry noise.\n\t */\n\tpublic sendIfMultiple(eventName: string, value: number) {\n\t\tif (value === this.thresholdMultiple) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName,\n\t\t\t\tvalue,\n\t\t\t});\n\t\t\t// reduce number of \"multiple\" events.\n\t\t\tthis.thresholdMultiple = this.thresholdMultiple * 2;\n\t\t}\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/telemetry-utils",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.5.2.0.169897",
|
|
4
4
|
"description": "Collection of telemetry relates utilities for Fluid",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"uuid": "^8.3.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@fluid-tools/build-cli": "^0.
|
|
50
|
-
"@fluidframework/build-common": "^1.
|
|
51
|
-
"@fluidframework/build-tools": "^0.
|
|
49
|
+
"@fluid-tools/build-cli": "^0.20.0-169245",
|
|
50
|
+
"@fluidframework/build-common": "^1.2.0",
|
|
51
|
+
"@fluidframework/build-tools": "^0.20.0-169245",
|
|
52
52
|
"@fluidframework/eslint-config-fluid": "^2.0.0",
|
|
53
|
-
"@fluidframework/mocha-test-setup": "2.0.0-dev.
|
|
54
|
-
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.0.0-internal.
|
|
53
|
+
"@fluidframework/mocha-test-setup": "2.0.0-dev.5.2.0.169897",
|
|
54
|
+
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.0.0-internal.5.0.0",
|
|
55
55
|
"@microsoft/api-extractor": "^7.34.4",
|
|
56
56
|
"@types/debug": "^4.1.5",
|
|
57
57
|
"@types/events": "^3.0.0",
|
|
@@ -73,16 +73,36 @@
|
|
|
73
73
|
"typescript": "~4.5.5"
|
|
74
74
|
},
|
|
75
75
|
"typeValidation": {
|
|
76
|
-
"broken": {
|
|
76
|
+
"broken": {
|
|
77
|
+
"InterfaceDeclaration_ITaggedTelemetryPropertyTypeExt": {
|
|
78
|
+
"backCompat": false
|
|
79
|
+
},
|
|
80
|
+
"InterfaceDeclaration_ITelemetryErrorEventExt": {
|
|
81
|
+
"backCompat": false
|
|
82
|
+
},
|
|
83
|
+
"InterfaceDeclaration_ITelemetryEventExt": {
|
|
84
|
+
"backCompat": false
|
|
85
|
+
},
|
|
86
|
+
"InterfaceDeclaration_ITelemetryGenericEventExt": {
|
|
87
|
+
"backCompat": false
|
|
88
|
+
},
|
|
89
|
+
"InterfaceDeclaration_ITelemetryPerformanceEventExt": {
|
|
90
|
+
"backCompat": false
|
|
91
|
+
},
|
|
92
|
+
"InterfaceDeclaration_ITelemetryPropertiesExt": {
|
|
93
|
+
"backCompat": false
|
|
94
|
+
},
|
|
95
|
+
"TypeAliasDeclaration_TelemetryEventPropertyTypeExt": {
|
|
96
|
+
"backCompat": false
|
|
97
|
+
}
|
|
98
|
+
}
|
|
77
99
|
},
|
|
78
100
|
"scripts": {
|
|
79
|
-
"build": "
|
|
80
|
-
"build:commonjs": "
|
|
81
|
-
"build:compile": "
|
|
101
|
+
"build": "fluid-build . --task build",
|
|
102
|
+
"build:commonjs": "fluid-build . --task commonjs",
|
|
103
|
+
"build:compile": "fluid-build . --task compile",
|
|
82
104
|
"build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
|
|
83
105
|
"build:esnext": "tsc --project ./tsconfig.esnext.json",
|
|
84
|
-
"build:full": "npm run build",
|
|
85
|
-
"build:full:compile": "npm run build:compile",
|
|
86
106
|
"build:test": "tsc --project ./src/test/tsconfig.json",
|
|
87
107
|
"bump-version": "npm version minor --no-push --no-git-tag-version && npm run build:genver",
|
|
88
108
|
"ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
|
package/src/config.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { ITelemetryBaseLogger
|
|
5
|
+
import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
|
|
6
6
|
import { Lazy } from "@fluidframework/common-utils";
|
|
7
7
|
import { TelemetryDataTag } from "./logger";
|
|
8
|
+
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
8
9
|
|
|
9
10
|
export type ConfigTypes = string | number | boolean | number[] | string[] | boolean[] | undefined;
|
|
10
11
|
|
|
@@ -240,19 +241,19 @@ export class CachedConfigProvider implements IConfigProvider {
|
|
|
240
241
|
/**
|
|
241
242
|
* A type containing both a telemetry logger and a configuration provider
|
|
242
243
|
*/
|
|
243
|
-
export interface MonitoringContext<L extends ITelemetryBaseLogger =
|
|
244
|
+
export interface MonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt> {
|
|
244
245
|
config: IConfigProvider;
|
|
245
246
|
logger: L;
|
|
246
247
|
}
|
|
247
248
|
|
|
248
|
-
export function loggerIsMonitoringContext<L extends ITelemetryBaseLogger =
|
|
249
|
+
export function loggerIsMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(
|
|
249
250
|
obj: L,
|
|
250
251
|
): obj is L & MonitoringContext<L> {
|
|
251
252
|
const maybeConfig = obj as Partial<MonitoringContext<L>> | undefined;
|
|
252
253
|
return isConfigProviderBase(maybeConfig?.config) && maybeConfig?.logger !== undefined;
|
|
253
254
|
}
|
|
254
255
|
|
|
255
|
-
export function loggerToMonitoringContext<L extends ITelemetryBaseLogger =
|
|
256
|
+
export function loggerToMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(
|
|
256
257
|
logger: L,
|
|
257
258
|
): MonitoringContext<L> {
|
|
258
259
|
if (loggerIsMonitoringContext<L>(logger)) {
|
|
@@ -261,7 +262,7 @@ export function loggerToMonitoringContext<L extends ITelemetryBaseLogger = ITele
|
|
|
261
262
|
return mixinMonitoringContext<L>(logger, sessionStorageConfigProvider.value);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
export function mixinMonitoringContext<L extends ITelemetryBaseLogger =
|
|
265
|
+
export function mixinMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(
|
|
265
266
|
logger: L,
|
|
266
267
|
...configs: (IConfigProviderBase | undefined)[]
|
|
267
268
|
) {
|
package/src/errorLogging.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import {
|
|
7
7
|
ILoggingError,
|
|
8
8
|
ITaggedTelemetryPropertyType,
|
|
9
|
-
ITelemetryLogger,
|
|
10
9
|
ITelemetryProperties,
|
|
11
10
|
TelemetryEventPropertyType,
|
|
12
11
|
} from "@fluidframework/common-definitions";
|
|
@@ -17,7 +16,11 @@ import {
|
|
|
17
16
|
isFluidError,
|
|
18
17
|
isValidLegacyError,
|
|
19
18
|
} from "./fluidErrorBase";
|
|
20
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
ITaggedTelemetryPropertyTypeExt,
|
|
21
|
+
ITelemetryLoggerExt,
|
|
22
|
+
TelemetryEventPropertyTypeExt,
|
|
23
|
+
} from "./telemetryTypes";
|
|
21
24
|
|
|
22
25
|
/** @returns true if value is an object but neither null nor an array */
|
|
23
26
|
const isRegularObject = (value: any): boolean => {
|
|
@@ -121,8 +124,19 @@ export function normalizeError(
|
|
|
121
124
|
// Anywhere they are set should be on a valid Fluid Error that would have been returned above,
|
|
122
125
|
// but we can't prove it with the types, so adding this defensive measure.
|
|
123
126
|
if (typeof error === "object" && error !== null) {
|
|
124
|
-
const
|
|
125
|
-
|
|
127
|
+
const maybeHasRetry: Partial<Record<"canRetry" | "retryAfterSeconds", unknown>> = error;
|
|
128
|
+
let retryProps: Partial<Record<"canRetry" | "retryAfterSeconds", unknown>> | undefined;
|
|
129
|
+
if ("canRetry" in error) {
|
|
130
|
+
retryProps ??= {};
|
|
131
|
+
retryProps.canRetry = maybeHasRetry.canRetry;
|
|
132
|
+
}
|
|
133
|
+
if ("retryAfterSeconds" in error) {
|
|
134
|
+
retryProps ??= {};
|
|
135
|
+
retryProps.retryAfterSeconds = maybeHasRetry.retryAfterSeconds;
|
|
136
|
+
}
|
|
137
|
+
if (retryProps !== undefined) {
|
|
138
|
+
Object.assign(fluidError, retryProps);
|
|
139
|
+
}
|
|
126
140
|
}
|
|
127
141
|
|
|
128
142
|
if (typeof error !== "object") {
|
|
@@ -220,7 +234,7 @@ export function wrapError<T extends LoggingError>(
|
|
|
220
234
|
export function wrapErrorAndLog<T extends LoggingError>(
|
|
221
235
|
innerError: unknown,
|
|
222
236
|
newErrorFn: (message: string) => T,
|
|
223
|
-
logger:
|
|
237
|
+
logger: ITelemetryLoggerExt,
|
|
224
238
|
) {
|
|
225
239
|
const newError = wrapError(innerError, newErrorFn);
|
|
226
240
|
|
package/src/events.ts
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { EventEmitter } from "events";
|
|
7
|
-
import {
|
|
7
|
+
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
8
8
|
|
|
9
9
|
export const connectedEventName = "connected";
|
|
10
10
|
export const disconnectedEventName = "disconnected";
|
|
11
11
|
|
|
12
12
|
export function safeRaiseEvent(
|
|
13
13
|
emitter: EventEmitter,
|
|
14
|
-
logger:
|
|
14
|
+
logger: ITelemetryLoggerExt,
|
|
15
15
|
event: string,
|
|
16
16
|
...args
|
|
17
17
|
) {
|
|
@@ -31,7 +31,7 @@ export function safeRaiseEvent(
|
|
|
31
31
|
* @param disconnectedReason - The reason for the connection to be disconnected (Used for telemetry purposes only)
|
|
32
32
|
*/
|
|
33
33
|
export function raiseConnectedEvent(
|
|
34
|
-
logger:
|
|
34
|
+
logger: ITelemetryLoggerExt,
|
|
35
35
|
emitter: EventEmitter,
|
|
36
36
|
connected: boolean,
|
|
37
37
|
clientId?: string,
|
package/src/logger.ts
CHANGED
|
@@ -8,14 +8,13 @@ import {
|
|
|
8
8
|
ITelemetryBaseLogger,
|
|
9
9
|
ITelemetryErrorEvent,
|
|
10
10
|
ITelemetryGenericEvent,
|
|
11
|
-
ITelemetryLogger,
|
|
12
11
|
ITelemetryPerformanceEvent,
|
|
13
12
|
ITelemetryProperties,
|
|
14
13
|
TelemetryEventPropertyType,
|
|
15
14
|
ITaggedTelemetryPropertyType,
|
|
16
15
|
TelemetryEventCategory,
|
|
17
16
|
} from "@fluidframework/common-definitions";
|
|
18
|
-
import { performance } from "@fluidframework/common-utils";
|
|
17
|
+
import { IsomorphicPerformance, performance } from "@fluidframework/common-utils";
|
|
19
18
|
import { CachedConfigProvider, loggerIsMonitoringContext, mixinMonitoringContext } from "./config";
|
|
20
19
|
import {
|
|
21
20
|
isILoggingError,
|
|
@@ -32,6 +31,13 @@ import {
|
|
|
32
31
|
TelemetryEventPropertyTypeExt,
|
|
33
32
|
} from "./telemetryTypes";
|
|
34
33
|
|
|
34
|
+
export interface Memory {
|
|
35
|
+
usedJSHeapSize: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PerformanceWithMemory extends IsomorphicPerformance {
|
|
39
|
+
readonly memory: Memory;
|
|
40
|
+
}
|
|
35
41
|
/**
|
|
36
42
|
* Broad classifications to be applied to individual properties as they're prepared to be logged to telemetry.
|
|
37
43
|
* Please do not modify existing entries for backwards compatibility.
|
|
@@ -290,7 +296,6 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
290
296
|
* is created, but it does not send telemetry events anywhere.
|
|
291
297
|
* @param namespace - Telemetry event name prefix to add to all events
|
|
292
298
|
* @param properties - Base properties to add to all events
|
|
293
|
-
* @param propertyGetters - Getters to add additional properties to all events
|
|
294
299
|
*/
|
|
295
300
|
public static create(
|
|
296
301
|
baseLogger?: ITelemetryBaseLogger,
|
|
@@ -361,7 +366,6 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
361
366
|
/**
|
|
362
367
|
* Multi-sink logger
|
|
363
368
|
* Takes multiple ITelemetryBaseLogger objects (sinks) and logs all events into each sink
|
|
364
|
-
* Implements ITelemetryBaseLogger (through static create() method)
|
|
365
369
|
*/
|
|
366
370
|
export class MultiSinkLogger extends TelemetryLogger {
|
|
367
371
|
protected loggers: ITelemetryBaseLogger[] = [];
|
|
@@ -370,7 +374,6 @@ export class MultiSinkLogger extends TelemetryLogger {
|
|
|
370
374
|
* Create multiple sink logger (i.e. logger that sends events to multiple sinks)
|
|
371
375
|
* @param namespace - Telemetry event name prefix to add to all events
|
|
372
376
|
* @param properties - Base properties to add to all events
|
|
373
|
-
* @param propertyGetters - Getters to add additional properties to all events
|
|
374
377
|
*/
|
|
375
378
|
constructor(namespace?: string, properties?: ITelemetryLoggerPropertyBags) {
|
|
376
379
|
super(namespace, properties);
|
|
@@ -416,15 +419,16 @@ export interface IPerformanceEventMarkers {
|
|
|
416
419
|
*/
|
|
417
420
|
export class PerformanceEvent {
|
|
418
421
|
public static start(
|
|
419
|
-
logger:
|
|
422
|
+
logger: ITelemetryLoggerExt,
|
|
420
423
|
event: ITelemetryGenericEvent,
|
|
421
424
|
markers?: IPerformanceEventMarkers,
|
|
425
|
+
recordHeapSize: boolean = false,
|
|
422
426
|
) {
|
|
423
|
-
return new PerformanceEvent(logger, event, markers);
|
|
427
|
+
return new PerformanceEvent(logger, event, markers, recordHeapSize);
|
|
424
428
|
}
|
|
425
429
|
|
|
426
430
|
public static timedExec<T>(
|
|
427
|
-
logger:
|
|
431
|
+
logger: ITelemetryLoggerExt,
|
|
428
432
|
event: ITelemetryGenericEvent,
|
|
429
433
|
callback: (event: PerformanceEvent) => T,
|
|
430
434
|
markers?: IPerformanceEventMarkers,
|
|
@@ -441,12 +445,13 @@ export class PerformanceEvent {
|
|
|
441
445
|
}
|
|
442
446
|
|
|
443
447
|
public static async timedExecAsync<T>(
|
|
444
|
-
logger:
|
|
448
|
+
logger: ITelemetryLoggerExt,
|
|
445
449
|
event: ITelemetryGenericEvent,
|
|
446
450
|
callback: (event: PerformanceEvent) => Promise<T>,
|
|
447
451
|
markers?: IPerformanceEventMarkers,
|
|
452
|
+
recordHeapSize?: boolean,
|
|
448
453
|
) {
|
|
449
|
-
const perfEvent = PerformanceEvent.start(logger, event, markers);
|
|
454
|
+
const perfEvent = PerformanceEvent.start(logger, event, markers, recordHeapSize);
|
|
450
455
|
try {
|
|
451
456
|
const ret = await callback(perfEvent);
|
|
452
457
|
perfEvent.autoEnd();
|
|
@@ -464,11 +469,13 @@ export class PerformanceEvent {
|
|
|
464
469
|
private event?: ITelemetryGenericEvent;
|
|
465
470
|
private readonly startTime = performance.now();
|
|
466
471
|
private startMark?: string;
|
|
472
|
+
private startMemoryCollection: number | undefined = 0;
|
|
467
473
|
|
|
468
474
|
protected constructor(
|
|
469
|
-
private readonly logger:
|
|
475
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
470
476
|
event: ITelemetryGenericEvent,
|
|
471
477
|
private readonly markers: IPerformanceEventMarkers = { end: true, cancel: "generic" },
|
|
478
|
+
private readonly recordHeapSize: boolean = false,
|
|
472
479
|
) {
|
|
473
480
|
this.event = { ...event };
|
|
474
481
|
if (this.markers.start) {
|
|
@@ -531,6 +538,20 @@ export class PerformanceEvent {
|
|
|
531
538
|
event.eventName = `${event.eventName}_${eventNameSuffix}`;
|
|
532
539
|
if (eventNameSuffix !== "start") {
|
|
533
540
|
event.duration = this.duration;
|
|
541
|
+
if (this.startMemoryCollection) {
|
|
542
|
+
const currentMemory = (performance as PerformanceWithMemory)?.memory
|
|
543
|
+
?.usedJSHeapSize;
|
|
544
|
+
const differenceInKBytes = Math.floor(
|
|
545
|
+
(currentMemory - this.startMemoryCollection) / 1024,
|
|
546
|
+
);
|
|
547
|
+
if (differenceInKBytes > 0) {
|
|
548
|
+
event.usedJSHeapSize = differenceInKBytes;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
} else if (this.recordHeapSize) {
|
|
552
|
+
this.startMemoryCollection = (
|
|
553
|
+
performance as PerformanceWithMemory
|
|
554
|
+
)?.memory?.usedJSHeapSize;
|
|
534
555
|
}
|
|
535
556
|
|
|
536
557
|
this.logger.sendPerformanceEvent(event, error);
|
|
@@ -541,7 +562,7 @@ export class PerformanceEvent {
|
|
|
541
562
|
* Logger that is useful for UT
|
|
542
563
|
* It can be used in places where logger instance is required, but events should be not send over.
|
|
543
564
|
*/
|
|
544
|
-
export class TelemetryUTLogger implements
|
|
565
|
+
export class TelemetryUTLogger implements ITelemetryLoggerExt {
|
|
545
566
|
public send(event: ITelemetryBaseEvent): void {}
|
|
546
567
|
public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any) {}
|
|
547
568
|
public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
|
|
@@ -591,7 +612,7 @@ export class BaseTelemetryNullLogger implements ITelemetryBaseLogger {
|
|
|
591
612
|
* Null logger
|
|
592
613
|
* It can be used in places where logger instance is required, but events should be not send over.
|
|
593
614
|
*/
|
|
594
|
-
export class TelemetryNullLogger implements
|
|
615
|
+
export class TelemetryNullLogger implements ITelemetryLoggerExt {
|
|
595
616
|
public send(event: ITelemetryBaseEvent): void {}
|
|
596
617
|
public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any): void {}
|
|
597
618
|
public sendErrorEvent(event: ITelemetryErrorEvent, error?: any): void {}
|
|
@@ -645,7 +666,7 @@ function convertToBasePropertyTypeUntagged(
|
|
|
645
666
|
case "undefined":
|
|
646
667
|
return x;
|
|
647
668
|
case "object":
|
|
648
|
-
// We assume this is an array based on the input types
|
|
669
|
+
// We assume this is an array or flat object based on the input types
|
|
649
670
|
return JSON.stringify(x);
|
|
650
671
|
default:
|
|
651
672
|
// should never reach this case based on the input types
|
package/src/mockLogger.ts
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { ITelemetryBaseEvent } from "@fluidframework/common-definitions";
|
|
7
7
|
import { assert } from "@fluidframework/common-utils";
|
|
8
8
|
import { TelemetryLogger } from "./logger";
|
|
9
|
+
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* The MockLogger records events sent to it, and then can walk back over those events
|
|
12
13
|
* searching for a set of expected events to match against the logged events.
|
|
13
14
|
*/
|
|
14
|
-
export class MockLogger extends TelemetryLogger implements
|
|
15
|
+
export class MockLogger extends TelemetryLogger implements ITelemetryLoggerExt {
|
|
15
16
|
events: ITelemetryBaseEvent[] = [];
|
|
16
17
|
|
|
17
18
|
constructor() {
|
|
@@ -191,7 +192,7 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
191
192
|
if (inlineDetailsProp && details !== undefined) {
|
|
192
193
|
assert(
|
|
193
194
|
typeof details === "string",
|
|
194
|
-
|
|
195
|
+
0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,
|
|
195
196
|
);
|
|
196
197
|
detailsExpanded = JSON.parse(details);
|
|
197
198
|
}
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
import {
|
|
7
7
|
IDisposable,
|
|
8
8
|
ITelemetryGenericEvent,
|
|
9
|
-
ITelemetryLogger,
|
|
10
9
|
ITelemetryPerformanceEvent,
|
|
11
10
|
ITelemetryProperties,
|
|
12
11
|
} from "@fluidframework/common-definitions";
|
|
13
12
|
import { performance } from "@fluidframework/common-utils";
|
|
13
|
+
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
14
14
|
|
|
15
15
|
interface Measurements {
|
|
16
16
|
// The names of the properties in this interface are the ones that will get stamped in the
|
|
@@ -75,7 +75,7 @@ export class SampledTelemetryHelper implements IDisposable {
|
|
|
75
75
|
*/
|
|
76
76
|
public constructor(
|
|
77
77
|
private readonly eventBase: ITelemetryGenericEvent,
|
|
78
|
-
private readonly logger:
|
|
78
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
79
79
|
private readonly sampleThreshold: number,
|
|
80
80
|
private readonly includeAggregateMetrics: boolean = false,
|
|
81
81
|
private readonly perBucketProperties = new Map<string, ITelemetryProperties>(),
|
package/src/telemetryTypes.ts
CHANGED
|
@@ -14,7 +14,11 @@ export type TelemetryEventPropertyTypeExt =
|
|
|
14
14
|
| number
|
|
15
15
|
| boolean
|
|
16
16
|
| undefined
|
|
17
|
-
| (string | number | boolean)[]
|
|
17
|
+
| (string | number | boolean)[]
|
|
18
|
+
| {
|
|
19
|
+
[key: string]: // Flat objects can have the same properties as the event itself
|
|
20
|
+
string | number | boolean | undefined | (string | number | boolean)[];
|
|
21
|
+
};
|
|
18
22
|
|
|
19
23
|
/**
|
|
20
24
|
* A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used
|
package/src/thresholdCounter.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { ITelemetryLoggerExt } from "./telemetryTypes";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Utility counter which will send event only if the provided value
|
|
@@ -12,7 +12,7 @@ import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
|
12
12
|
export class ThresholdCounter {
|
|
13
13
|
public constructor(
|
|
14
14
|
private readonly threshold: number,
|
|
15
|
-
private readonly logger:
|
|
15
|
+
private readonly logger: ITelemetryLoggerExt,
|
|
16
16
|
private thresholdMultiple = threshold,
|
|
17
17
|
) {}
|
|
18
18
|
|