@fluidframework/telemetry-utils 2.0.0-dev-rc.5.0.0.272251 → 2.0.0-dev-rc.5.0.0.272889
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api-extractor.json +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +20 -1
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +15 -1
- package/dist/mockLogger.js.map +1 -1
- package/dist/telemetryEventBatcher.d.ts +4 -27
- package/dist/telemetryEventBatcher.d.ts.map +1 -1
- package/dist/telemetryEventBatcher.js +5 -28
- package/dist/telemetryEventBatcher.js.map +1 -1
- package/dist/utils.d.ts +12 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +16 -1
- package/dist/utils.js.map +1 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +20 -1
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +13 -0
- package/lib/mockLogger.js.map +1 -1
- package/lib/telemetryEventBatcher.d.ts +4 -27
- package/lib/telemetryEventBatcher.d.ts.map +1 -1
- package/lib/telemetryEventBatcher.js +5 -28
- package/lib/telemetryEventBatcher.js.map +1 -1
- package/lib/utils.d.ts +12 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +14 -0
- package/lib/utils.js.map +1 -1
- package/package.json +8 -8
- package/src/config.ts +6 -6
- package/src/errorLogging.ts +5 -2
- package/src/index.ts +8 -3
- package/src/logger.ts +10 -11
- package/src/mockLogger.ts +38 -2
- package/src/telemetryEventBatcher.ts +6 -47
- package/src/utils.ts +15 -0
package/lib/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAgCxD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,mBAAmB,CAClC,MAA2B,EAC3B,YAA4B,EAC5B,iCAA2C;IAE3C,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,kBAAkB,GACvB,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,iCAAiC,CAAC,IAAI,KAAK,CAAC;IAEjF,MAAM,aAAa,GAAG;QACrB,IAAI,EAAE,CAAC,KAA0B,EAAQ,EAAE;YAC1C,2DAA2D;YAC3D,gIAAgI;YAChI,2LAA2L;YAC3L,0EAA0E;YAC1E,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;QACF,CAAC;QACD,kBAAkB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC9D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;QACF,CAAC;QACD,cAAc,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC1D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QACD,oBAAoB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAChE,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QACD,kBAAkB;KAClB,CAAC;IAEF,OAAO,aAAa,CAAC;AACtB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseEvent } from \"@fluidframework/core-interfaces\";\n\nimport { loggerToMonitoringContext } from \"./config.js\";\nimport type { ITelemetryGenericEventExt, ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * An object that contains a callback used in conjunction with the {@link createSampledLogger} utility function to provide custom logic for sampling events.\n *\n * @internal\n */\nexport interface IEventSampler {\n\t/**\n\t * @returns true if the event should be sampled or false if not\n\t */\n\tsample: () => boolean | undefined;\n}\n\n/**\n * A telemetry logger that has sampling capabilities\n *\n * @internal\n */\nexport interface ISampledTelemetryLogger extends ITelemetryLoggerExt {\n\t/**\n\t * Indicates if the feature flag to disable sampling is set.\n\t *\n\t * @remarks Exposed to enable some advanced scenarios where the code using the sampled logger\n\t * could take advantage of skipping the execution of some logic when it can determine\n\t * it won't be necessary because the telemetry event that needs it wouldn't be\n\t * emitted anyway.\n\t */\n\tisSamplingDisabled: boolean;\n}\n\n/**\n * Wraps around an existing logger matching the {@link ITelemetryLoggerExt} interface and provides the ability to only log a subset of events using a sampling strategy provided by an ${@link IEventSampler}.\n * You can chose to not provide an event sampler which is effectively a no-op, meaning that it will be treated as if the sampler always returns true.\n *\n * @remarks\n * The sampling functionality uses the Fluid telemetry logging configuration along with the optionally provided event sampling callback to determine whether an event should\n * be logged or not.\n *\n * Configuration object parameters:\n * 'Fluid.Telemetry.DisableSampling': if this config value is set to true, all events will be unsampled and therefore logged.\n * Otherwise only a sample will be logged according to the provided event sampler callback.\n *\n * Note that the same sampler is used for all APIs of the returned logger. If you want separate events flowing through the returned logger to be sampled separately, the {@link IEventSampler} you provide should track them separately.\n *\n * @internal\n */\nexport function createSampledLogger(\n\tlogger: ITelemetryLoggerExt,\n\teventSampler?: IEventSampler,\n\tskipLoggingWhenSamplingIsDisabled?: boolean,\n): ISampledTelemetryLogger {\n\tconst monitoringContext = loggerToMonitoringContext(logger);\n\tconst isSamplingDisabled =\n\t\tmonitoringContext.config.getBoolean(\"Fluid.Telemetry.DisableSampling\") ?? false;\n\n\tconst sampledLogger = {\n\t\tsend: (event: ITelemetryBaseEvent): void => {\n\t\t\t// The sampler uses the following logic for sending events:\n\t\t\t// 1. If isSamplingDisabled is true, then this means events should be unsampled. Therefore we send the event without any checks.\n\t\t\t// 2. If isSamplingDisabled is false, then event should be sampled using the event sampler, if the sampler is not defined just send all events, other use the eventSampler.sample() method.\n\t\t\t// 3. If skipLoggingWhenSamplingIsDisabled is true, then no event is sent.\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.send(event);\n\t\t\t}\n\t\t},\n\t\tsendTelemetryEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendTelemetryEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendErrorEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendErrorEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendPerformanceEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendPerformanceEvent(event);\n\t\t\t}\n\t\t},\n\t\tisSamplingDisabled,\n\t};\n\n\treturn sampledLogger;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAgCxD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,mBAAmB,CAClC,MAA2B,EAC3B,YAA4B,EAC5B,iCAA2C;IAE3C,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,kBAAkB,GACvB,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,iCAAiC,CAAC,IAAI,KAAK,CAAC;IAEjF,MAAM,aAAa,GAAG;QACrB,IAAI,EAAE,CAAC,KAA0B,EAAQ,EAAE;YAC1C,2DAA2D;YAC3D,gIAAgI;YAChI,2LAA2L;YAC3L,0EAA0E;YAC1E,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;QACF,CAAC;QACD,kBAAkB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC9D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;QACF,CAAC;QACD,cAAc,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC1D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QACD,oBAAoB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAChE,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QACD,kBAAkB;KAClB,CAAC;IAEF,OAAO,aAAa,CAAC;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAI,aAAsB;IAChD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseEvent } from \"@fluidframework/core-interfaces\";\n\nimport { loggerToMonitoringContext } from \"./config.js\";\nimport type { ITelemetryGenericEventExt, ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * An object that contains a callback used in conjunction with the {@link createSampledLogger} utility function to provide custom logic for sampling events.\n *\n * @internal\n */\nexport interface IEventSampler {\n\t/**\n\t * @returns true if the event should be sampled or false if not\n\t */\n\tsample: () => boolean | undefined;\n}\n\n/**\n * A telemetry logger that has sampling capabilities\n *\n * @internal\n */\nexport interface ISampledTelemetryLogger extends ITelemetryLoggerExt {\n\t/**\n\t * Indicates if the feature flag to disable sampling is set.\n\t *\n\t * @remarks Exposed to enable some advanced scenarios where the code using the sampled logger\n\t * could take advantage of skipping the execution of some logic when it can determine\n\t * it won't be necessary because the telemetry event that needs it wouldn't be\n\t * emitted anyway.\n\t */\n\tisSamplingDisabled: boolean;\n}\n\n/**\n * Wraps around an existing logger matching the {@link ITelemetryLoggerExt} interface and provides the ability to only log a subset of events using a sampling strategy provided by an ${@link IEventSampler}.\n * You can chose to not provide an event sampler which is effectively a no-op, meaning that it will be treated as if the sampler always returns true.\n *\n * @remarks\n * The sampling functionality uses the Fluid telemetry logging configuration along with the optionally provided event sampling callback to determine whether an event should\n * be logged or not.\n *\n * Configuration object parameters:\n * 'Fluid.Telemetry.DisableSampling': if this config value is set to true, all events will be unsampled and therefore logged.\n * Otherwise only a sample will be logged according to the provided event sampler callback.\n *\n * Note that the same sampler is used for all APIs of the returned logger. If you want separate events flowing through the returned logger to be sampled separately, the {@link IEventSampler} you provide should track them separately.\n *\n * @internal\n */\nexport function createSampledLogger(\n\tlogger: ITelemetryLoggerExt,\n\teventSampler?: IEventSampler,\n\tskipLoggingWhenSamplingIsDisabled?: boolean,\n): ISampledTelemetryLogger {\n\tconst monitoringContext = loggerToMonitoringContext(logger);\n\tconst isSamplingDisabled =\n\t\tmonitoringContext.config.getBoolean(\"Fluid.Telemetry.DisableSampling\") ?? false;\n\n\tconst sampledLogger = {\n\t\tsend: (event: ITelemetryBaseEvent): void => {\n\t\t\t// The sampler uses the following logic for sending events:\n\t\t\t// 1. If isSamplingDisabled is true, then this means events should be unsampled. Therefore we send the event without any checks.\n\t\t\t// 2. If isSamplingDisabled is false, then event should be sampled using the event sampler, if the sampler is not defined just send all events, other use the eventSampler.sample() method.\n\t\t\t// 3. If skipLoggingWhenSamplingIsDisabled is true, then no event is sent.\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.send(event);\n\t\t\t}\n\t\t},\n\t\tsendTelemetryEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendTelemetryEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendErrorEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendErrorEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendPerformanceEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendPerformanceEvent(event);\n\t\t\t}\n\t\t},\n\t\tisSamplingDisabled,\n\t};\n\n\treturn sampledLogger;\n}\n\n/**\n * Runs the specified function and returns an object with the time it took to run as well as any output from it.\n * @remarks Useful in conjunction with {@link TelemetryEventBatcher}.\n *\n * @param codeToMeasure - The code to be executed and measured.\n * @returns The total duration of the code execution and whatever the passed-in code block returns.\n * @internal\n */\nexport function measure<T>(codeToMeasure: () => T): { duration: number; output: T } {\n\tconst start = performance.now();\n\tconst output = codeToMeasure();\n\tconst duration = performance.now() - start;\n\treturn { duration, output };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/telemetry-utils",
|
|
3
|
-
"version": "2.0.0-dev-rc.5.0.0.
|
|
3
|
+
"version": "2.0.0-dev-rc.5.0.0.272889",
|
|
4
4
|
"description": "Collection of telemetry relates utilities for Fluid",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -67,17 +67,17 @@
|
|
|
67
67
|
"temp-directory": "nyc/.nyc_output"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@fluid-internal/client-utils": "2.0.0-dev-rc.5.0.0.
|
|
71
|
-
"@fluidframework/core-interfaces": "2.0.0-dev-rc.5.0.0.
|
|
72
|
-
"@fluidframework/core-utils": "2.0.0-dev-rc.5.0.0.
|
|
73
|
-
"@fluidframework/driver-definitions": "2.0.0-dev-rc.5.0.0.
|
|
70
|
+
"@fluid-internal/client-utils": "2.0.0-dev-rc.5.0.0.272889",
|
|
71
|
+
"@fluidframework/core-interfaces": "2.0.0-dev-rc.5.0.0.272889",
|
|
72
|
+
"@fluidframework/core-utils": "2.0.0-dev-rc.5.0.0.272889",
|
|
73
|
+
"@fluidframework/driver-definitions": "2.0.0-dev-rc.5.0.0.272889",
|
|
74
74
|
"debug": "^4.3.4",
|
|
75
75
|
"uuid": "^9.0.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@arethetypeswrong/cli": "^0.15.2",
|
|
79
79
|
"@biomejs/biome": "^1.7.3",
|
|
80
|
-
"@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.5.0.0.
|
|
80
|
+
"@fluid-internal/mocha-test-setup": "2.0.0-dev-rc.5.0.0.272889",
|
|
81
81
|
"@fluid-tools/build-cli": "^0.39.0",
|
|
82
82
|
"@fluidframework/build-common": "^2.0.3",
|
|
83
83
|
"@fluidframework/build-tools": "^0.39.0",
|
|
@@ -135,13 +135,13 @@
|
|
|
135
135
|
"check:exports:cjs:public": "api-extractor run --config api-extractor/api-extractor-lint-public.cjs.json",
|
|
136
136
|
"check:exports:esm:legacy": "api-extractor run --config api-extractor/api-extractor-lint-legacy.esm.json",
|
|
137
137
|
"check:exports:esm:public": "api-extractor run --config api-extractor/api-extractor-lint-public.esm.json",
|
|
138
|
-
"check:format": "npm run check:
|
|
138
|
+
"check:format": "npm run check:biome",
|
|
139
139
|
"check:prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore",
|
|
140
140
|
"ci:build:docs": "api-extractor run",
|
|
141
141
|
"clean": "rimraf --glob dist lib \"*.d.ts\" \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
|
|
142
142
|
"eslint": "eslint --format stylish src",
|
|
143
143
|
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
144
|
-
"format": "npm run format:
|
|
144
|
+
"format": "npm run format:biome",
|
|
145
145
|
"format:biome": "biome check . --formatter-enabled=true --apply",
|
|
146
146
|
"format:prettier": "prettier --write . --cache --ignore-path ../../../.prettierignore",
|
|
147
147
|
"lint": "fluid-build . --task lint",
|
package/src/config.ts
CHANGED
|
@@ -279,9 +279,9 @@ export interface MonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLo
|
|
|
279
279
|
*
|
|
280
280
|
* @internal
|
|
281
281
|
*/
|
|
282
|
-
export function loggerIsMonitoringContext<
|
|
283
|
-
|
|
284
|
-
): obj is L & MonitoringContext<L> {
|
|
282
|
+
export function loggerIsMonitoringContext<
|
|
283
|
+
L extends ITelemetryBaseLogger = ITelemetryLoggerExt,
|
|
284
|
+
>(obj: L): obj is L & MonitoringContext<L> {
|
|
285
285
|
const maybeConfig = obj as Partial<MonitoringContext<L>> | undefined;
|
|
286
286
|
return isConfigProviderBase(maybeConfig?.config) && maybeConfig?.logger !== undefined;
|
|
287
287
|
}
|
|
@@ -291,9 +291,9 @@ export function loggerIsMonitoringContext<L extends ITelemetryBaseLogger = ITele
|
|
|
291
291
|
*
|
|
292
292
|
* @internal
|
|
293
293
|
*/
|
|
294
|
-
export function loggerToMonitoringContext<
|
|
295
|
-
|
|
296
|
-
): MonitoringContext<L> {
|
|
294
|
+
export function loggerToMonitoringContext<
|
|
295
|
+
L extends ITelemetryBaseLogger = ITelemetryLoggerExt,
|
|
296
|
+
>(logger: L): MonitoringContext<L> {
|
|
297
297
|
if (loggerIsMonitoringContext<L>(logger)) {
|
|
298
298
|
return logger;
|
|
299
299
|
}
|
package/src/errorLogging.ts
CHANGED
|
@@ -162,7 +162,7 @@ export function normalizeError(
|
|
|
162
162
|
// FUTURE: Once 2.0 becomes LTS, switch to this more explicit property name
|
|
163
163
|
// Consider using a string to distinguish cases like "dependency" v. "callback"
|
|
164
164
|
// errorRunningExternalCode: 1,
|
|
165
|
-
|
|
165
|
+
};
|
|
166
166
|
|
|
167
167
|
fluidError.addTelemetryProperties({
|
|
168
168
|
...errorTelemetryProps,
|
|
@@ -226,7 +226,10 @@ export function wrapError<T extends LoggingError>(
|
|
|
226
226
|
innerError: unknown,
|
|
227
227
|
newErrorFn: (message: string) => T,
|
|
228
228
|
): T {
|
|
229
|
-
const { message, stack } = extractLogSafeErrorProperties(
|
|
229
|
+
const { message, stack } = extractLogSafeErrorProperties(
|
|
230
|
+
innerError,
|
|
231
|
+
false /* sanitizeStack */,
|
|
232
|
+
);
|
|
230
233
|
|
|
231
234
|
const newError = newErrorFn(message);
|
|
232
235
|
|
package/src/index.ts
CHANGED
|
@@ -61,10 +61,15 @@ export {
|
|
|
61
61
|
TelemetryDataTag,
|
|
62
62
|
type TelemetryEventPropertyTypes,
|
|
63
63
|
} from "./logger.js";
|
|
64
|
-
export { MockLogger } from "./mockLogger.js";
|
|
64
|
+
export { createMockLoggerExt, type IMockLoggerExt, MockLogger } from "./mockLogger.js";
|
|
65
65
|
export { ThresholdCounter } from "./thresholdCounter.js";
|
|
66
66
|
export { SampledTelemetryHelper } from "./sampledTelemetryHelper.js";
|
|
67
|
-
export {
|
|
67
|
+
export {
|
|
68
|
+
createSampledLogger,
|
|
69
|
+
type IEventSampler,
|
|
70
|
+
type ISampledTelemetryLogger,
|
|
71
|
+
measure,
|
|
72
|
+
} from "./utils.js";
|
|
68
73
|
export type {
|
|
69
74
|
TelemetryEventPropertyTypeExt,
|
|
70
75
|
ITelemetryEventExt,
|
|
@@ -76,4 +81,4 @@ export type {
|
|
|
76
81
|
ITelemetryPropertiesExt,
|
|
77
82
|
TelemetryEventCategory,
|
|
78
83
|
} from "./telemetryTypes.js";
|
|
79
|
-
export {
|
|
84
|
+
export { TelemetryEventBatcher } from "./telemetryEventBatcher.js";
|
package/src/logger.ts
CHANGED
|
@@ -274,10 +274,9 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
|
|
|
274
274
|
return this.extendProperties(newEvent, includeErrorProps);
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
-
private extendProperties<
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
): T {
|
|
277
|
+
private extendProperties<
|
|
278
|
+
T extends ITelemetryLoggerPropertyBag = ITelemetryLoggerPropertyBag,
|
|
279
|
+
>(toExtend: T, includeErrorProps: boolean): T {
|
|
281
280
|
const eventLike: ITelemetryLoggerPropertyBag = toExtend;
|
|
282
281
|
if (this.properties) {
|
|
283
282
|
const properties: (undefined | ITelemetryLoggerPropertyBag)[] = [];
|
|
@@ -422,8 +421,8 @@ export class ChildLogger extends TelemetryLogger {
|
|
|
422
421
|
baseLogger.namespace === undefined
|
|
423
422
|
? namespace
|
|
424
423
|
: namespace === undefined
|
|
425
|
-
|
|
426
|
-
|
|
424
|
+
? baseLogger.namespace
|
|
425
|
+
: `${baseLogger.namespace}${TelemetryLogger.eventNamespaceSeparator}${namespace}`;
|
|
427
426
|
|
|
428
427
|
const child = new ChildLogger(
|
|
429
428
|
baseLogger.baseLogger,
|
|
@@ -856,7 +855,7 @@ export function convertToBasePropertyType(
|
|
|
856
855
|
? {
|
|
857
856
|
value: convertToBasePropertyTypeUntagged(x.value),
|
|
858
857
|
tag: x.tag,
|
|
859
|
-
|
|
858
|
+
}
|
|
860
859
|
: convertToBasePropertyTypeUntagged(x);
|
|
861
860
|
}
|
|
862
861
|
|
|
@@ -921,11 +920,11 @@ export const tagData = <
|
|
|
921
920
|
? () => {
|
|
922
921
|
value: ReturnType<V[P]>;
|
|
923
922
|
tag: T;
|
|
924
|
-
|
|
923
|
+
}
|
|
925
924
|
: {
|
|
926
925
|
value: Exclude<V[P], undefined>;
|
|
927
926
|
tag: T;
|
|
928
|
-
|
|
927
|
+
})
|
|
929
928
|
| (V[P] extends undefined ? undefined : never);
|
|
930
929
|
} =>
|
|
931
930
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
@@ -983,10 +982,10 @@ export const tagCodeArtifacts = <
|
|
|
983
982
|
? () => {
|
|
984
983
|
value: ReturnType<T[P]>;
|
|
985
984
|
tag: TelemetryDataTag.CodeArtifact;
|
|
986
|
-
|
|
985
|
+
}
|
|
987
986
|
: {
|
|
988
987
|
value: Exclude<T[P], undefined>;
|
|
989
988
|
tag: TelemetryDataTag.CodeArtifact;
|
|
990
|
-
|
|
989
|
+
})
|
|
991
990
|
| (T[P] extends undefined ? undefined : never);
|
|
992
991
|
} => tagData<TelemetryDataTag.CodeArtifact, T>(TelemetryDataTag.CodeArtifact, values);
|
package/src/mockLogger.ts
CHANGED
|
@@ -11,7 +11,11 @@ import {
|
|
|
11
11
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
12
12
|
|
|
13
13
|
import { createChildLogger } from "./logger.js";
|
|
14
|
-
import type {
|
|
14
|
+
import type {
|
|
15
|
+
ITelemetryEventExt,
|
|
16
|
+
ITelemetryLoggerExt,
|
|
17
|
+
ITelemetryPropertiesExt,
|
|
18
|
+
} from "./telemetryTypes.js";
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* Mock {@link @fluidframework/core-interfaces#ITelemetryBaseLogger} implementation.
|
|
@@ -234,7 +238,10 @@ ${JSON.stringify(actualEvents)}`);
|
|
|
234
238
|
}
|
|
235
239
|
}
|
|
236
240
|
|
|
237
|
-
function matchObjects(
|
|
241
|
+
function matchObjects(
|
|
242
|
+
actual: ITelemetryPropertiesExt,
|
|
243
|
+
expected: ITelemetryPropertiesExt,
|
|
244
|
+
): boolean {
|
|
238
245
|
for (const [expectedKey, expectedValue] of Object.entries(expected)) {
|
|
239
246
|
const actualValue = actual[expectedKey];
|
|
240
247
|
if (
|
|
@@ -259,3 +266,32 @@ function matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPrope
|
|
|
259
266
|
}
|
|
260
267
|
return true;
|
|
261
268
|
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Mock {@link ITelemetryLoggerExt} implementation.
|
|
272
|
+
*
|
|
273
|
+
* @remarks Can be created via {@link createMockLoggerExt}.
|
|
274
|
+
*
|
|
275
|
+
* @internal
|
|
276
|
+
*/
|
|
277
|
+
export interface IMockLoggerExt extends ITelemetryLoggerExt {
|
|
278
|
+
/**
|
|
279
|
+
* Gets the events that have been logged so far.
|
|
280
|
+
*/
|
|
281
|
+
events(): readonly ITelemetryEventExt[];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Creates an {@link IMockLoggerExt}.
|
|
286
|
+
*
|
|
287
|
+
* @internal
|
|
288
|
+
*/
|
|
289
|
+
export function createMockLoggerExt(minLogLevel?: LogLevel): IMockLoggerExt {
|
|
290
|
+
const mockLogger = new MockLogger(minLogLevel);
|
|
291
|
+
const childLogger = createChildLogger({ logger: mockLogger });
|
|
292
|
+
Object.assign(childLogger, {
|
|
293
|
+
events: (): readonly ITelemetryEventExt[] =>
|
|
294
|
+
mockLogger.events.map((e) => e as ITelemetryEventExt),
|
|
295
|
+
});
|
|
296
|
+
return childLogger as IMockLoggerExt;
|
|
297
|
+
}
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { performance } from "@fluid-internal/client-utils";
|
|
7
|
-
|
|
8
6
|
import { roundToDecimalPlaces } from "./mathTools.js";
|
|
9
7
|
import type {
|
|
10
8
|
ITelemetryGenericEventExt,
|
|
@@ -13,20 +11,10 @@ import type {
|
|
|
13
11
|
} from "./telemetryTypes.js";
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
|
-
*
|
|
17
|
-
* @
|
|
18
|
-
*/
|
|
19
|
-
export interface IMeasuredCodeResult<TKey extends string> {
|
|
20
|
-
/**
|
|
21
|
-
* Optional properties to log custom data. The set of properties must be the same for all calls to the `measure` function.
|
|
22
|
-
*/
|
|
23
|
-
telemetryProperties?: { readonly [key in TKey]: number };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Telemetry class that measures the execution time of a given piece of code and accumulates user defined telemetry metrics, to finally log an event through the {@link TelemetryEventBatcher.logger | logger} provided to this class when the number of calls to the {@link TelemetryEventBatcher.measure | measure} function reaches the specified by {@link TelemetryEventBatcher.threshold | threshold}.
|
|
14
|
+
* Telemetry class that accumulates measurements which are eventually logged in a telemetry event through the provided
|
|
15
|
+
* {@link TelemetryEventBatcher.logger | logger} when the number of calls to the function reaches the specified {@link TelemetryEventBatcher.threshold | threshold}.
|
|
28
16
|
*
|
|
29
|
-
* @remarks It is expected to be used for a single event type. If
|
|
17
|
+
* @remarks It is expected to be used for a single event type. If different properties should be logged at different times, a separate `TelemetryEventBatcher` should be created with separate `TMetrics` type.
|
|
30
18
|
* @typeparam TMetrics - The set of keys that should be logged.
|
|
31
19
|
* E.g., `keyof Foo` for logging properties `bar` and `baz` from `type Foo = { bar: number, baz: number }`.
|
|
32
20
|
*
|
|
@@ -34,11 +22,6 @@ export interface IMeasuredCodeResult<TKey extends string> {
|
|
|
34
22
|
* @internal
|
|
35
23
|
*/
|
|
36
24
|
export class TelemetryEventBatcher<TMetrics extends string> {
|
|
37
|
-
/**
|
|
38
|
-
* Stores the accumulated duration of the code passed into the logger.
|
|
39
|
-
*/
|
|
40
|
-
private accumulatedDuration: number = 0;
|
|
41
|
-
|
|
42
25
|
/**
|
|
43
26
|
* Stores the sum of the custom data passed into the logger.
|
|
44
27
|
*/
|
|
@@ -71,34 +54,13 @@ export class TelemetryEventBatcher<TMetrics extends string> {
|
|
|
71
54
|
private readonly threshold: number,
|
|
72
55
|
) {}
|
|
73
56
|
|
|
74
|
-
/**
|
|
75
|
-
* Executes the specified code, keeping statistics of its execution time and the telemetry properties it returns, and when the {@link TelemetryEventBatcher.threshold} is reached it logs a performance event which includes the maxes and averages.
|
|
76
|
-
* @param codeToMeasure - The code to be executed and measured.
|
|
77
|
-
* @param customData - Custom data to be logged.
|
|
78
|
-
*
|
|
79
|
-
* @returns Whatever the passed-in code block returns.
|
|
80
|
-
*/
|
|
81
|
-
public measure<T extends IMeasuredCodeResult<TMetrics>>(codeToMeasure: () => T): T {
|
|
82
|
-
const start = performance.now();
|
|
83
|
-
const returnValue = codeToMeasure();
|
|
84
|
-
const duration = performance.now() - start;
|
|
85
|
-
|
|
86
|
-
this.accumulatedDuration += duration;
|
|
87
|
-
|
|
88
|
-
if (returnValue.telemetryProperties) {
|
|
89
|
-
this.accumulateAndLog(returnValue.telemetryProperties);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return returnValue;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
57
|
/**
|
|
96
58
|
* Accumulates the custom data and sends it to the logger every {@link TelemetryEventBatcher.threshold} calls.
|
|
97
59
|
*
|
|
98
60
|
* @param customData -
|
|
99
61
|
* A record storing the custom data to be accumulated and eventually logged.
|
|
100
62
|
*/
|
|
101
|
-
|
|
63
|
+
public accumulateAndLog(customData: Record<TMetrics, number>): void {
|
|
102
64
|
for (const key of Object.keys(customData) as TMetrics[]) {
|
|
103
65
|
this.dataSums[key] = (this.dataSums[key] ?? 0) + customData[key];
|
|
104
66
|
this.dataMaxes[key] = Math.max(
|
|
@@ -119,17 +81,15 @@ export class TelemetryEventBatcher<TMetrics extends string> {
|
|
|
119
81
|
...this.eventBase,
|
|
120
82
|
};
|
|
121
83
|
|
|
122
|
-
telemetryEvent.duration = this.accumulatedDuration /= this.counter;
|
|
123
|
-
|
|
124
84
|
for (const key of Object.keys(this.dataSums) as TMetrics[]) {
|
|
125
85
|
if (this.dataSums[key] !== undefined) {
|
|
126
|
-
telemetryEvent[`
|
|
86
|
+
telemetryEvent[`avg_${key}`] = roundToDecimalPlaces(
|
|
127
87
|
this.dataSums[key]! / this.counter,
|
|
128
88
|
6,
|
|
129
89
|
);
|
|
130
90
|
}
|
|
131
91
|
if (this.dataMaxes[key] !== undefined) {
|
|
132
|
-
telemetryEvent[`
|
|
92
|
+
telemetryEvent[`max_${key}`] = this.dataMaxes[key];
|
|
133
93
|
}
|
|
134
94
|
}
|
|
135
95
|
|
|
@@ -137,7 +97,6 @@ export class TelemetryEventBatcher<TMetrics extends string> {
|
|
|
137
97
|
|
|
138
98
|
// Reset the counter and the data.
|
|
139
99
|
this.counter = 0;
|
|
140
|
-
this.accumulatedDuration = 0;
|
|
141
100
|
this.dataSums = {};
|
|
142
101
|
this.dataMaxes = {};
|
|
143
102
|
}
|
package/src/utils.ts
CHANGED
|
@@ -104,3 +104,18 @@ export function createSampledLogger(
|
|
|
104
104
|
|
|
105
105
|
return sampledLogger;
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Runs the specified function and returns an object with the time it took to run as well as any output from it.
|
|
110
|
+
* @remarks Useful in conjunction with {@link TelemetryEventBatcher}.
|
|
111
|
+
*
|
|
112
|
+
* @param codeToMeasure - The code to be executed and measured.
|
|
113
|
+
* @returns The total duration of the code execution and whatever the passed-in code block returns.
|
|
114
|
+
* @internal
|
|
115
|
+
*/
|
|
116
|
+
export function measure<T>(codeToMeasure: () => T): { duration: number; output: T } {
|
|
117
|
+
const start = performance.now();
|
|
118
|
+
const output = codeToMeasure();
|
|
119
|
+
const duration = performance.now() - start;
|
|
120
|
+
return { duration, output };
|
|
121
|
+
}
|