@fluidframework/telemetry-utils 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +11 -13
- package/.mocharc.js +2 -2
- package/api-extractor.json +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -5
- package/dist/config.js.map +1 -1
- package/dist/debugLogger.d.ts.map +1 -1
- package/dist/debugLogger.js +12 -1
- package/dist/debugLogger.js.map +1 -1
- package/dist/errorLogging.d.ts +8 -7
- package/dist/errorLogging.d.ts.map +1 -1
- package/dist/errorLogging.js +23 -20
- package/dist/errorLogging.js.map +1 -1
- package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/dist/eventEmitterWithErrorHandling.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/fluidErrorBase.d.ts.map +1 -1
- package/dist/fluidErrorBase.js +4 -4
- package/dist/fluidErrorBase.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +15 -4
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +69 -11
- package/dist/logger.js.map +1 -1
- package/dist/mockLogger.d.ts +12 -2
- package/dist/mockLogger.d.ts.map +1 -1
- package/dist/mockLogger.js +24 -2
- package/dist/mockLogger.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/sampledTelemetryHelper.d.ts.map +1 -1
- package/dist/sampledTelemetryHelper.js.map +1 -1
- package/dist/telemetryTypes.d.ts +81 -0
- package/dist/telemetryTypes.d.ts.map +1 -0
- package/dist/telemetryTypes.js +7 -0
- package/dist/telemetryTypes.js.map +1 -0
- package/dist/thresholdCounter.d.ts.map +1 -1
- package/dist/thresholdCounter.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js.map +1 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +18 -5
- package/lib/config.js.map +1 -1
- package/lib/debugLogger.d.ts.map +1 -1
- package/lib/debugLogger.js +13 -2
- package/lib/debugLogger.js.map +1 -1
- package/lib/errorLogging.d.ts +8 -7
- package/lib/errorLogging.d.ts.map +1 -1
- package/lib/errorLogging.js +23 -20
- package/lib/errorLogging.js.map +1 -1
- package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
- package/lib/eventEmitterWithErrorHandling.js.map +1 -1
- package/lib/events.d.ts.map +1 -1
- package/lib/events.js.map +1 -1
- package/lib/fluidErrorBase.d.ts.map +1 -1
- package/lib/fluidErrorBase.js +4 -4
- package/lib/fluidErrorBase.js.map +1 -1
- package/lib/index.d.ts +3 -2
- 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 +15 -4
- package/lib/logger.d.ts.map +1 -1
- package/lib/logger.js +69 -12
- package/lib/logger.js.map +1 -1
- package/lib/mockLogger.d.ts +12 -2
- package/lib/mockLogger.d.ts.map +1 -1
- package/lib/mockLogger.js +24 -2
- package/lib/mockLogger.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/sampledTelemetryHelper.d.ts.map +1 -1
- package/lib/sampledTelemetryHelper.js.map +1 -1
- package/lib/telemetryTypes.d.ts +81 -0
- package/lib/telemetryTypes.d.ts.map +1 -0
- package/lib/telemetryTypes.js +6 -0
- package/lib/telemetryTypes.js.map +1 -0
- package/lib/thresholdCounter.d.ts.map +1 -1
- package/lib/thresholdCounter.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js.map +1 -1
- package/package.json +49 -48
- package/prettier.config.cjs +1 -1
- package/src/config.ts +185 -173
- package/src/debugLogger.ts +128 -111
- package/src/errorLogging.ts +306 -300
- package/src/eventEmitterWithErrorHandling.ts +16 -12
- package/src/events.ts +26 -26
- package/src/fluidErrorBase.ts +42 -38
- package/src/index.ts +29 -9
- package/src/logger.ts +568 -500
- package/src/mockLogger.ts +118 -88
- package/src/packageVersion.ts +1 -1
- package/src/sampledTelemetryHelper.ts +122 -122
- package/src/telemetryTypes.ts +96 -0
- package/src/thresholdCounter.ts +34 -34
- package/src/utils.ts +15 -15
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +9 -13
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.4.1.0.148229",
|
|
4
4
|
"description": "Collection of telemetry relates utilities for Fluid",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -18,35 +18,6 @@
|
|
|
18
18
|
"./lib/indexNode.js": "./lib/indexBrowser.js"
|
|
19
19
|
},
|
|
20
20
|
"types": "dist/index.d.ts",
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "npm run build:genver && concurrently npm:build:compile npm:lint && npm run build:docs",
|
|
23
|
-
"build:commonjs": "npm run tsc && npm run typetests:gen && npm run build:test",
|
|
24
|
-
"build:compile": "concurrently npm:build:commonjs npm:build:esnext",
|
|
25
|
-
"build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
|
|
26
|
-
"build:esnext": "tsc --project ./tsconfig.esnext.json",
|
|
27
|
-
"build:full": "npm run build",
|
|
28
|
-
"build:full:compile": "npm run build:compile",
|
|
29
|
-
"build:genver": "gen-version",
|
|
30
|
-
"build:test": "tsc --project ./src/test/tsconfig.json",
|
|
31
|
-
"bump-version": "npm version minor --no-push --no-git-tag-version && npm run build:genver",
|
|
32
|
-
"ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
|
|
33
|
-
"clean": "rimraf dist lib *.tsbuildinfo *.build.log",
|
|
34
|
-
"eslint": "eslint --format stylish src",
|
|
35
|
-
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
36
|
-
"format": "npm run prettier:fix",
|
|
37
|
-
"lint": "npm run eslint",
|
|
38
|
-
"lint:fix": "npm run eslint:fix",
|
|
39
|
-
"prettier": "prettier --check . --ignore-path ../../../.prettierignore",
|
|
40
|
-
"prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
|
|
41
|
-
"test": "npm run test:mocha",
|
|
42
|
-
"test:coverage": "nyc npm run test:report",
|
|
43
|
-
"test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
|
|
44
|
-
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
45
|
-
"test:report": "npm test -- -- --reporter xunit --reporter-option output=nyc/mocha-junit-report.xml",
|
|
46
|
-
"tsc": "tsc",
|
|
47
|
-
"typetests:gen": "flub generate typetests --generate --dir .",
|
|
48
|
-
"typetests:prepare": "flub generate typetests --prepare --dir . --pin"
|
|
49
|
-
},
|
|
50
21
|
"nyc": {
|
|
51
22
|
"all": true,
|
|
52
23
|
"cache-dir": "nyc/.cache",
|
|
@@ -69,39 +40,69 @@
|
|
|
69
40
|
},
|
|
70
41
|
"dependencies": {
|
|
71
42
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
72
|
-
"@fluidframework/common-utils": "^1.
|
|
43
|
+
"@fluidframework/common-utils": "^1.1.1",
|
|
73
44
|
"debug": "^4.1.1",
|
|
74
45
|
"events": "^3.1.0",
|
|
75
46
|
"uuid": "^8.3.1"
|
|
76
47
|
},
|
|
77
48
|
"devDependencies": {
|
|
78
|
-
"@fluid-tools/build-cli": "^0.
|
|
49
|
+
"@fluid-tools/build-cli": "^0.13.1",
|
|
79
50
|
"@fluidframework/build-common": "^1.1.0",
|
|
80
|
-
"@fluidframework/build-tools": "^0.
|
|
81
|
-
"@fluidframework/eslint-config-fluid": "^
|
|
82
|
-
"@fluidframework/mocha-test-setup": "
|
|
83
|
-
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.0.0-internal.
|
|
84
|
-
"@microsoft/api-extractor": "^7.
|
|
85
|
-
"@rushstack/eslint-config": "^2.5.1",
|
|
51
|
+
"@fluidframework/build-tools": "^0.13.1",
|
|
52
|
+
"@fluidframework/eslint-config-fluid": "^2.0.0",
|
|
53
|
+
"@fluidframework/mocha-test-setup": "2.0.0-dev.4.1.0.148229",
|
|
54
|
+
"@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.0.0-internal.4.0.0",
|
|
55
|
+
"@microsoft/api-extractor": "^7.34.4",
|
|
86
56
|
"@types/debug": "^4.1.5",
|
|
87
57
|
"@types/events": "^3.0.0",
|
|
88
58
|
"@types/mocha": "^9.1.1",
|
|
89
|
-
"@types/node": "^14.18.
|
|
90
|
-
"
|
|
59
|
+
"@types/node": "^14.18.38",
|
|
60
|
+
"@types/uuid": "^8.3.0",
|
|
61
|
+
"concurrently": "^7.6.0",
|
|
91
62
|
"copyfiles": "^2.4.1",
|
|
92
|
-
"cross-env": "^7.0.
|
|
63
|
+
"cross-env": "^7.0.3",
|
|
93
64
|
"eslint": "~8.6.0",
|
|
94
|
-
"mocha": "^10.
|
|
95
|
-
"
|
|
65
|
+
"mocha": "^10.2.0",
|
|
66
|
+
"mocha-json-output-reporter": "^2.0.1",
|
|
67
|
+
"mocha-multi-reporters": "^1.5.1",
|
|
68
|
+
"moment": "^2.21.0",
|
|
69
|
+
"nyc": "^15.1.0",
|
|
96
70
|
"prettier": "~2.6.2",
|
|
97
|
-
"rimraf": "^
|
|
71
|
+
"rimraf": "^4.4.0",
|
|
98
72
|
"sinon": "^7.4.2",
|
|
99
73
|
"typescript": "~4.5.5"
|
|
100
74
|
},
|
|
101
75
|
"typeValidation": {
|
|
102
|
-
"version": "2.0.0-internal.2.3.0",
|
|
103
|
-
"baselineRange": ">=2.0.0-internal.2.2.0 <2.0.0-internal.2.3.0",
|
|
104
|
-
"baselineVersion": "2.0.0-internal.2.2.0",
|
|
105
76
|
"broken": {}
|
|
77
|
+
},
|
|
78
|
+
"scripts": {
|
|
79
|
+
"build": "npm run build:genver && concurrently npm:build:compile npm:lint && npm run build:docs",
|
|
80
|
+
"build:commonjs": "npm run tsc && npm run typetests:gen && npm run build:test",
|
|
81
|
+
"build:compile": "concurrently npm:build:commonjs npm:build:esnext",
|
|
82
|
+
"build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
|
|
83
|
+
"build:esnext": "tsc --project ./tsconfig.esnext.json",
|
|
84
|
+
"build:full": "npm run build",
|
|
85
|
+
"build:full:compile": "npm run build:compile",
|
|
86
|
+
"build:genver": "gen-version",
|
|
87
|
+
"build:test": "tsc --project ./src/test/tsconfig.json",
|
|
88
|
+
"bump-version": "npm version minor --no-push --no-git-tag-version && npm run build:genver",
|
|
89
|
+
"ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
|
|
90
|
+
"clean": "rimraf dist lib *.tsbuildinfo *.build.log",
|
|
91
|
+
"eslint": "eslint --format stylish src",
|
|
92
|
+
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
93
|
+
"format": "npm run prettier:fix",
|
|
94
|
+
"lint": "npm run prettier && npm run eslint",
|
|
95
|
+
"lint:fix": "npm run prettier:fix && npm run eslint:fix",
|
|
96
|
+
"prettier": "prettier --check . --ignore-path ../../../.prettierignore",
|
|
97
|
+
"prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
|
|
98
|
+
"test": "npm run test:mocha",
|
|
99
|
+
"test:coverage": "nyc npm run test:report",
|
|
100
|
+
"test:mocha": "mocha --ignore 'dist/test/types/*' --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
|
|
101
|
+
"test:mocha:multireport": "cross-env FLUID_TEST_MULTIREPORT=1 npm run test:mocha",
|
|
102
|
+
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
103
|
+
"test:report": "npm test -- -- --reporter xunit --reporter-option output=nyc/mocha-junit-report.xml",
|
|
104
|
+
"tsc": "tsc",
|
|
105
|
+
"typetests:gen": "fluid-type-test-generator",
|
|
106
|
+
"typetests:prepare": "flub generate typetests --prepare --dir . --pin"
|
|
106
107
|
}
|
|
107
|
-
}
|
|
108
|
+
}
|
package/prettier.config.cjs
CHANGED
package/src/config.ts
CHANGED
|
@@ -11,30 +11,31 @@ export type ConfigTypes = string | number | boolean | number[] | string[] | bool
|
|
|
11
11
|
* Base interface for providing configurations to enable/disable/control features
|
|
12
12
|
*/
|
|
13
13
|
export interface IConfigProviderBase {
|
|
14
|
-
|
|
14
|
+
getRawConfig(name: string): ConfigTypes;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Explicitly typed interface for reading configurations
|
|
19
19
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
export interface IConfigProvider extends IConfigProviderBase {
|
|
21
|
+
getBoolean(name: string): boolean | undefined;
|
|
22
|
+
getNumber(name: string): number | undefined;
|
|
23
|
+
getString(name: string): string | undefined;
|
|
24
|
+
getBooleanArray(name: string): boolean[] | undefined;
|
|
25
|
+
getNumberArray(name: string): number[] | undefined;
|
|
26
|
+
getStringArray(name: string): string[] | undefined;
|
|
27
|
+
}
|
|
28
28
|
/**
|
|
29
29
|
* Creates a base configuration provider based on `sessionStorage`
|
|
30
30
|
*
|
|
31
31
|
* @returns A lazy initialized base configuration provider with `sessionStorage` as the underlying config store
|
|
32
32
|
*/
|
|
33
|
-
export const sessionStorageConfigProvider =
|
|
34
|
-
|
|
33
|
+
export const sessionStorageConfigProvider = new Lazy<IConfigProviderBase>(() =>
|
|
34
|
+
inMemoryConfigProvider(safeSessionStorage()),
|
|
35
|
+
);
|
|
35
36
|
|
|
36
37
|
const NullConfigProvider: IConfigProviderBase = {
|
|
37
|
-
|
|
38
|
+
getRawConfig: () => undefined,
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
/**
|
|
@@ -44,45 +45,44 @@ const NullConfigProvider: IConfigProviderBase = {
|
|
|
44
45
|
* @returns A base configuration provider with
|
|
45
46
|
* the supplied `Storage` instance as the underlying config store
|
|
46
47
|
*/
|
|
47
|
-
export const inMemoryConfigProvider =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return NullConfigProvider;
|
|
48
|
+
export const inMemoryConfigProvider = (storage: Storage | undefined): IConfigProviderBase => {
|
|
49
|
+
if (storage !== undefined && storage !== null) {
|
|
50
|
+
return new CachedConfigProvider({
|
|
51
|
+
getRawConfig: (name: string) => {
|
|
52
|
+
try {
|
|
53
|
+
return stronglyTypedParse(storage.getItem(name) ?? undefined)?.raw;
|
|
54
|
+
} catch {}
|
|
55
|
+
return undefined;
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return NullConfigProvider;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
interface ConfigTypeStringToType {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
number: number;
|
|
64
|
+
string: string;
|
|
65
|
+
boolean: boolean;
|
|
66
|
+
["number[]"]: number[];
|
|
67
|
+
["string[]"]: string[];
|
|
68
|
+
["boolean[]"]: boolean[];
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
type PrimitiveTypeStrings = "number" | "string" | "boolean";
|
|
72
72
|
|
|
73
73
|
function isPrimitiveType(type: string): type is PrimitiveTypeStrings {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
switch (type) {
|
|
75
|
+
case "boolean":
|
|
76
|
+
case "number":
|
|
77
|
+
case "string":
|
|
78
|
+
return true;
|
|
79
|
+
default:
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
interface StronglyTypedValue extends Partial<ConfigTypeStringToType> {
|
|
85
|
-
|
|
85
|
+
raw: ConfigTypes;
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
88
|
* Takes any supported config type, and returns the value with a strong type. If the type of
|
|
@@ -94,170 +94,182 @@ interface StronglyTypedValue extends Partial<ConfigTypeStringToType> {
|
|
|
94
94
|
* will be return with a string type for the consumer to handle further if necessary.
|
|
95
95
|
*/
|
|
96
96
|
function stronglyTypedParse(input: ConfigTypes): StronglyTypedValue | undefined {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
97
|
+
let output: ConfigTypes = input;
|
|
98
|
+
let defaultReturn: Pick<StronglyTypedValue, "raw" | "string"> | undefined;
|
|
99
|
+
// we do special handling for strings to try and coerce
|
|
100
|
+
// them into a config type if we can. This makes it easy
|
|
101
|
+
// for config sources like sessionStorage which only
|
|
102
|
+
// holds strings
|
|
103
|
+
if (typeof input === "string") {
|
|
104
|
+
try {
|
|
105
|
+
output = JSON.parse(input);
|
|
106
|
+
// we succeeded in parsing, but we don't support parsing
|
|
107
|
+
// for any object as we can't do it type safely
|
|
108
|
+
// so in this case, the default return will be string
|
|
109
|
+
// rather than undefined, and the consumer
|
|
110
|
+
// can parse, as we don't want to provide
|
|
111
|
+
// a false sense of security by just
|
|
112
|
+
// casting.
|
|
113
|
+
defaultReturn = { raw: input, string: input };
|
|
114
|
+
} catch {}
|
|
115
|
+
}
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
if (output === undefined) {
|
|
118
|
+
return defaultReturn;
|
|
119
|
+
}
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
const outputType = typeof output;
|
|
122
|
+
if (isPrimitiveType(outputType)) {
|
|
123
|
+
return { ...defaultReturn, raw: input, [outputType]: output };
|
|
124
|
+
}
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
126
|
+
if (Array.isArray(output)) {
|
|
127
|
+
const firstType = typeof output[0];
|
|
128
|
+
// ensure the first elements is a primitive type
|
|
129
|
+
if (!isPrimitiveType(firstType)) {
|
|
130
|
+
return defaultReturn;
|
|
131
|
+
}
|
|
132
|
+
// ensue all the elements types are homogeneous
|
|
133
|
+
// aka they all have the same type as the first
|
|
134
|
+
for (const v of output) {
|
|
135
|
+
if (typeof v !== firstType) {
|
|
136
|
+
return defaultReturn;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { ...defaultReturn, raw: input, [`${firstType}[]`]: output };
|
|
140
|
+
}
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
return defaultReturn;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
/** `sessionStorage` is undefined in some environments such as Node */
|
|
145
|
+
/** `sessionStorage` is undefined in some environments such as Node and web pages with session storage disabled */
|
|
146
146
|
const safeSessionStorage = (): Storage | undefined => {
|
|
147
|
-
|
|
147
|
+
// For some configurations accessing "globalThis.sessionStorage" throws
|
|
148
|
+
// "'sessionStorage' property from 'Window': Access is denied for this document" rather than returning undefined.
|
|
149
|
+
// Therefor check for it before accessing.
|
|
150
|
+
try {
|
|
151
|
+
// Using globalThis and checking for undefined is preferred over just accessing global sessionStorage
|
|
152
|
+
// since it avoids an exception when running in node.
|
|
153
|
+
// In some cases this has returned null when disabled in the browser, so ensure its undefined in that case:
|
|
154
|
+
return globalThis.sessionStorage ?? undefined;
|
|
155
|
+
} catch {
|
|
156
|
+
// For browsers which error on the above when session storage is disabled:
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
148
159
|
};
|
|
149
160
|
|
|
150
161
|
/**
|
|
151
162
|
* Implementation of {@link IConfigProvider} which contains nested {@link IConfigProviderBase} instances
|
|
152
163
|
*/
|
|
153
164
|
export class CachedConfigProvider implements IConfigProvider {
|
|
154
|
-
|
|
155
|
-
|
|
165
|
+
private readonly configCache = new Map<string, StronglyTypedValue>();
|
|
166
|
+
private readonly orderedBaseProviders: (IConfigProviderBase | undefined)[];
|
|
156
167
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
168
|
+
constructor(...orderedBaseProviders: (IConfigProviderBase | undefined)[]) {
|
|
169
|
+
this.orderedBaseProviders = [];
|
|
170
|
+
const knownProviders = new Set<IConfigProviderBase>();
|
|
171
|
+
const candidateProviders = [...orderedBaseProviders];
|
|
172
|
+
while (candidateProviders.length > 0) {
|
|
173
|
+
const baseProvider = candidateProviders.shift()!;
|
|
174
|
+
if (
|
|
175
|
+
baseProvider !== undefined &&
|
|
176
|
+
isConfigProviderBase(baseProvider) &&
|
|
177
|
+
!knownProviders.has(baseProvider)
|
|
178
|
+
) {
|
|
179
|
+
knownProviders.add(baseProvider);
|
|
180
|
+
if (baseProvider instanceof CachedConfigProvider) {
|
|
181
|
+
candidateProviders.push(...baseProvider.orderedBaseProviders);
|
|
182
|
+
} else {
|
|
183
|
+
this.orderedBaseProviders.push(baseProvider);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
getBoolean(name: string): boolean | undefined {
|
|
189
|
+
return this.getCacheEntry(name)?.boolean;
|
|
190
|
+
}
|
|
191
|
+
getNumber(name: string): number | undefined {
|
|
192
|
+
return this.getCacheEntry(name)?.number;
|
|
193
|
+
}
|
|
194
|
+
getString(name: string): string | undefined {
|
|
195
|
+
return this.getCacheEntry(name)?.string;
|
|
196
|
+
}
|
|
197
|
+
getBooleanArray(name: string): boolean[] | undefined {
|
|
198
|
+
return this.getCacheEntry(name)?.["boolean[]"];
|
|
199
|
+
}
|
|
200
|
+
getNumberArray(name: string): number[] | undefined {
|
|
201
|
+
return this.getCacheEntry(name)?.["number[]"];
|
|
202
|
+
}
|
|
203
|
+
getStringArray(name: string): string[] | undefined {
|
|
204
|
+
return this.getCacheEntry(name)?.["string[]"];
|
|
205
|
+
}
|
|
196
206
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
207
|
+
getRawConfig(name: string): ConfigTypes {
|
|
208
|
+
return this.getCacheEntry(name)?.raw;
|
|
209
|
+
}
|
|
200
210
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
private getCacheEntry(name: string): StronglyTypedValue | undefined {
|
|
212
|
+
if (!this.configCache.has(name)) {
|
|
213
|
+
for (const provider of this.orderedBaseProviders) {
|
|
214
|
+
const parsed = stronglyTypedParse(provider?.getRawConfig(name));
|
|
215
|
+
if (parsed !== undefined) {
|
|
216
|
+
this.configCache.set(name, parsed);
|
|
217
|
+
return parsed;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// configs are immutable, if the first lookup returned no results, all lookups should
|
|
221
|
+
this.configCache.set(name, { raw: undefined });
|
|
222
|
+
}
|
|
223
|
+
return this.configCache.get(name);
|
|
224
|
+
}
|
|
215
225
|
}
|
|
216
226
|
|
|
217
227
|
/**
|
|
218
228
|
* A type containing both a telemetry logger and a configuration provider
|
|
219
229
|
*/
|
|
220
|
-
export interface MonitoringContext<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
config: IConfigProvider;
|
|
224
|
-
logger: L;
|
|
230
|
+
export interface MonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLogger> {
|
|
231
|
+
config: IConfigProvider;
|
|
232
|
+
logger: L;
|
|
225
233
|
}
|
|
226
234
|
|
|
227
235
|
export function loggerIsMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLogger>(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
236
|
+
obj: L,
|
|
237
|
+
): obj is L & MonitoringContext<L> {
|
|
238
|
+
const maybeConfig = obj as Partial<MonitoringContext<L>> | undefined;
|
|
239
|
+
return isConfigProviderBase(maybeConfig?.config) && maybeConfig?.logger !== undefined;
|
|
231
240
|
}
|
|
232
241
|
|
|
233
242
|
export function loggerToMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLogger>(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
243
|
+
logger: L,
|
|
244
|
+
): MonitoringContext<L> {
|
|
245
|
+
if (loggerIsMonitoringContext<L>(logger)) {
|
|
246
|
+
return logger;
|
|
247
|
+
}
|
|
248
|
+
return mixinMonitoringContext<L>(logger, sessionStorageConfigProvider.value);
|
|
239
249
|
}
|
|
240
250
|
|
|
241
251
|
export function mixinMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLogger>(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
logger: L,
|
|
253
|
+
...configs: (IConfigProviderBase | undefined)[]
|
|
254
|
+
) {
|
|
255
|
+
if (loggerIsMonitoringContext<L>(logger)) {
|
|
256
|
+
throw new Error("Logger is already a monitoring context");
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* this is the tricky bit we use for now to smuggle monitoring context around.
|
|
260
|
+
* To the logger we mixin both config and itself, so mc.logger === logger as it is self-referential.
|
|
261
|
+
* We then expose it as a Monitoring context, so via types we hide the outer logger methods.
|
|
262
|
+
* To layers that expect just a logger we can pass mc.logger, but this is still a MonitoringContext
|
|
263
|
+
* so if a deeper layer then converts that logger to a monitoring context it can find the smuggled properties
|
|
264
|
+
* of the MonitoringContext and get the config provider.
|
|
265
|
+
*/
|
|
266
|
+
const mc: L & Partial<MonitoringContext<L>> = logger;
|
|
267
|
+
mc.config = new CachedConfigProvider(...configs);
|
|
268
|
+
mc.logger = logger;
|
|
269
|
+
return mc as MonitoringContext<L>;
|
|
258
270
|
}
|
|
259
271
|
|
|
260
272
|
function isConfigProviderBase(obj: unknown): obj is IConfigProviderBase {
|
|
261
|
-
|
|
262
|
-
|
|
273
|
+
const maybeConfig = obj as Partial<IConfigProviderBase> | undefined;
|
|
274
|
+
return typeof maybeConfig?.getRawConfig === "function";
|
|
263
275
|
}
|