From 8191a22845d43dbf8107c36668b4247da8df8826 Mon Sep 17 00:00:00 2001 From: "Wei Wei (AZURE)" Date: Tue, 5 Mar 2024 16:50:27 +0800 Subject: [PATCH 01/14] Telemetry prototype --- package-lock.json | 745 ++++++++++++++++-- package.json | 1 + src/azurite.ts | 7 + .../generated/middleware/end.middleware.ts | 2 + src/common/Telemetry.ts | 167 ++++ 5 files changed, 878 insertions(+), 44 deletions(-) create mode 100644 src/common/Telemetry.ts diff --git a/package-lock.json b/package-lock.json index d3c74c263..363922818 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@azure/ms-rest-js": "^1.5.0", + "applicationinsights": "^2.9.5", "args": "^5.0.1", "axios": "^0.27.0", "etag": "^1.8.1", @@ -534,6 +535,33 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/@azure/opentelemetry-instrumentation-azure-sdk": { + "version": "1.0.0-beta.5", + "resolved": "https://registry.npmjs.org/@azure/opentelemetry-instrumentation-azure-sdk/-/opentelemetry-instrumentation-azure-sdk-1.0.0-beta.5.tgz", + "integrity": "sha512-fsUarKQDvjhmBO4nIfaZkfNSApm1hZBzcvpNbSrXdcUBxu7lRvKsV5DnwszX7cnhLyVOW9yl1uigtRQ1yDANjA==", + "dependencies": { + "@azure/core-tracing": "^1.0.0", + "@azure/logger": "^1.0.0", + "@opentelemetry/api": "^1.4.1", + "@opentelemetry/core": "^1.15.2", + "@opentelemetry/instrumentation": "^0.41.2", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/opentelemetry-instrumentation-azure-sdk/node_modules/@azure/core-tracing": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", + "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@azure/storage-blob": { "version": "12.16.0", "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.16.0.tgz", @@ -1063,6 +1091,11 @@ "node": ">= 8" } }, + "node_modules/@microsoft/applicationinsights-web-snippet": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-web-snippet/-/applicationinsights-web-snippet-1.0.1.tgz", + "integrity": "sha512-2IHAOaLauc8qaAitvWS+U931T+ze+7MNWrDHY47IENP5y2UA0vqJDu67kWZDdpCN1fFC77sfgfB+HV7SrKshnQ==" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1099,13 +1132,84 @@ } }, "node_modules/@opentelemetry/api": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz", - "integrity": "sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", "engines": { "node": ">=8.0.0" } }, + "node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.41.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.41.2.tgz", + "integrity": "sha512-rxU72E0pKNH6ae2w5+xgVYZLzc5mlxAbGzF4shxMVK8YC2QQsfN38B2GPbj0jvrKWWNUElfclQ+YTykkNg/grw==", + "dependencies": { + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.4.2", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.1", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "engines": { + "node": ">=14" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -1355,6 +1459,11 @@ "@types/mime": "*" } }, + "node_modules/@types/shimmer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.0.5.tgz", + "integrity": "sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==" + }, "node_modules/@types/stoppable": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/stoppable/-/stoppable-1.1.2.tgz", @@ -1721,7 +1830,6 @@ "version": "8.9.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -1729,6 +1837,14 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -1831,6 +1947,101 @@ "node": ">= 8" } }, + "node_modules/applicationinsights": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.9.5.tgz", + "integrity": "sha512-APQ8IWyYDHFvKbitFKpsmZXxkzQh0yYTFacQqoVW7HwlPo3eeLprwnq5RFNmmG6iqLmvQ+xRJSDLEQCgqPh+bw==", + "dependencies": { + "@azure/core-auth": "^1.5.0", + "@azure/core-rest-pipeline": "1.10.1", + "@azure/core-util": "1.2.0", + "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.5", + "@microsoft/applicationinsights-web-snippet": "1.0.1", + "@opentelemetry/api": "^1.7.0", + "@opentelemetry/core": "^1.19.0", + "@opentelemetry/sdk-trace-base": "^1.19.0", + "@opentelemetry/semantic-conventions": "^1.19.0", + "cls-hooked": "^4.2.2", + "continuation-local-storage": "^3.2.1", + "diagnostic-channel": "1.1.1", + "diagnostic-channel-publishers": "1.0.8" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "applicationinsights-native-metrics": "*" + }, + "peerDependenciesMeta": { + "applicationinsights-native-metrics": { + "optional": true + } + } + }, + "node_modules/applicationinsights/node_modules/@azure/core-rest-pipeline": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.1.tgz", + "integrity": "sha512-Kji9k6TOFRDB5ZMTw8qUf2IJ+CeJtsuMdAHox9eqpTf1cefiNMpzrfnF6sINEBZJsaVaWgQ0o48B6kcUH68niA==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "form-data": "^4.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/applicationinsights/node_modules/@azure/core-tracing": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", + "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/applicationinsights/node_modules/@azure/core-util": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz", + "integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/applicationinsights/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/applicationinsights/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -1916,6 +2127,37 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, + "node_modules/async-hook-jl": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", + "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "dependencies": { + "stack-chain": "^1.3.7" + }, + "engines": { + "node": "^4.7 || >=6.9 || >=7.3" + } + }, + "node_modules/async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "dependencies": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "engines": { + "node": "<=0.11.8 || >0.11.10" + } + }, + "node_modules/async-listener/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3311,6 +3553,11 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -3392,6 +3639,27 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "dependencies": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "engines": { + "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1" + } + }, + "node_modules/cls-hooked/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -3533,6 +3801,15 @@ "node": ">= 0.6" } }, + "node_modules/continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "dependencies": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, "node_modules/convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", @@ -3913,6 +4190,22 @@ "node": ">=8" } }, + "node_modules/diagnostic-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-1.1.1.tgz", + "integrity": "sha512-r2HV5qFkUICyoaKlBEpLKHjxMXATUf/l+h8UZPGBHGLy4DDiY2sOLcIctax4eRnTw5wH2jTMExLntGPJ8eOJxw==", + "dependencies": { + "semver": "^7.5.3" + } + }, + "node_modules/diagnostic-channel-publishers": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-1.0.8.tgz", + "integrity": "sha512-HmSm9hXxSPxA9BaLGY98QU1zsdjeCk113KjAYGPCen1ZP6mhVaTPzHd6UYv5r21DnWANi+f+NyPOHruGT9jpqQ==", + "peerDependencies": { + "diagnostic-channel": "*" + } + }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -4023,6 +4316,14 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "node_modules/emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "dependencies": { + "shimmer": "^1.2.0" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -5871,6 +6172,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.4.2.tgz", + "integrity": "sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==", + "dependencies": { + "acorn": "^8.8.2", + "acorn-import-assertions": "^1.9.0", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -7295,6 +7607,11 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -7791,8 +8108,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { "version": "0.1.10", @@ -8097,23 +8413,6 @@ "node": ">= 6" } }, - "node_modules/pkg/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/pkg/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8531,6 +8830,56 @@ "node": ">=0.10.0" } }, + "node_modules/require-in-the-middle": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.2.0.tgz", + "integrity": "sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw==", + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/require-in-the-middle/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/require-in-the-middle/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -8540,6 +8889,17 @@ "node": ">=4" } }, + "node_modules/resolve/node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/restore-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", @@ -8947,6 +9307,11 @@ "node": ">=0.10.0" } }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -9129,6 +9494,11 @@ "node": ">=0.10.0" } }, + "node_modules/stack-chain": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", + "integrity": "sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug==" + }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -9311,7 +9681,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -10687,6 +11056,29 @@ } } }, + "@azure/opentelemetry-instrumentation-azure-sdk": { + "version": "1.0.0-beta.5", + "resolved": "https://registry.npmjs.org/@azure/opentelemetry-instrumentation-azure-sdk/-/opentelemetry-instrumentation-azure-sdk-1.0.0-beta.5.tgz", + "integrity": "sha512-fsUarKQDvjhmBO4nIfaZkfNSApm1hZBzcvpNbSrXdcUBxu7lRvKsV5DnwszX7cnhLyVOW9yl1uigtRQ1yDANjA==", + "requires": { + "@azure/core-tracing": "^1.0.0", + "@azure/logger": "^1.0.0", + "@opentelemetry/api": "^1.4.1", + "@opentelemetry/core": "^1.15.2", + "@opentelemetry/instrumentation": "^0.41.2", + "tslib": "^2.2.0" + }, + "dependencies": { + "@azure/core-tracing": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", + "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", + "requires": { + "tslib": "^2.2.0" + } + } + } + }, "@azure/storage-blob": { "version": "12.16.0", "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.16.0.tgz", @@ -11079,6 +11471,11 @@ } } }, + "@microsoft/applicationinsights-web-snippet": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-web-snippet/-/applicationinsights-web-snippet-1.0.1.tgz", + "integrity": "sha512-2IHAOaLauc8qaAitvWS+U931T+ze+7MNWrDHY47IENP5y2UA0vqJDu67kWZDdpCN1fFC77sfgfB+HV7SrKshnQ==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -11108,9 +11505,53 @@ } }, "@opentelemetry/api": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz", - "integrity": "sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==" + }, + "@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "requires": { + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/instrumentation": { + "version": "0.41.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.41.2.tgz", + "integrity": "sha512-rxU72E0pKNH6ae2w5+xgVYZLzc5mlxAbGzF4shxMVK8YC2QQsfN38B2GPbj0jvrKWWNUElfclQ+YTykkNg/grw==", + "requires": { + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.4.2", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.1", + "shimmer": "^1.2.1" + } + }, + "@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==" }, "@tootallnate/once": { "version": "2.0.0", @@ -11358,6 +11799,11 @@ "@types/mime": "*" } }, + "@types/shimmer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.0.5.tgz", + "integrity": "sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==" + }, "@types/stoppable": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/stoppable/-/stoppable-1.1.2.tgz", @@ -11593,8 +12039,13 @@ "acorn": { "version": "8.9.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", - "dev": true + "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==" + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "requires": {} }, "acorn-jsx": { "version": "5.3.2", @@ -11668,6 +12119,77 @@ "picomatch": "^2.0.4" } }, + "applicationinsights": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.9.5.tgz", + "integrity": "sha512-APQ8IWyYDHFvKbitFKpsmZXxkzQh0yYTFacQqoVW7HwlPo3eeLprwnq5RFNmmG6iqLmvQ+xRJSDLEQCgqPh+bw==", + "requires": { + "@azure/core-auth": "^1.5.0", + "@azure/core-rest-pipeline": "1.10.1", + "@azure/core-util": "1.2.0", + "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.5", + "@microsoft/applicationinsights-web-snippet": "1.0.1", + "@opentelemetry/api": "^1.7.0", + "@opentelemetry/core": "^1.19.0", + "@opentelemetry/sdk-trace-base": "^1.19.0", + "@opentelemetry/semantic-conventions": "^1.19.0", + "cls-hooked": "^4.2.2", + "continuation-local-storage": "^3.2.1", + "diagnostic-channel": "1.1.1", + "diagnostic-channel-publishers": "1.0.8" + }, + "dependencies": { + "@azure/core-rest-pipeline": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.1.tgz", + "integrity": "sha512-Kji9k6TOFRDB5ZMTw8qUf2IJ+CeJtsuMdAHox9eqpTf1cefiNMpzrfnF6sINEBZJsaVaWgQ0o48B6kcUH68niA==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "form-data": "^4.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + } + }, + "@azure/core-tracing": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", + "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", + "requires": { + "tslib": "^2.2.0" + } + }, + "@azure/core-util": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz", + "integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "tslib": "^2.2.0" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -11738,6 +12260,30 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, + "async-hook-jl": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", + "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "requires": { + "stack-chain": "^1.3.7" + } + }, + "async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + } + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -12988,6 +13534,11 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true }, + "cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" + }, "cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -13041,6 +13592,23 @@ } } }, + "cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "requires": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + } + } + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -13154,6 +13722,15 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", @@ -13417,6 +13994,20 @@ "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", "dev": true }, + "diagnostic-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-1.1.1.tgz", + "integrity": "sha512-r2HV5qFkUICyoaKlBEpLKHjxMXATUf/l+h8UZPGBHGLy4DDiY2sOLcIctax4eRnTw5wH2jTMExLntGPJ8eOJxw==", + "requires": { + "semver": "^7.5.3" + } + }, + "diagnostic-channel-publishers": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-1.0.8.tgz", + "integrity": "sha512-HmSm9hXxSPxA9BaLGY98QU1zsdjeCk113KjAYGPCen1ZP6mhVaTPzHd6UYv5r21DnWANi+f+NyPOHruGT9jpqQ==", + "requires": {} + }, "diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -13503,6 +14094,14 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "requires": { + "shimmer": "^1.2.0" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -14837,6 +15436,17 @@ "resolve-from": "^4.0.0" } }, + "import-in-the-middle": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.4.2.tgz", + "integrity": "sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==", + "requires": { + "acorn": "^8.8.2", + "acorn-import-assertions": "^1.9.0", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -15895,6 +16505,11 @@ } } }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, "moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -16265,8 +16880,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { "version": "0.1.10", @@ -16397,17 +17011,6 @@ "util-deprecate": "^1.0.1" } }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16812,6 +17415,51 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-in-the-middle": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.2.0.tgz", + "integrity": "sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "dependencies": { + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "requires": { + "hasown": "^2.0.0" + } + } + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -17109,6 +17757,11 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -17218,6 +17871,11 @@ "tweetnacl": "~0.14.0" } }, + "stack-chain": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", + "integrity": "sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug==" + }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -17352,8 +18010,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "tar-fs": { "version": "2.1.1", diff --git a/package.json b/package.json index 828b12ec4..5406229d8 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@azure/ms-rest-js": "^1.5.0", + "applicationinsights": "^2.9.5", "args": "^5.0.1", "axios": "^0.27.0", "etag": "^1.8.1", diff --git a/src/azurite.ts b/src/azurite.ts index 74250b445..46a3c3b08 100644 --- a/src/azurite.ts +++ b/src/azurite.ts @@ -24,6 +24,7 @@ import TableServer from "./table/TableServer"; import { DEFAULT_TABLE_LOKI_DB_PATH } from "./table/utils/constants"; import { setExtentMemoryLimit } from "./common/ConfigurationBase"; +import { AzuriteTelemetryClient } from "./common/Telemetry"; // tslint:disable:no-console @@ -59,6 +60,10 @@ function shutdown( * Entry for Azurite services. */ async function main() { + + AzuriteTelemetryClient.init(true); + AzuriteTelemetryClient.TraceStartEvent(); + // Initialize and validate environment values from command line parameters const env = new Environment(); @@ -173,6 +178,8 @@ async function main() { }) .once("SIGINT", () => shutdown(blobServer, queueServer, tableServer)) .once("SIGTERM", () => shutdown(blobServer, queueServer, tableServer)); + + AzuriteTelemetryClient.TraceStopEvent(); } main().catch((err) => { diff --git a/src/blob/generated/middleware/end.middleware.ts b/src/blob/generated/middleware/end.middleware.ts index 91692225c..40c1744cc 100644 --- a/src/blob/generated/middleware/end.middleware.ts +++ b/src/blob/generated/middleware/end.middleware.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from '../../../common/Telemetry'; import Context from '../Context'; import IResponse from '../IResponse'; import ILogger from '../utils/ILogger'; @@ -27,6 +28,7 @@ export default function endMiddleware( )}`, context.contextId ); + AzuriteTelemetryClient.TraceRequest(context); res.getBodyStream().end(); } diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts new file mode 100644 index 000000000..9f90d611e --- /dev/null +++ b/src/common/Telemetry.ts @@ -0,0 +1,167 @@ +import TelemetryClient from "applicationinsights/out/Library/TelemetryClient"; +import Context from "../blob/generated/Context"; +import {Operation as BlobOperation} from "../blob/generated/artifacts/operation"; +import { Contracts } from "applicationinsights"; +import { createHash } from "crypto"; +//import {Operation as QueueOperation} from "../queue/generated/artifacts/operation"; +//import {Operation as TableOperation} from "../table/generated/artifacts/operation"; + +export class AzuriteTelemetryClient { + private static eventClient : TelemetryClient | undefined; + private static requestClient : TelemetryClient | undefined; + + private static enableTelemetry: boolean = true; + //private _totalSize: number = 0; + + public static init(enableTelemetry?: boolean) { + + + if (enableTelemetry !== undefined) + { + AzuriteTelemetryClient.enableTelemetry = enableTelemetry; + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) + { + this.eventClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + } + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) + { + //TODO: change to 1% in product + this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + } + } + } + + private static removeRoleInstance ( envelope: Contracts.EnvelopeTelemetry) : boolean { + //var data = envelope.data.baseData; + // envelope.tags["ai.cloud.role"] = ""; + envelope.tags["ai.cloud.roleInstance"] = createHash('sha256').update(envelope.tags["ai.cloud.roleInstance"]).digest('hex'); + + return true; + } + + + public static createAppInsigntClient(cloudRole:string, samplingPercentage:number|undefined) : TelemetryClient + { + const ConnectionString = 'InstrumentationKey=28f7cfab-c2b3-44bf-b880-8af2d41f1783;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/'; + let appInsights = require('applicationinsights'); + + // disable default logging + var appConfig = appInsights.setup(ConnectionString) + .setAutoCollectRequests(false) + .setAutoCollectPerformance(false) + .setAutoCollectExceptions(false) + .setAutoCollectDependencies(false) + .setAutoCollectConsole(false) + .setAutoCollectHeartbeat(false) + .setAutoCollectConsole(false); + + // Remove some default telemetry item in the telemetry envelope + appInsights.defaultClient.addTelemetryProcessor(AzuriteTelemetryClient.removeRoleInstance); + appInsights.start(); + + + if (appInsights.defaultClient !== undefined) + { + appInsights.defaultClient.context.tags[appInsights.defaultClient.context.keys.cloudRole] = "AzuriteTest"; + } + + appInsights.defaultClient.config.samplingPercentage = samplingPercentage??100; + + // For development only, make your telemetry to be sent as soon as it's collected. + appConfig.setInternalLogging(true, true); + appInsights.defaultClient.config.maxBatchSize = 0; + + appInsights.start(); + + return appInsights.defaultClient; + } + + public static TraceRequest(context: Context) { + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) + { + AzuriteTelemetryClient.requestClient.trackRequest( + { + name:BlobOperation[context.operation??0], + url:AzuriteTelemetryClient.GetRequestUri(context), + duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + resultCode:context.response?.getStatusCode()??0, + success:true, + id: context.contextId, + source: context.request?.getHeader("user-agent"), + properties: + { + //userAgent: context.request?.getHeader("user-agent"), + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: AzuriteTelemetryClient.GetRequestAuthentication(context), + }, + contextObjects: + { + operationId: "", + operationParentId: "", + operationName: "test", + appName: "" + } + }); + /* + AzuriteTelemetryClient.requestClient.trackPageView( + { + name:BlobOperation[context.operation??0], + duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + properties: + { + //userAgent: context.request?.getHeader("user-agent"), + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: AzuriteTelemetryClient.GetRequestAuthentication(context), + } + } + ) + */ + } + } + + public static TraceStartEvent() { + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) + { + // TODO: record Azurite instance ID (GUID) in customProperty, to get how many Azurite instance are installed. + AzuriteTelemetryClient.eventClient.trackEvent({name: "Azurite Start event", properties: {customProperty: "custom property value"}}); + } + } + + public static TraceStopEvent() { + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) + { + AzuriteTelemetryClient.eventClient.trackEvent({name: "Azurite Stop event", properties: {customProperty: "custom property value"}}); + } + } + + private static GetRequestUri(context: Context): string { + if (context.request !== undefined) + { + let request = context.request; + let requestUri = request.getUrl(); + let sig = request.getQuery("sig"); + if (sig!=undefined) + { + requestUri = requestUri.replace(encodeURIComponent(sig), "[hidden]"); + } + return `${request.getEndpoint()}${requestUri}`; + } + return ""; + } + + private static GetRequestAuthentication(context: Context): string { + let auth = context.request?.getHeader("authorization")?.split(" ")[0]; + if (auth === undefined) + { + if (context.request!.getQuery("sig") !== undefined) + { + auth = "Sas"; + } + else + { + auth = "Anonymous"; + } + } + return auth; + } +} \ No newline at end of file From 7e04d810e594eaca0a5259fb888123e25ecf8845 Mon Sep 17 00:00:00 2001 From: blueww Date: Tue, 15 Oct 2024 15:38:43 +0800 Subject: [PATCH 02/14] telemetry temp --- .vscode/launch.json | 2 +- AzuriteConfig | 1 + package.json | 5 ++ src/azurite.ts | 12 +-- src/blob/BlobEnvironment.ts | 12 +++ src/common/Environment.ts | 12 +++ src/common/Telemetry.ts | 137 ++++++++++++++++++++++++++++++----- src/common/VSCEnvironment.ts | 6 ++ 8 files changed, 161 insertions(+), 26 deletions(-) create mode 100644 AzuriteConfig diff --git a/.vscode/launch.json b/.vscode/launch.json index 3ba7e4335..2d72e1ec9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "name": "Azurite Service - Loki", "cwd": "${workspaceFolder}", "runtimeArgs": ["-r", "ts-node/register"], - "args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log"], + "args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log"],//,"--DisableTelemetry"], "env": { "AZURITE_ACCOUNTS": "" }, diff --git a/AzuriteConfig b/AzuriteConfig new file mode 100644 index 000000000..0aef8f817 --- /dev/null +++ b/AzuriteConfig @@ -0,0 +1 @@ +ae2f0534-73cc-4b19-b990-ceb853d2771f \ No newline at end of file diff --git a/package.json b/package.json index 5406229d8..02dbf7815 100644 --- a/package.json +++ b/package.json @@ -265,6 +265,11 @@ ], "default": null, "description": "When using in-memory persistence, limit the total size of extents (blob and queue content) to a specific number of megabytes. Defaults to 50% of total memory." + }, + "azurite.disableTelemetry": { + "type": "boolean", + "default": false, + "description": "Disable telemetry data collection of this Azurite execution. By default, Azurite will collect telemetry data to help improve the product." } } } diff --git a/src/azurite.ts b/src/azurite.ts index 46a3c3b08..41e58b74f 100644 --- a/src/azurite.ts +++ b/src/azurite.ts @@ -40,6 +40,8 @@ function shutdown( const tableBeforeCloseMessage = `Azurite Table service is closing...`; const tableAfterCloseMessage = `Azurite Table service successfully closed`; + AzuriteTelemetryClient.TraceStopEvent(); + console.log(blobBeforeCloseMessage); blobServer.close().then(() => { console.log(blobAfterCloseMessage); @@ -61,9 +63,6 @@ function shutdown( */ async function main() { - AzuriteTelemetryClient.init(true); - AzuriteTelemetryClient.TraceStartEvent(); - // Initialize and validate environment values from command line parameters const env = new Environment(); @@ -77,6 +76,10 @@ async function main() { await access(dirname(debugFilePath!)); } + + AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.TraceStartEvent(); + const blobServerFactory = new BlobServerFactory(); const blobServer = await blobServerFactory.createServer(env); const blobConfig = blobServer.config; @@ -178,11 +181,10 @@ async function main() { }) .once("SIGINT", () => shutdown(blobServer, queueServer, tableServer)) .once("SIGTERM", () => shutdown(blobServer, queueServer, tableServer)); - - AzuriteTelemetryClient.TraceStopEvent(); } main().catch((err) => { console.error(`Exit due to unhandled error: ${err.message}`); + AzuriteTelemetryClient.TraceStopEvent(); process.exit(1); }); diff --git a/src/blob/BlobEnvironment.ts b/src/blob/BlobEnvironment.ts index 481293a8b..d6505aa99 100644 --- a/src/blob/BlobEnvironment.ts +++ b/src/blob/BlobEnvironment.ts @@ -65,6 +65,10 @@ if (!(args as any).config.name) { .option( ["", "disableProductStyleUrl"], "Optional. Disable getting account name from the host of request URI, always get account name from the first path segment of request URI." + ) + .option( + ["", "disableTelemetry"], + "Optional. Disable telemetry data collection of this Azurite execution. By default, Azurite will collect telemetry data to help improve the product." ); (args as any).config.name = "azurite-blob"; @@ -139,6 +143,14 @@ export default class BlobEnvironment implements IBlobEnvironment { return false; } + public disableTelemetry(): boolean { + if (this.flags.disableTelemetry !== undefined) { + return true; + } + // default is false which will not collect telemetry data + return false; + } + public inMemoryPersistence(): boolean { if (this.flags.inMemoryPersistence !== undefined) { if (this.flags.location) { diff --git a/src/common/Environment.ts b/src/common/Environment.ts index 80ac881d1..d659eb4a4 100644 --- a/src/common/Environment.ts +++ b/src/common/Environment.ts @@ -102,6 +102,10 @@ args .option( ["d", "debug"], "Optional. Enable debug log by providing a valid local file path as log destination" + ) + .option( + ["", "disableProductStyleUrl"], + "Optional. Disable getting account name from the host of request Uri, always get account name from the first path segment of request Uri" ); (args as any).config.name = "azurite"; @@ -214,6 +218,14 @@ export default class Environment implements IEnvironment { return this.flags.extentMemoryLimit; } + public disableTelemetry(): boolean { + if (this.flags.disableTelemetry !== undefined) { + return true; + } + // default is false which will collect telemetry data + return false; + } + public async debug(): Promise { if (typeof this.flags.debug === "string") { // Enable debug log to file diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 9f90d611e..a93c388b2 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -3,6 +3,9 @@ import Context from "../blob/generated/Context"; import {Operation as BlobOperation} from "../blob/generated/artifacts/operation"; import { Contracts } from "applicationinsights"; import { createHash } from "crypto"; +import * as fs from "fs"; +import uuid from "uuid"; +import { join } from "path"; //import {Operation as QueueOperation} from "../queue/generated/artifacts/operation"; //import {Operation as TableOperation} from "../table/generated/artifacts/operation"; @@ -11,13 +14,27 @@ export class AzuriteTelemetryClient { private static requestClient : TelemetryClient | undefined; private static enableTelemetry: boolean = true; + private static location: string; + private static configFileName = "AzuriteConfig"; //private _totalSize: number = 0; + private _totalBlobRequestCount: number = 0; + private _totalQueueRequestCount: number = 0; + private _totalTableRequestCount: number = 0; - public static init(enableTelemetry?: boolean) { - - - if (enableTelemetry !== undefined) + private static sessionID = uuid(); + private static instanceID = ""; + + public static init(location: string, enableTelemetry: boolean) { + //TODO: check in VSCODE extension + AzuriteTelemetryClient.enableTelemetry = enableTelemetry; + + if (enableTelemetry !== false) { + //Get instaceID and sessionID + //TODO: need check if this works on VScode extension + AzuriteTelemetryClient.location = location; + AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(); + AzuriteTelemetryClient.enableTelemetry = enableTelemetry; if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) { @@ -36,13 +53,16 @@ export class AzuriteTelemetryClient { // envelope.tags["ai.cloud.role"] = ""; envelope.tags["ai.cloud.roleInstance"] = createHash('sha256').update(envelope.tags["ai.cloud.roleInstance"]).digest('hex'); + // per privacy review, we will not collect operation name as it contains request path + envelope.tags["ai.operation.name"] = ""; + return true; } public static createAppInsigntClient(cloudRole:string, samplingPercentage:number|undefined) : TelemetryClient { - const ConnectionString = 'InstrumentationKey=28f7cfab-c2b3-44bf-b880-8af2d41f1783;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/'; + const ConnectionString = 'InstrumentationKey=feb4ae36-1db7-4808-abaa-e0b94996d665;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=9af871a3-75b5-417c-8a2f-7f2eb1ba6a6c'; let appInsights = require('applicationinsights'); // disable default logging @@ -82,6 +102,8 @@ export class AzuriteTelemetryClient { AzuriteTelemetryClient.requestClient.trackRequest( { name:BlobOperation[context.operation??0], + // From privacy review, we will not collect url + // url:"", url:AzuriteTelemetryClient.GetRequestUri(context), duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, resultCode:context.response?.getStatusCode()??0, @@ -89,16 +111,20 @@ export class AzuriteTelemetryClient { id: context.contextId, source: context.request?.getHeader("user-agent"), properties: - { - //userAgent: context.request?.getHeader("user-agent"), - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: AzuriteTelemetryClient.GetRequestAuthentication(context), - }, + { + //userAgent: context.request?.getHeader("user-agent"), + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: AzuriteTelemetryClient.GetRequestAuthentication(context), + requestContentSize: context.request?.getBody.length, + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + }, contextObjects: { operationId: "", operationParentId: "", operationName: "test", + operation_Name: "test", appName: "" } }); @@ -123,32 +149,103 @@ export class AzuriteTelemetryClient { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) { // TODO: record Azurite instance ID (GUID) in customProperty, to get how many Azurite instance are installed. - AzuriteTelemetryClient.eventClient.trackEvent({name: "Azurite Start event", properties: {customProperty: "custom property value"}}); + AzuriteTelemetryClient.eventClient.trackEvent({name: "Azurite Start event", + properties: + { + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + } + }); } } public static TraceStopEvent() { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) { - AzuriteTelemetryClient.eventClient.trackEvent({name: "Azurite Stop event", properties: {customProperty: "custom property value"}}); + AzuriteTelemetryClient.eventClient.trackEvent({name: `Azurite Stop event`, + properties: + { + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + } + }); } } private static GetRequestUri(context: Context): string { if (context.request !== undefined) { - let request = context.request; - let requestUri = request.getUrl(); - let sig = request.getQuery("sig"); - if (sig!=undefined) - { - requestUri = requestUri.replace(encodeURIComponent(sig), "[hidden]"); - } - return `${request.getEndpoint()}${requestUri}`; + let uri = new URL(context.request.getEndpoint()); + if(uri.hostname != "127.0.0.1" && uri.hostname != "localhost") + { + return context.request.getEndpoint().replace(uri.hostname, "[hidden]"); + } + else + { + return context.request.getEndpoint(); + } + + // let request = context.request; + // let requestUri = request.getUrl(); + // let sig = request.getQuery("sig"); + // if (sig!=undefined) + // { + // requestUri = requestUri.replace(encodeURIComponent(sig), "[hidden]"); + // } + // return `${request.getEndpoint()}${requestUri}`; } return ""; } + + private static GetInstanceID(): string { + const configFilePath = join( + AzuriteTelemetryClient.location, + AzuriteTelemetryClient.configFileName + ); + + //const fs = require('fs'); + let instaceID = ""; + try { + if(!fs.existsSync(configFilePath)) + { + instaceID = uuid(); + fs.writeFile(configFilePath, instaceID, (err) => { + //TODO: write warning for write file failed. + }); + } + else{ + + var data = fs.readFileSync(configFilePath, 'utf8'); + instaceID = data.toString(); + if(instaceID === "") + { + instaceID = uuid(); + fs.writeFile(configFilePath, instaceID, (err) => { + //TODO: write warning for write file failed. + }); + } + + // fs.readFile(configFilePath, function (err, data) { + // if (!err) + // { + // instaceID = data.toString(); + // } + // else + // { + // instaceID = uuid(); + // fs.writeFile(configFilePath, instaceID, (err) => { + // //TODO: write warning for write file failed. + // }); + // } + // }); + } + return instaceID; + } catch { + // TODO: Add warning log for instanceID is empty + return instaceID; + } + } private static GetRequestAuthentication(context: Context): string { let auth = context.request?.getHeader("authorization")?.split(" ")[0]; if (auth === undefined) diff --git a/src/common/VSCEnvironment.ts b/src/common/VSCEnvironment.ts index 8b6c5a41a..04e0ea771 100644 --- a/src/common/VSCEnvironment.ts +++ b/src/common/VSCEnvironment.ts @@ -129,4 +129,10 @@ export default class VSCEnvironment implements IEnvironment { public extentMemoryLimit(): number | undefined { return this.workspaceConfiguration.get("extentMemoryLimit"); } + + public disableTelemetry(): boolean { + return ( + this.workspaceConfiguration.get("disableTelemetry") || false + ); + } } From ddb65a37c6d8b446d53dc7fd20f053aec15631bd Mon Sep 17 00:00:00 2001 From: blueww Date: Tue, 22 Oct 2024 18:13:35 +0800 Subject: [PATCH 03/14] Add B/T/Q support, and disableTelemetry for VSC/B/T/Q start/stop --- .vscode/launch.json | 1 + src/azurite.ts | 11 +- src/blob/BlobEnvironment.ts | 2 +- .../generated/middleware/end.middleware.ts | 2 +- src/blob/main.ts | 10 +- src/common/Environment.ts | 4 + src/common/Telemetry.ts | 311 ++++++++++++------ src/common/VSCServerManagerBlob.ts | 4 + src/common/VSCServerManagerQueue.ts | 4 + src/common/VSCServerManagerTable.ts | 4 + src/queue/QueueEnvironment.ts | 12 + .../generated/middleware/end.middleware.ts | 2 + src/queue/main.ts | 6 + src/table/TableEnvironment.ts | 14 +- .../generated/middleware/end.middleware.ts | 2 + src/table/main.ts | 6 + 16 files changed, 280 insertions(+), 115 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 2d72e1ec9..86f2f3d7a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,6 +11,7 @@ "cwd": "${workspaceFolder}", "runtimeArgs": ["-r", "ts-node/register"], "args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log"],//,"--DisableTelemetry"], + //"args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log","--DisableTelemetry"], "env": { "AZURITE_ACCOUNTS": "" }, diff --git a/src/azurite.ts b/src/azurite.ts index 41e58b74f..8fb98fb26 100644 --- a/src/azurite.ts +++ b/src/azurite.ts @@ -40,7 +40,7 @@ function shutdown( const tableBeforeCloseMessage = `Azurite Table service is closing...`; const tableAfterCloseMessage = `Azurite Table service successfully closed`; - AzuriteTelemetryClient.TraceStopEvent(); + AzuriteTelemetryClient.TraceStopEvent("0"); console.log(blobBeforeCloseMessage); blobServer.close().then(() => { @@ -76,10 +76,6 @@ async function main() { await access(dirname(debugFilePath!)); } - - AzuriteTelemetryClient.init(location, !env.disableTelemetry()); - AzuriteTelemetryClient.TraceStartEvent(); - const blobServerFactory = new BlobServerFactory(); const blobServer = await blobServerFactory.createServer(env); const blobConfig = blobServer.config; @@ -171,6 +167,9 @@ async function main() { console.log( `Azurite Table service is successfully listening at ${tableServer.getHttpServerAddress()}` ); + + AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.TraceStartEvent("Blob"); // Handle close event process @@ -185,6 +184,6 @@ async function main() { main().catch((err) => { console.error(`Exit due to unhandled error: ${err.message}`); - AzuriteTelemetryClient.TraceStopEvent(); + AzuriteTelemetryClient.TraceStopEvent("1"); process.exit(1); }); diff --git a/src/blob/BlobEnvironment.ts b/src/blob/BlobEnvironment.ts index d6505aa99..19978e592 100644 --- a/src/blob/BlobEnvironment.ts +++ b/src/blob/BlobEnvironment.ts @@ -147,7 +147,7 @@ export default class BlobEnvironment implements IBlobEnvironment { if (this.flags.disableTelemetry !== undefined) { return true; } - // default is false which will not collect telemetry data + // default is false which will collect telemetry data return false; } diff --git a/src/blob/generated/middleware/end.middleware.ts b/src/blob/generated/middleware/end.middleware.ts index 40c1744cc..710e8deb8 100644 --- a/src/blob/generated/middleware/end.middleware.ts +++ b/src/blob/generated/middleware/end.middleware.ts @@ -28,7 +28,7 @@ export default function endMiddleware( )}`, context.contextId ); - AzuriteTelemetryClient.TraceRequest(context); + AzuriteTelemetryClient.TraceBlobRequest(context); res.getBodyStream().end(); } diff --git a/src/blob/main.ts b/src/blob/main.ts index 41af28052..b6e807441 100644 --- a/src/blob/main.ts +++ b/src/blob/main.ts @@ -5,12 +5,14 @@ import SqlBlobServer from "./SqlBlobServer"; import BlobServer from "./BlobServer"; import { setExtentMemoryLimit } from "../common/ConfigurationBase"; import BlobEnvironment from "./BlobEnvironment"; +import { AzuriteTelemetryClient } from "../common/Telemetry"; // tslint:disable:no-console function shutdown(server: BlobServer | SqlBlobServer) { const beforeCloseMessage = `Azurite Blob service is closing...`; const afterCloseMessage = `Azurite Blob service successfully closed`; + AzuriteTelemetryClient.TraceStopEvent("Blob"); console.log(beforeCloseMessage); server.close().then(() => { @@ -32,7 +34,8 @@ async function main() { // Enable debug log by default before first release for debugging purpose Logger.configLogger(config.enableDebugLog, config.debugLogFilePath); - setExtentMemoryLimit(new BlobEnvironment(), true); + let env = new BlobEnvironment(); + setExtentMemoryLimit(env, true); // Start server console.log( @@ -42,6 +45,10 @@ async function main() { console.log( `Azurite Blob service successfully listens on ${server.getHttpServerAddress()}` ); + + const location = await env.location(); + AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.TraceStartEvent("Blob"); // Handle close event process @@ -56,5 +63,6 @@ async function main() { main().catch((err) => { console.error(`Exit due to unhandled error: ${err.message}`); + AzuriteTelemetryClient.TraceStopEvent("Blob1"); process.exit(1); }); diff --git a/src/common/Environment.ts b/src/common/Environment.ts index d659eb4a4..e42c4fddb 100644 --- a/src/common/Environment.ts +++ b/src/common/Environment.ts @@ -106,6 +106,10 @@ args .option( ["", "disableProductStyleUrl"], "Optional. Disable getting account name from the host of request Uri, always get account name from the first path segment of request Uri" + ) + .option( + ["", "disableTelemetry"], + "Optional. Disable telemtry collection of Azurite. If not specify this parameter Azurite will collect telemetry data by default." ); (args as any).config.name = "azurite"; diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index a93c388b2..20f03b8dd 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -1,13 +1,16 @@ import TelemetryClient from "applicationinsights/out/Library/TelemetryClient"; -import Context from "../blob/generated/Context"; +import {default as BlobContext} from "../blob/generated/Context"; +import {default as QueueContext} from "../queue/generated/Context"; +import {default as TableContext} from "../table/generated/Context"; import {Operation as BlobOperation} from "../blob/generated/artifacts/operation"; +import {Operation as QueueOperation} from "../queue/generated/artifacts/operation"; +import {Operation as TableOperation} from "../table/generated/artifacts/operation"; import { Contracts } from "applicationinsights"; import { createHash } from "crypto"; import * as fs from "fs"; import uuid from "uuid"; import { join } from "path"; -//import {Operation as QueueOperation} from "../queue/generated/artifacts/operation"; -//import {Operation as TableOperation} from "../table/generated/artifacts/operation"; +import logger from "./Logger"; export class AzuriteTelemetryClient { private static eventClient : TelemetryClient | undefined; @@ -16,36 +19,51 @@ export class AzuriteTelemetryClient { private static enableTelemetry: boolean = true; private static location: string; private static configFileName = "AzuriteConfig"; - //private _totalSize: number = 0; - private _totalBlobRequestCount: number = 0; - private _totalQueueRequestCount: number = 0; - private _totalTableRequestCount: number = 0; + //private static _totalSize: number = 0; + private static _totalBlobRequestCount: number = 0; + //private static _totalQueueRequestCount: number = 0; + //private static _totalTableRequestCount: number = 0; private static sessionID = uuid(); private static instanceID = ""; + private static initialized = false; public static init(location: string, enableTelemetry: boolean) { - //TODO: check in VSCODE extension - AzuriteTelemetryClient.enableTelemetry = enableTelemetry; - - if (enableTelemetry !== false) - { - //Get instaceID and sessionID - //TODO: need check if this works on VScode extension - AzuriteTelemetryClient.location = location; - AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(); - + try{ + //TODO: check in VSCODE extension AzuriteTelemetryClient.enableTelemetry = enableTelemetry; - if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) + + if (enableTelemetry !== false && AzuriteTelemetryClient.initialized != true) { - this.eventClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + //Get instaceID and sessionID + //TODO: need check if this works on VScode extension + AzuriteTelemetryClient.location = location; + AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(); + + AzuriteTelemetryClient.enableTelemetry = enableTelemetry; + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) + { + this.eventClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + } + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) + { + //TODO: change to 1% in product + this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + } + + AzuriteTelemetryClient.initialized = true; + logger.info('Telemetry initialize successfully.'); } - if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) + else { - //TODO: change to 1% in product - this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + logger.info('Don\'t need initialize Telemetry. enableTelemetry: ' + enableTelemetry + ", initialized: " + AzuriteTelemetryClient.initialized); + } } + catch (e) + { + logger.warn('Fail to init telemetry, error: ' + e.message); + } } private static removeRoleInstance ( envelope: Contracts.EnvelopeTelemetry) : boolean { @@ -96,105 +114,187 @@ export class AzuriteTelemetryClient { return appInsights.defaultClient; } - public static TraceRequest(context: Context) { - if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) - { - AzuriteTelemetryClient.requestClient.trackRequest( - { - name:BlobOperation[context.operation??0], - // From privacy review, we will not collect url - // url:"", - url:AzuriteTelemetryClient.GetRequestUri(context), - duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, - resultCode:context.response?.getStatusCode()??0, - success:true, - id: context.contextId, - source: context.request?.getHeader("user-agent"), - properties: - { - //userAgent: context.request?.getHeader("user-agent"), - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: AzuriteTelemetryClient.GetRequestAuthentication(context), - requestContentSize: context.request?.getBody.length, - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, - }, - contextObjects: - { - operationId: "", - operationParentId: "", - operationName: "test", - operation_Name: "test", - appName: "" - } - }); - /* - AzuriteTelemetryClient.requestClient.trackPageView( + public static TraceBlobRequest(context: BlobContext) { + try{ + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) + { + AzuriteTelemetryClient._totalBlobRequestCount++; + AzuriteTelemetryClient.requestClient.trackRequest( { - name:BlobOperation[context.operation??0], + name:"B_" + BlobOperation[context.operation??0], + url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + resultCode:context.response?.getStatusCode()??0, + success:true, + id: context.contextId, + source: context.request?.getHeader("user-agent"), properties: - { - //userAgent: context.request?.getHeader("user-agent"), - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: AzuriteTelemetryClient.GetRequestAuthentication(context), - } - } - ) - */ + { + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + requestContentSize: context.request?.getBody.length, + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + totalReqs:AzuriteTelemetryClient._totalBlobRequestCount, + }, + contextObjects: + { + operationId: "", + operationParentId: "", + operationName: "test", + operation_Name: "test", + appName: "" + } + }); + } + logger.verbose('Send blob telemetry: ' + BlobOperation[context.operation??0], context.contextId); + } + catch (e) + { + logger.warn('Fail to telemetry a blob request, error: ' + e.message); } } - public static TraceStartEvent() { - if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) + public static TraceQueueRequest(context: QueueContext) { + try{ + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) + { + AzuriteTelemetryClient.requestClient.trackRequest( + { + name:"Q_" + QueueOperation[context.operation??0], + url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", + duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + resultCode:context.response?.getStatusCode()??0, + success:true, + id: context.contextID, + source: context.request?.getHeader("user-agent"), + properties: + { + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + requestContentSize: context.request?.getBody.length, + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + }, + contextObjects: + { + operationId: "", + operationParentId: "", + operationName: "test", + operation_Name: "test", + appName: "" + } + }); + } + logger.verbose('Send queue telemetry: ' + QueueOperation[context.operation??0], context.contextID); + } + catch (e) { - // TODO: record Azurite instance ID (GUID) in customProperty, to get how many Azurite instance are installed. - AzuriteTelemetryClient.eventClient.trackEvent({name: "Azurite Start event", - properties: - { - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, - } - }); + logger.warn('Fail to telemetry a queue request, error: ' + e.message); } } - public static TraceStopEvent() { - if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) + public static TraceTableRequest(context: TableContext) { + try{ + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) + { + AzuriteTelemetryClient.requestClient.trackRequest( + { + name:"T_" + TableOperation[context.operation??0], + url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", + duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + resultCode:context.response?.getStatusCode()??0, + success:true, + id: context.contextID, + source: context.request?.getHeader("user-agent"), + properties: + { + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + requestContentSize: context.request?.getBody.length, + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + }, + contextObjects: + { + operationId: "", + operationParentId: "", + operationName: "test", + operation_Name: "test", + appName: "" + } + }); + } + logger.verbose('Send table telemetry: ' + TableOperation[context.operation??0], context.contextID); + } + catch (e) { - AzuriteTelemetryClient.eventClient.trackEvent({name: `Azurite Stop event`, - properties: + logger.warn('Fail to telemetry a table request, error: ' + e.message); + } + } + + public static TraceStartEvent(serviceType: string = "") { + try{ + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) { - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, + AzuriteTelemetryClient.eventClient.trackEvent({name: 'Azurite Start' + (serviceType === "" ? "" : ": " + serviceType), + properties: + { + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + // TODO: Add start Parameters + } + }); } - }); + logger.info('Send start telemetry'); + } + catch (e) + { + logger.warn('Fail to send start telemetry, error: ' + e.message); } } - private static GetRequestUri(context: Context): string { - if (context.request !== undefined) + public static TraceStopEvent(serviceType: string = "") { + try{ + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) + { + AzuriteTelemetryClient.eventClient.trackEvent({name: 'Azurite Stop' + (serviceType === "" ? "" : ": " + serviceType), + properties: + { + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + } + }); + } + logger.info('Send stop telemetry'); + } + catch (e) { - let uri = new URL(context.request.getEndpoint()); - if(uri.hostname != "127.0.0.1" && uri.hostname != "localhost") - { - return context.request.getEndpoint().replace(uri.hostname, "[hidden]"); - } - else - { - return context.request.getEndpoint(); - } + logger.warn('Fail to send stop telemetry, error: ' + e.message); + } + } - // let request = context.request; - // let requestUri = request.getUrl(); - // let sig = request.getQuery("sig"); - // if (sig!=undefined) - // { - // requestUri = requestUri.replace(encodeURIComponent(sig), "[hidden]"); - // } - // return `${request.getEndpoint()}${requestUri}`; + private static GetRequestUri(endpoint: string): string { + //From privacy review, won't return the whole Uri + let uri = new URL(endpoint); + let knownHosts = ["127.0.0.1","localhost","host.docker.internal"]; + if(uri.hostname.toLowerCase() in knownHosts) + { + return endpoint.replace(uri.hostname, "[hidden]"); } - return ""; + else + { + return endpoint; + } + + // let request = context.request; + // let requestUri = request.getUrl(); + // let sig = request.getQuery("sig"); + // if (sig!=undefined) + // { + // requestUri = requestUri.replace(encodeURIComponent(sig), "[hidden]"); + // } + // return `${request.getEndpoint()}${requestUri}`; } @@ -246,11 +346,12 @@ export class AzuriteTelemetryClient { return instaceID; } } - private static GetRequestAuthentication(context: Context): string { - let auth = context.request?.getHeader("authorization")?.split(" ")[0]; + + private static GetRequestAuthentication(authorizationHeader: string|undefined, sigQuery: string|undefined): string { + let auth = authorizationHeader?.split(" ")[0]; if (auth === undefined) { - if (context.request!.getQuery("sig") !== undefined) + if (sigQuery !== undefined) { auth = "Sas"; } diff --git a/src/common/VSCServerManagerBlob.ts b/src/common/VSCServerManagerBlob.ts index 3ad33a061..45432157c 100644 --- a/src/common/VSCServerManagerBlob.ts +++ b/src/common/VSCServerManagerBlob.ts @@ -15,6 +15,7 @@ import VSCChannelWriteStream from "./VSCChannelWriteStream"; import VSCEnvironment from "./VSCEnvironment"; import VSCServerManagerBase from "./VSCServerManagerBase"; import VSCServerManagerClosedState from "./VSCServerManagerClosedState"; +import { AzuriteTelemetryClient } from "./Telemetry"; export default class VSCServerManagerBlob extends VSCServerManagerBase { public readonly accessChannelStream = new VSCChannelWriteStream( @@ -50,9 +51,11 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { public async startImpl(): Promise { await this.server!.start(); + AzuriteTelemetryClient.TraceStartEvent("Blob-VSC"); } public async closeImpl(): Promise { + AzuriteTelemetryClient.TraceStopEvent("Blob-VSC"); this.server!.close(); } @@ -69,6 +72,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { location, DEFAULT_BLOB_PERSISTENCE_PATH ); + AzuriteTelemetryClient.init(DEFAULT_BLOB_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry()); // Initialize server configuration const config = new BlobConfiguration( diff --git a/src/common/VSCServerManagerQueue.ts b/src/common/VSCServerManagerQueue.ts index 30f055025..f8c89d03a 100644 --- a/src/common/VSCServerManagerQueue.ts +++ b/src/common/VSCServerManagerQueue.ts @@ -16,6 +16,7 @@ import VSCChannelWriteStream from "./VSCChannelWriteStream"; import VSCEnvironment from "./VSCEnvironment"; import VSCServerManagerBase from "./VSCServerManagerBase"; import VSCServerManagerClosedState from "./VSCServerManagerClosedState"; +import { AzuriteTelemetryClient } from "./Telemetry"; export default class VSCServerManagerBlob extends VSCServerManagerBase { public readonly accessChannelStream = new VSCChannelWriteStream( @@ -51,9 +52,11 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { public async startImpl(): Promise { await this.server!.start(); + AzuriteTelemetryClient.TraceStartEvent("Queue-VSC"); } public async closeImpl(): Promise { + AzuriteTelemetryClient.TraceStopEvent("Queue-VSC"); this.server!.close(); } @@ -72,6 +75,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { location, DEFAULT_QUEUE_PERSISTENCE_PATH ); + AzuriteTelemetryClient.init(DEFAULT_QUEUE_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry()); // Initialize server configuration const config = new QueueConfiguration( diff --git a/src/common/VSCServerManagerTable.ts b/src/common/VSCServerManagerTable.ts index df0403a04..7b34137a1 100644 --- a/src/common/VSCServerManagerTable.ts +++ b/src/common/VSCServerManagerTable.ts @@ -12,6 +12,7 @@ import VSCChannelWriteStream from "./VSCChannelWriteStream"; import VSCEnvironment from "./VSCEnvironment"; import VSCServerManagerBase from "./VSCServerManagerBase"; import VSCServerManagerClosedState from "./VSCServerManagerClosedState"; +import { AzuriteTelemetryClient } from "./Telemetry"; export default class VSCServerManagerTable extends VSCServerManagerBase { public readonly accessChannelStream = new VSCChannelWriteStream( @@ -47,9 +48,11 @@ export default class VSCServerManagerTable extends VSCServerManagerBase { public async startImpl(): Promise { await this.server!.start(); + AzuriteTelemetryClient.TraceStartEvent("Table-VSC"); } public async closeImpl(): Promise { + AzuriteTelemetryClient.TraceStopEvent("Table-VSC"); this.server!.close(); } @@ -61,6 +64,7 @@ export default class VSCServerManagerTable extends VSCServerManagerBase { private async getConfiguration(): Promise { const env = new VSCEnvironment(); const location = await env.location(); + AzuriteTelemetryClient.init(location, !env.disableTelemetry()); // Initialize server configuration const config = new TableConfiguration( diff --git a/src/queue/QueueEnvironment.ts b/src/queue/QueueEnvironment.ts index 162db8a45..b0228e013 100644 --- a/src/queue/QueueEnvironment.ts +++ b/src/queue/QueueEnvironment.ts @@ -53,6 +53,10 @@ args .option( ["d", "debug"], "Optional. Enable debug log by providing a valid local file path as log destination" + ) + .option( + ["", "disableTelemetry"], + "Optional. Disable telemetry data collection of this Azurite execution. By default, Azurite will collect telemetry data to help improve the product." ); (args as any).config.name = "azurite-queue"; @@ -123,6 +127,14 @@ export default class QueueEnvironment implements IQueueEnvironment { return false; } + public disableTelemetry(): boolean { + if (this.flags.disableTelemetry !== undefined) { + return true; + } + // default is false which will collect telemetry data + return false; + } + public inMemoryPersistence(): boolean { if (this.flags.inMemoryPersistence !== undefined) { if (this.flags.location) { diff --git a/src/queue/generated/middleware/end.middleware.ts b/src/queue/generated/middleware/end.middleware.ts index cc75e6b8b..402ace575 100644 --- a/src/queue/generated/middleware/end.middleware.ts +++ b/src/queue/generated/middleware/end.middleware.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import IResponse from "../IResponse"; import ILogger from "../utils/ILogger"; @@ -27,6 +28,7 @@ export default function endMiddleware( )}`, context.contextID ); + AzuriteTelemetryClient.TraceQueueRequest(context); res.getBodyStream().end(); } diff --git a/src/queue/main.ts b/src/queue/main.ts index 745a0bff9..7198be23c 100644 --- a/src/queue/main.ts +++ b/src/queue/main.ts @@ -13,12 +13,14 @@ import { DEFAULT_QUEUE_PERSISTENCE_PATH } from "./utils/constants"; import { setExtentMemoryLimit } from "../common/ConfigurationBase"; +import { AzuriteTelemetryClient } from "../common/Telemetry"; // tslint:disable:no-console function shutdown(server: QueueServer) { const beforeCloseMessage = `Azurite Queue service is closing...`; const afterCloseMessage = `Azurite Queue service successfully closed`; + AzuriteTelemetryClient.TraceStopEvent("Queue"); console.log(beforeCloseMessage); server.close().then(() => { @@ -89,6 +91,9 @@ async function main() { console.log( `Azurite Queue service successfully listens on ${server.getHttpServerAddress()}` ); + + AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.TraceStartEvent("Queue"); // Handle close event process @@ -103,5 +108,6 @@ async function main() { main().catch((err) => { console.error(`Exit due to unhandled error: ${err.message}`); + AzuriteTelemetryClient.TraceStopEvent("Queue1"); process.exit(1); }); diff --git a/src/table/TableEnvironment.ts b/src/table/TableEnvironment.ts index 7d61f766e..86007cd85 100644 --- a/src/table/TableEnvironment.ts +++ b/src/table/TableEnvironment.ts @@ -56,7 +56,11 @@ args .option(["", "oauth"], 'Optional. OAuth level. Candidate values: "basic"') .option(["", "cert"], "Optional. Path to certificate file") .option(["", "key"], "Optional. Path to certificate key .pem file") - .option(["", "pwd"], "Optional. Password for .pfx file"); + .option(["", "pwd"], "Optional. Password for .pfx file") + .option( + ["", "disableTelemetry"], + "Optional. Disable telemetry data collection of this Azurite execution. By default, Azurite will collect telemetry data to help improve the product." + ); (args as any).config.name = "azurite-table"; @@ -115,6 +119,14 @@ export default class TableEnvironment implements ITableEnvironment { return false; } + public disableTelemetry(): boolean { + if (this.flags.disableTelemetry !== undefined) { + return true; + } + // default is false which will collect telemetry data + return false; + } + public inMemoryPersistence(): boolean { if (this.flags.inMemoryPersistence !== undefined) { if (this.flags.location) { diff --git a/src/table/generated/middleware/end.middleware.ts b/src/table/generated/middleware/end.middleware.ts index cc75e6b8b..d2ec9047c 100644 --- a/src/table/generated/middleware/end.middleware.ts +++ b/src/table/generated/middleware/end.middleware.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import IResponse from "../IResponse"; import ILogger from "../utils/ILogger"; @@ -27,6 +28,7 @@ export default function endMiddleware( )}`, context.contextID ); + AzuriteTelemetryClient.TraceTableRequest(context) ; res.getBodyStream().end(); } diff --git a/src/table/main.ts b/src/table/main.ts index e86b952f9..402b685e4 100644 --- a/src/table/main.ts +++ b/src/table/main.ts @@ -7,6 +7,7 @@ import TableConfiguration from "./TableConfiguration"; import TableEnvironment from "./TableEnvironment"; import TableServer from "./TableServer"; import { DEFAULT_TABLE_LOKI_DB_PATH } from "./utils/constants"; +import { AzuriteTelemetryClient } from "../common/Telemetry"; // tslint:disable:no-console @@ -67,12 +68,16 @@ async function main() { console.log(beforeStartMessage); await server.start(); console.log(afterStartMessage); + + AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.TraceStartEvent("Table"); // Handle close event process .once("message", (msg) => { if (msg === "shutdown") { console.log(beforeCloseMessage); + AzuriteTelemetryClient.TraceStopEvent("Table"); server.close().then(() => { console.log(afterCloseMessage); }); @@ -80,6 +85,7 @@ async function main() { }) .once("SIGINT", () => { console.log(beforeCloseMessage); + AzuriteTelemetryClient.TraceStopEvent("Table"); server.close().then(() => { console.log(afterCloseMessage); }); From 9145a9480d345dffc5e6534aa37b5638d44089e9 Mon Sep 17 00:00:00 2001 From: blueww Date: Wed, 23 Oct 2024 17:46:40 +0800 Subject: [PATCH 04/14] Add parameter in start event --- src/azurite.ts | 9 +-- src/blob/BlobServerFactory.ts | 2 + src/blob/IBlobEnvironment.ts | 1 + src/blob/main.ts | 3 +- src/common/AccountDataStore.ts | 2 + src/common/Environment.ts | 4 + src/common/Telemetry.ts | 120 ++++++++++++++++++++++++++-- src/common/VSCServerManagerBlob.ts | 2 +- src/common/VSCServerManagerQueue.ts | 2 +- src/common/VSCServerManagerTable.ts | 2 +- src/queue/IQueueEnvironment.ts | 1 + src/queue/main.ts | 3 +- src/table/ITableEnvironment.ts | 2 + src/table/main.ts | 2 +- 14 files changed, 135 insertions(+), 20 deletions(-) diff --git a/src/azurite.ts b/src/azurite.ts index 8fb98fb26..0f96ae56c 100644 --- a/src/azurite.ts +++ b/src/azurite.ts @@ -40,7 +40,7 @@ function shutdown( const tableBeforeCloseMessage = `Azurite Table service is closing...`; const tableAfterCloseMessage = `Azurite Table service successfully closed`; - AzuriteTelemetryClient.TraceStopEvent("0"); + AzuriteTelemetryClient.TraceStopEvent(); console.log(blobBeforeCloseMessage); blobServer.close().then(() => { @@ -65,7 +65,7 @@ async function main() { // Initialize and validate environment values from command line parameters const env = new Environment(); - + const location = await env.location(); await ensureDir(location); await access(location); @@ -168,8 +168,8 @@ async function main() { `Azurite Table service is successfully listening at ${tableServer.getHttpServerAddress()}` ); - AzuriteTelemetryClient.init(location, !env.disableTelemetry()); - AzuriteTelemetryClient.TraceStartEvent("Blob"); + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); + AzuriteTelemetryClient.TraceStartEvent(); // Handle close event process @@ -184,6 +184,5 @@ async function main() { main().catch((err) => { console.error(`Exit due to unhandled error: ${err.message}`); - AzuriteTelemetryClient.TraceStopEvent("1"); process.exit(1); }); diff --git a/src/blob/BlobServerFactory.ts b/src/blob/BlobServerFactory.ts index 158456476..8590347f2 100644 --- a/src/blob/BlobServerFactory.ts +++ b/src/blob/BlobServerFactory.ts @@ -13,6 +13,7 @@ import { DEFAULT_BLOB_LOKI_DB_PATH, DEFAULT_BLOB_PERSISTENCE_ARRAY } from "./utils/constants"; +import { AzuriteTelemetryClient } from "../common/Telemetry"; export class BlobServerFactory { public async createServer( @@ -42,6 +43,7 @@ export class BlobServerFactory { const isSQL = databaseConnectionString !== undefined; if (isSQL) { + AzuriteTelemetryClient.envDBIsSet = true; if (env.inMemoryPersistence()) { throw new Error(`The --inMemoryPersistence option is not supported when using SQL-based metadata storage.`) } diff --git a/src/blob/IBlobEnvironment.ts b/src/blob/IBlobEnvironment.ts index 6974c560d..a57700759 100644 --- a/src/blob/IBlobEnvironment.ts +++ b/src/blob/IBlobEnvironment.ts @@ -14,4 +14,5 @@ export default interface IBlobEnvironment { disableProductStyleUrl(): boolean; inMemoryPersistence(): boolean; extentMemoryLimit(): number | undefined; + disableTelemetry(): boolean; } diff --git a/src/blob/main.ts b/src/blob/main.ts index b6e807441..27ea99673 100644 --- a/src/blob/main.ts +++ b/src/blob/main.ts @@ -47,7 +47,7 @@ async function main() { ); const location = await env.location(); - AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); AzuriteTelemetryClient.TraceStartEvent("Blob"); // Handle close event @@ -63,6 +63,5 @@ async function main() { main().catch((err) => { console.error(`Exit due to unhandled error: ${err.message}`); - AzuriteTelemetryClient.TraceStopEvent("Blob1"); process.exit(1); }); diff --git a/src/common/AccountDataStore.ts b/src/common/AccountDataStore.ts index 65a88eec9..a1fd501b6 100644 --- a/src/common/AccountDataStore.ts +++ b/src/common/AccountDataStore.ts @@ -4,6 +4,7 @@ import { } from "../common/utils/constants"; import ILogger from "../queue/generated/utils/ILogger"; import IAccountDataStore, { IAccountProperties } from "./IAccountDataStore"; +import { AzuriteTelemetryClient } from "./Telemetry"; import { AZURITE_ACCOUNTS_ENV, DEFAULT_ACCOUNTS_REFRESH_INTERVAL @@ -80,6 +81,7 @@ export default class AccountDataStore implements IAccountDataStore { if (env) { try { this.accounts = this.parserAccountsEnvironmentString(env); + AzuriteTelemetryClient.envAccountIsSet = true; } catch (err) { this.logger.error( `AccountDataStore:init() Fallback to default emulator account ${EMULATOR_ACCOUNT_NAME}. Refresh accounts from environment variable ${AZURITE_ACCOUNTS_ENV} failed. ${JSON.stringify( diff --git a/src/common/Environment.ts b/src/common/Environment.ts index e42c4fddb..be0ced2cf 100644 --- a/src/common/Environment.ts +++ b/src/common/Environment.ts @@ -117,6 +117,10 @@ args export default class Environment implements IEnvironment { private flags = args.parse(process.argv); + //public ToString(): string | undefined { + // return Object.getOwnPropertyNames(this.flags).join(", "); + //} + public blobHost(): string | undefined { return this.flags.blobHost; } diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 20f03b8dd..6ad0ed86f 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -11,6 +11,7 @@ import * as fs from "fs"; import uuid from "uuid"; import { join } from "path"; import logger from "./Logger"; +//import IEnvironment from "../common/IEnvironment"; export class AzuriteTelemetryClient { private static eventClient : TelemetryClient | undefined; @@ -19,16 +20,20 @@ export class AzuriteTelemetryClient { private static enableTelemetry: boolean = true; private static location: string; private static configFileName = "AzuriteConfig"; - //private static _totalSize: number = 0; + //private static _totalIngressSize: number = 0; + //private static _totalEgressSize: number = 0; private static _totalBlobRequestCount: number = 0; - //private static _totalQueueRequestCount: number = 0; - //private static _totalTableRequestCount: number = 0; + private static _totalQueueRequestCount: number = 0; + private static _totalTableRequestCount: number = 0; private static sessionID = uuid(); private static instanceID = ""; private static initialized = false; + private static env: any = undefined; + public static envAccountIsSet = false; + public static envDBIsSet = false; - public static init(location: string, enableTelemetry: boolean) { + public static init(location: string, enableTelemetry: boolean, env: any) { try{ //TODO: check in VSCODE extension AzuriteTelemetryClient.enableTelemetry = enableTelemetry; @@ -41,6 +46,7 @@ export class AzuriteTelemetryClient { AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(); AzuriteTelemetryClient.enableTelemetry = enableTelemetry; + AzuriteTelemetryClient.env = env; if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) { this.eventClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); @@ -159,6 +165,7 @@ export class AzuriteTelemetryClient { try{ if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) { + AzuriteTelemetryClient._totalQueueRequestCount++; AzuriteTelemetryClient.requestClient.trackRequest( { name:"Q_" + QueueOperation[context.operation??0], @@ -198,6 +205,7 @@ export class AzuriteTelemetryClient { try{ if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) { + AzuriteTelemetryClient._totalTableRequestCount++; AzuriteTelemetryClient.requestClient.trackRequest( { name:"T_" + TableOperation[context.operation??0], @@ -236,17 +244,18 @@ export class AzuriteTelemetryClient { public static TraceStartEvent(serviceType: string = "") { try{ if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) - { + { AzuriteTelemetryClient.eventClient.trackEvent({name: 'Azurite Start' + (serviceType === "" ? "" : ": " + serviceType), properties: { instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, + parameters: AzuriteTelemetryClient.GetAllParameterString() // TODO: Add start Parameters } }); } - logger.info('Send start telemetry'); + logger.verbose('Send start telemetry'); } catch (e) { @@ -263,10 +272,13 @@ export class AzuriteTelemetryClient { { instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, + blobRegCount: AzuriteTelemetryClient._totalBlobRequestCount, + queueRegCount: AzuriteTelemetryClient._totalQueueRequestCount, + tableRegCount: AzuriteTelemetryClient._totalTableRequestCount, } }); } - logger.info('Send stop telemetry'); + logger.verbose('Send stop telemetry'); } catch (e) { @@ -362,4 +374,98 @@ export class AzuriteTelemetryClient { } return auth; } + + private static GetAllParameterString(): string { + let parameters = ""; + if (this.envAccountIsSet) + { + parameters += "AZURITE_ACCOUNTS,"; + } + if (this.envDBIsSet) + { + parameters += "AZURITE_DB,"; + } + if (AzuriteTelemetryClient.env === undefined) + { + return parameters; + } + + if (typeof AzuriteTelemetryClient.env?.blobHost === "function" && AzuriteTelemetryClient.env?.blobHost() !== undefined && AzuriteTelemetryClient.env?.blobHost() !== "127.0.0.1") + { + parameters += "blobHost,"; + } + if (typeof AzuriteTelemetryClient.env?.queueHost === "function" && AzuriteTelemetryClient.env?.queueHost() !== undefined && AzuriteTelemetryClient.env?.queueHost() !== "127.0.0.1") + { + parameters += "queueHost,"; + } + if (typeof AzuriteTelemetryClient.env?.tableHost === "function" && AzuriteTelemetryClient.env?.tableHost() !== undefined && AzuriteTelemetryClient.env?.tableHost() !== "127.0.0.1") + { + parameters += "tableHost,"; + } + if (typeof AzuriteTelemetryClient.env?.blobPort === "function" && AzuriteTelemetryClient.env?.blobPort() !== undefined && AzuriteTelemetryClient.env?.blobPort() !== 10000) + { + parameters += "blobPort,"; + } + if (typeof AzuriteTelemetryClient.env?.queuePort === "function" && AzuriteTelemetryClient.env?.queuePort() !== undefined && AzuriteTelemetryClient.env?.queuePort() !== 10001) + { + parameters += "queuePort,"; + } + if (typeof AzuriteTelemetryClient.env?.tablePort === "function" && AzuriteTelemetryClient.env?.tablePort() !== undefined && AzuriteTelemetryClient.env?.tablePort() !== 10002) + { + parameters += "tablePort,"; + } + if (typeof AzuriteTelemetryClient.env?.location === "function" && AzuriteTelemetryClient.env?.location() !== undefined) + { + parameters += "location,"; + } + if (typeof AzuriteTelemetryClient.env?.silent === "function" && AzuriteTelemetryClient.env?.silent()) + { + parameters += "silent,"; + } + if (typeof AzuriteTelemetryClient.env?.loose === "function" && AzuriteTelemetryClient.env?.loose()) + { + parameters += "loose,"; + } + if (typeof AzuriteTelemetryClient.env?.skipApiVersionCheck === "function" && AzuriteTelemetryClient.env?.skipApiVersionCheck()) + { + parameters += "skipApiVersionCheck,"; + } + if (typeof AzuriteTelemetryClient.env?.disableProductStyleUrl === "function" && AzuriteTelemetryClient.env?.disableProductStyleUrl()) + { + parameters += "disableProductStyleUrl,"; + } + if (typeof AzuriteTelemetryClient.env?.cert === "function" && AzuriteTelemetryClient.env?.cert() !== undefined) + { + parameters += "cert,"; + } + if (typeof AzuriteTelemetryClient.env?.key === "function" && AzuriteTelemetryClient.env?.key() !== undefined) + { + parameters += "key,"; + } + if (typeof AzuriteTelemetryClient.env?.pwd === "function" && AzuriteTelemetryClient.env?.pwd() !== undefined) + { + parameters += "pwd,"; + } + if (typeof AzuriteTelemetryClient.env?.oauth === "function" && AzuriteTelemetryClient.env?.oauth() !== undefined) + { + parameters += "oauth,"; + } + if (typeof AzuriteTelemetryClient.env?.inMemoryPersistence === "function" && AzuriteTelemetryClient.env?.inMemoryPersistence()) + { + parameters += "inMemoryPersistence,"; + } + if (typeof AzuriteTelemetryClient.env?.extentMemoryLimit === "function" && AzuriteTelemetryClient.env?.extentMemoryLimit() !== undefined) + { + parameters += "extentMemoryLimit,"; + } + if (typeof AzuriteTelemetryClient.env?.disableTelemetry === "function" && AzuriteTelemetryClient.env?.disableTelemetry()) + { + parameters += "disableTelemetry,"; + } + if (typeof AzuriteTelemetryClient.env?.debug === "function" && AzuriteTelemetryClient.env?.debug() !== undefined) + { + parameters += "debug,"; + } + return parameters; + } } \ No newline at end of file diff --git a/src/common/VSCServerManagerBlob.ts b/src/common/VSCServerManagerBlob.ts index 45432157c..ba0767536 100644 --- a/src/common/VSCServerManagerBlob.ts +++ b/src/common/VSCServerManagerBlob.ts @@ -72,7 +72,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { location, DEFAULT_BLOB_PERSISTENCE_PATH ); - AzuriteTelemetryClient.init(DEFAULT_BLOB_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry()); + AzuriteTelemetryClient.init(DEFAULT_BLOB_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry(), env); // Initialize server configuration const config = new BlobConfiguration( diff --git a/src/common/VSCServerManagerQueue.ts b/src/common/VSCServerManagerQueue.ts index f8c89d03a..b0669039d 100644 --- a/src/common/VSCServerManagerQueue.ts +++ b/src/common/VSCServerManagerQueue.ts @@ -75,7 +75,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { location, DEFAULT_QUEUE_PERSISTENCE_PATH ); - AzuriteTelemetryClient.init(DEFAULT_QUEUE_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry()); + AzuriteTelemetryClient.init(DEFAULT_QUEUE_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry(), env); // Initialize server configuration const config = new QueueConfiguration( diff --git a/src/common/VSCServerManagerTable.ts b/src/common/VSCServerManagerTable.ts index 7b34137a1..896d9ad3f 100644 --- a/src/common/VSCServerManagerTable.ts +++ b/src/common/VSCServerManagerTable.ts @@ -64,7 +64,7 @@ export default class VSCServerManagerTable extends VSCServerManagerBase { private async getConfiguration(): Promise { const env = new VSCEnvironment(); const location = await env.location(); - AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); // Initialize server configuration const config = new TableConfiguration( diff --git a/src/queue/IQueueEnvironment.ts b/src/queue/IQueueEnvironment.ts index 6aaa01880..0eaed4e37 100644 --- a/src/queue/IQueueEnvironment.ts +++ b/src/queue/IQueueEnvironment.ts @@ -13,4 +13,5 @@ export default interface IQueueEnvironment { debug(): Promise; inMemoryPersistence(): boolean; extentMemoryLimit(): number | undefined; + disableTelemetry(): boolean; } diff --git a/src/queue/main.ts b/src/queue/main.ts index 7198be23c..32a3a1360 100644 --- a/src/queue/main.ts +++ b/src/queue/main.ts @@ -92,7 +92,7 @@ async function main() { `Azurite Queue service successfully listens on ${server.getHttpServerAddress()}` ); - AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); AzuriteTelemetryClient.TraceStartEvent("Queue"); // Handle close event @@ -108,6 +108,5 @@ async function main() { main().catch((err) => { console.error(`Exit due to unhandled error: ${err.message}`); - AzuriteTelemetryClient.TraceStopEvent("Queue1"); process.exit(1); }); diff --git a/src/table/ITableEnvironment.ts b/src/table/ITableEnvironment.ts index 6b3f5e3d4..00d2e85d9 100644 --- a/src/table/ITableEnvironment.ts +++ b/src/table/ITableEnvironment.ts @@ -24,4 +24,6 @@ export default interface ITableEnvironment { debug(): Promise; /** Optional. Disable persisting any data to disk. If the Azurite process is terminated, all data is lost */ inMemoryPersistence(): boolean; + /** Optional. Disable telemtry collection of Azurite. If not specify this parameter Azurite will collect telemetry data by default. */ + disableTelemetry(): boolean; } diff --git a/src/table/main.ts b/src/table/main.ts index 402b685e4..c2dfbd06b 100644 --- a/src/table/main.ts +++ b/src/table/main.ts @@ -69,7 +69,7 @@ async function main() { await server.start(); console.log(afterStartMessage); - AzuriteTelemetryClient.init(location, !env.disableTelemetry()); + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); AzuriteTelemetryClient.TraceStartEvent("Table"); // Handle close event From fb40306bb74a3adbaff598b0e943d62cf6130875 Mon Sep 17 00:00:00 2001 From: blueww Date: Wed, 6 Nov 2024 16:18:15 +0800 Subject: [PATCH 05/14] Fix parameter string builder --- src/azurite.ts | 2 +- src/blob/main.ts | 4 +-- src/common/Telemetry.ts | 43 +++++++++++++++-------------- src/common/VSCServerManagerBlob.ts | 2 +- src/common/VSCServerManagerQueue.ts | 2 +- src/common/VSCServerManagerTable.ts | 2 +- src/queue/main.ts | 2 +- src/table/main.ts | 2 +- 8 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/azurite.ts b/src/azurite.ts index 0f96ae56c..e856c3e25 100644 --- a/src/azurite.ts +++ b/src/azurite.ts @@ -169,7 +169,7 @@ async function main() { ); AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); - AzuriteTelemetryClient.TraceStartEvent(); + await AzuriteTelemetryClient.TraceStartEvent(); // Handle close event process diff --git a/src/blob/main.ts b/src/blob/main.ts index 27ea99673..43d4d3ce8 100644 --- a/src/blob/main.ts +++ b/src/blob/main.ts @@ -47,8 +47,8 @@ async function main() { ); const location = await env.location(); - AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); - AzuriteTelemetryClient.TraceStartEvent("Blob"); + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); + await AzuriteTelemetryClient.TraceStartEvent("Blob"); // Handle close event process diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 6ad0ed86f..79c20c857 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -33,6 +33,8 @@ export class AzuriteTelemetryClient { public static envAccountIsSet = false; public static envDBIsSet = false; + private static appInsights = require('applicationinsights'); + public static init(location: string, enableTelemetry: boolean, env: any) { try{ //TODO: check in VSCODE extension @@ -49,14 +51,15 @@ export class AzuriteTelemetryClient { AzuriteTelemetryClient.env = env; if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) { - this.eventClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + this.eventClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100, 0); } if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) { //TODO: change to 1% in product - this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100); + this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 1, 0); } - + + AzuriteTelemetryClient.appInsights.start(); AzuriteTelemetryClient.initialized = true; logger.info('Telemetry initialize successfully.'); } @@ -84,14 +87,13 @@ export class AzuriteTelemetryClient { } - public static createAppInsigntClient(cloudRole:string, samplingPercentage:number|undefined) : TelemetryClient + public static createAppInsigntClient(cloudRole:string, samplingPercentage:number|undefined, maxBatchSize:number|undefined) : TelemetryClient { const ConnectionString = 'InstrumentationKey=feb4ae36-1db7-4808-abaa-e0b94996d665;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=9af871a3-75b5-417c-8a2f-7f2eb1ba6a6c'; - let appInsights = require('applicationinsights'); // disable default logging - var appConfig = appInsights.setup(ConnectionString) - .setAutoCollectRequests(false) + var appConfig = AzuriteTelemetryClient.appInsights.setup(ConnectionString); + appConfig.setAutoCollectRequests(false) .setAutoCollectPerformance(false) .setAutoCollectExceptions(false) .setAutoCollectDependencies(false) @@ -100,24 +102,23 @@ export class AzuriteTelemetryClient { .setAutoCollectConsole(false); // Remove some default telemetry item in the telemetry envelope - appInsights.defaultClient.addTelemetryProcessor(AzuriteTelemetryClient.removeRoleInstance); - appInsights.start(); + var telemetryClient = new AzuriteTelemetryClient.appInsights.TelemetryClient(ConnectionString); + telemetryClient.addTelemetryProcessor(AzuriteTelemetryClient.removeRoleInstance); + //appInsights.start(); - if (appInsights.defaultClient !== undefined) + if (telemetryClient !== undefined) { - appInsights.defaultClient.context.tags[appInsights.defaultClient.context.keys.cloudRole] = "AzuriteTest"; + telemetryClient.context.tags[telemetryClient.context.keys.cloudRole] = "AzuriteTest"; } - appInsights.defaultClient.config.samplingPercentage = samplingPercentage??100; + telemetryClient.config.samplingPercentage = samplingPercentage??100; // For development only, make your telemetry to be sent as soon as it's collected. appConfig.setInternalLogging(true, true); - appInsights.defaultClient.config.maxBatchSize = 0; - - appInsights.start(); + //telemetryClient.config.maxBatchSize = maxBatchSize??0; - return appInsights.defaultClient; + return telemetryClient; } public static TraceBlobRequest(context: BlobContext) { @@ -241,7 +242,7 @@ export class AzuriteTelemetryClient { } } - public static TraceStartEvent(serviceType: string = "") { + public static async TraceStartEvent(serviceType: string = "") { try{ if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) { @@ -250,7 +251,7 @@ export class AzuriteTelemetryClient { { instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, - parameters: AzuriteTelemetryClient.GetAllParameterString() + parameters: await AzuriteTelemetryClient.GetAllParameterString() // TODO: Add start Parameters } }); @@ -375,7 +376,7 @@ export class AzuriteTelemetryClient { return auth; } - private static GetAllParameterString(): string { + private static async GetAllParameterString(): Promise { let parameters = ""; if (this.envAccountIsSet) { @@ -414,7 +415,7 @@ export class AzuriteTelemetryClient { { parameters += "tablePort,"; } - if (typeof AzuriteTelemetryClient.env?.location === "function" && AzuriteTelemetryClient.env?.location() !== undefined) + if (typeof AzuriteTelemetryClient.env?.location === "function" && (await AzuriteTelemetryClient.env?.location()) !== undefined) { parameters += "location,"; } @@ -462,7 +463,7 @@ export class AzuriteTelemetryClient { { parameters += "disableTelemetry,"; } - if (typeof AzuriteTelemetryClient.env?.debug === "function" && AzuriteTelemetryClient.env?.debug() !== undefined) + if (typeof AzuriteTelemetryClient.env?.debug === "function" && (await AzuriteTelemetryClient.env?.debug()) !== undefined) { parameters += "debug,"; } diff --git a/src/common/VSCServerManagerBlob.ts b/src/common/VSCServerManagerBlob.ts index ba0767536..0667187e4 100644 --- a/src/common/VSCServerManagerBlob.ts +++ b/src/common/VSCServerManagerBlob.ts @@ -51,7 +51,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { public async startImpl(): Promise { await this.server!.start(); - AzuriteTelemetryClient.TraceStartEvent("Blob-VSC"); + await AzuriteTelemetryClient.TraceStartEvent("Blob-VSC"); } public async closeImpl(): Promise { diff --git a/src/common/VSCServerManagerQueue.ts b/src/common/VSCServerManagerQueue.ts index b0669039d..0c1c1dc98 100644 --- a/src/common/VSCServerManagerQueue.ts +++ b/src/common/VSCServerManagerQueue.ts @@ -52,7 +52,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { public async startImpl(): Promise { await this.server!.start(); - AzuriteTelemetryClient.TraceStartEvent("Queue-VSC"); + await AzuriteTelemetryClient.TraceStartEvent("Queue-VSC"); } public async closeImpl(): Promise { diff --git a/src/common/VSCServerManagerTable.ts b/src/common/VSCServerManagerTable.ts index 896d9ad3f..dd88861e3 100644 --- a/src/common/VSCServerManagerTable.ts +++ b/src/common/VSCServerManagerTable.ts @@ -48,7 +48,7 @@ export default class VSCServerManagerTable extends VSCServerManagerBase { public async startImpl(): Promise { await this.server!.start(); - AzuriteTelemetryClient.TraceStartEvent("Table-VSC"); + await AzuriteTelemetryClient.TraceStartEvent("Table-VSC"); } public async closeImpl(): Promise { diff --git a/src/queue/main.ts b/src/queue/main.ts index 32a3a1360..8aa3f3262 100644 --- a/src/queue/main.ts +++ b/src/queue/main.ts @@ -93,7 +93,7 @@ async function main() { ); AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); - AzuriteTelemetryClient.TraceStartEvent("Queue"); + await AzuriteTelemetryClient.TraceStartEvent("Queue"); // Handle close event process diff --git a/src/table/main.ts b/src/table/main.ts index c2dfbd06b..c399d8ef9 100644 --- a/src/table/main.ts +++ b/src/table/main.ts @@ -70,7 +70,7 @@ async function main() { console.log(afterStartMessage); AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); - AzuriteTelemetryClient.TraceStartEvent("Table"); + await AzuriteTelemetryClient.TraceStartEvent("Table"); // Handle close event process From d7b3575d17b43b08d9261537a7f1678f2957ac0d Mon Sep 17 00:00:00 2001 From: blueww Date: Mon, 11 Nov 2024 16:20:13 +0800 Subject: [PATCH 06/14] temp change for develop options --- AzuriteConfig | 1 - package-lock.json | 76 ++++++++++++++++++++--------------------- src/common/Telemetry.ts | 20 ++++++----- 3 files changed, 50 insertions(+), 47 deletions(-) delete mode 100644 AzuriteConfig diff --git a/AzuriteConfig b/AzuriteConfig deleted file mode 100644 index 0aef8f817..000000000 --- a/AzuriteConfig +++ /dev/null @@ -1 +0,0 @@ -ae2f0534-73cc-4b19-b990-ceb853d2771f \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 363922818..51f3105fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3639,27 +3639,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/cls-hooked": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", - "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", - "dependencies": { - "async-hook-jl": "^1.7.6", - "emitter-listener": "^1.0.1", - "semver": "^5.4.1" - }, - "engines": { - "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1" - } - }, - "node_modules/cls-hooked/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -3692,6 +3671,27 @@ "node": ">=8" } }, + "node_modules/cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "dependencies": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "engines": { + "node": "^4.7 || >=6.9 || >=7.3 || >=8.2.1" + } + }, + "node_modules/cls-hooked/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -13592,23 +13592,6 @@ } } }, - "cls-hooked": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", - "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", - "requires": { - "async-hook-jl": "^1.7.6", - "emitter-listener": "^1.0.1", - "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - } - } - }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -13637,6 +13620,23 @@ } } }, + "cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "requires": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + } + } + }, "color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 79c20c857..937b84774 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -92,7 +92,7 @@ export class AzuriteTelemetryClient { const ConnectionString = 'InstrumentationKey=feb4ae36-1db7-4808-abaa-e0b94996d665;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=9af871a3-75b5-417c-8a2f-7f2eb1ba6a6c'; // disable default logging - var appConfig = AzuriteTelemetryClient.appInsights.setup(ConnectionString); + let appConfig = AzuriteTelemetryClient.appInsights.setup(ConnectionString); appConfig.setAutoCollectRequests(false) .setAutoCollectPerformance(false) .setAutoCollectExceptions(false) @@ -102,7 +102,7 @@ export class AzuriteTelemetryClient { .setAutoCollectConsole(false); // Remove some default telemetry item in the telemetry envelope - var telemetryClient = new AzuriteTelemetryClient.appInsights.TelemetryClient(ConnectionString); + let telemetryClient = new AzuriteTelemetryClient.appInsights.TelemetryClient(ConnectionString); telemetryClient.addTelemetryProcessor(AzuriteTelemetryClient.removeRoleInstance); //appInsights.start(); @@ -115,8 +115,12 @@ export class AzuriteTelemetryClient { telemetryClient.config.samplingPercentage = samplingPercentage??100; // For development only, make your telemetry to be sent as soon as it's collected. - appConfig.setInternalLogging(true, true); - //telemetryClient.config.maxBatchSize = maxBatchSize??0; + // Enable AppInsight log, should enable in develoipment only + // appConfig.setInternalLogging(true, true); + if (maxBatchSize !== undefined) + { + telemetryClient.config.maxBatchSize = maxBatchSize??0; + } return telemetryClient; } @@ -273,9 +277,9 @@ export class AzuriteTelemetryClient { { instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, - blobRegCount: AzuriteTelemetryClient._totalBlobRequestCount, - queueRegCount: AzuriteTelemetryClient._totalQueueRequestCount, - tableRegCount: AzuriteTelemetryClient._totalTableRequestCount, + blobRequest: AzuriteTelemetryClient._totalBlobRequestCount, + queueRequest: AzuriteTelemetryClient._totalQueueRequestCount, + tableRequest: AzuriteTelemetryClient._totalTableRequestCount, } }); } @@ -329,7 +333,7 @@ export class AzuriteTelemetryClient { } else{ - var data = fs.readFileSync(configFilePath, 'utf8'); + let data = fs.readFileSync(configFilePath, 'utf8'); instaceID = data.toString(); if(instaceID === "") { From 99829041b7d2c752c1a6abacf6b9b51c4fe262a7 Mon Sep 17 00:00:00 2001 From: blueww Date: Mon, 18 Nov 2024 17:14:22 +0800 Subject: [PATCH 07/14] Enable Debug option --- src/common/Telemetry.ts | 116 ++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 40 deletions(-) diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 937b84774..7ed2b3998 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -11,7 +11,6 @@ import * as fs from "fs"; import uuid from "uuid"; import { join } from "path"; import logger from "./Logger"; -//import IEnvironment from "../common/IEnvironment"; export class AzuriteTelemetryClient { private static eventClient : TelemetryClient | undefined; @@ -20,7 +19,7 @@ export class AzuriteTelemetryClient { private static enableTelemetry: boolean = true; private static location: string; private static configFileName = "AzuriteConfig"; - //private static _totalIngressSize: number = 0; + private static _totalIngressSize: number = 0; //private static _totalEgressSize: number = 0; private static _totalBlobRequestCount: number = 0; private static _totalQueueRequestCount: number = 0; @@ -45,7 +44,7 @@ export class AzuriteTelemetryClient { //Get instaceID and sessionID //TODO: need check if this works on VScode extension AzuriteTelemetryClient.location = location; - AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(); + AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(typeof env?.inMemoryPersistence === "function" && env?.inMemoryPersistence()); AzuriteTelemetryClient.enableTelemetry = enableTelemetry; AzuriteTelemetryClient.env = env; @@ -56,7 +55,7 @@ export class AzuriteTelemetryClient { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) { //TODO: change to 1% in product - this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 1, 0); + this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100, 0); } AzuriteTelemetryClient.appInsights.start(); @@ -89,8 +88,12 @@ export class AzuriteTelemetryClient { public static createAppInsigntClient(cloudRole:string, samplingPercentage:number|undefined, maxBatchSize:number|undefined) : TelemetryClient { - const ConnectionString = 'InstrumentationKey=feb4ae36-1db7-4808-abaa-e0b94996d665;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=9af871a3-75b5-417c-8a2f-7f2eb1ba6a6c'; - + // Xclient APP + //const ConnectionString = 'InstrumentationKey=feb4ae36-1db7-4808-abaa-e0b94996d665;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=9af871a3-75b5-417c-8a2f-7f2eb1ba6a6c'; + + //weiapp + const ConnectionString = 'InstrumentationKey=40e81e8c-36af-4cf3-b46e-a7d67ecb5628;IngestionEndpoint=https://westus-0.in.applicationinsights.azure.com/;LiveEndpoint=https://westus.livediagnostics.monitor.azure.com/;ApplicationId=edbe156f-ede6-4c39-b948-0c0c638c7004' + // disable default logging let appConfig = AzuriteTelemetryClient.appInsights.setup(ConnectionString); appConfig.setAutoCollectRequests(false) @@ -130,6 +133,23 @@ export class AzuriteTelemetryClient { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) { AzuriteTelemetryClient._totalBlobRequestCount++; + let requestProperties: { [key: string]: any } = { + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + //totalReqs:AzuriteTelemetryClient._totalBlobRequestCount, + }; + if (context.request?.getHeader("content-length") !== undefined) + { + const contentLength = context.request?.getHeader("content-length"); + if (contentLength && parseInt(contentLength)) { + requestProperties["requestContentSize"] = contentLength; + this._totalIngressSize += parseInt(contentLength); + } + } + // Responds "content-length" Not work, as responds normally don't have "content-length" header even has body. + AzuriteTelemetryClient.requestClient.trackRequest( { name:"B_" + BlobOperation[context.operation??0], @@ -137,17 +157,10 @@ export class AzuriteTelemetryClient { duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, resultCode:context.response?.getStatusCode()??0, success:true, - id: context.contextId, - source: context.request?.getHeader("user-agent"), - properties: - { - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", - requestContentSize: context.request?.getBody.length, - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, - totalReqs:AzuriteTelemetryClient._totalBlobRequestCount, - }, + // Question: should we move InstanceID and SessionID to telemetry properties id & source, and move requestID and useragent to properties (customDimensions)? + id: context.contextId, // Request ID + source: context.request?.getHeader("user-agent"), // User Agent + properties: requestProperties, contextObjects: { operationId: "", @@ -171,6 +184,22 @@ export class AzuriteTelemetryClient { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) { AzuriteTelemetryClient._totalQueueRequestCount++; + let requestProperties: { [key: string]: any } = { + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + //totalReqs:AzuriteTelemetryClient._totalQueueRequestCount, + }; + if (context.request?.getHeader("content-length") !== undefined) + { + requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); + } + // if(context.response?.getHeader("content-length") !== undefined) + // { + // // Not work, as responds normally don't have "content-length" header, even has body. + // requestProperties["respondsContentSize"] = context.response?.getHeader("content-length"); + // } AzuriteTelemetryClient.requestClient.trackRequest( { name:"Q_" + QueueOperation[context.operation??0], @@ -180,14 +209,7 @@ export class AzuriteTelemetryClient { success:true, id: context.contextID, source: context.request?.getHeader("user-agent"), - properties: - { - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", - requestContentSize: context.request?.getBody.length, - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, - }, + properties: requestProperties, contextObjects: { operationId: "", @@ -211,6 +233,22 @@ export class AzuriteTelemetryClient { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) { AzuriteTelemetryClient._totalTableRequestCount++; + let requestProperties: { [key: string]: any } = { + apiVersion: "v"+context.request?.getHeader("x-ms-version"), + authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + instanceID: AzuriteTelemetryClient.instanceID, + sessionID: AzuriteTelemetryClient.sessionID, + // totalReqs:AzuriteTelemetryClient._totalTableRequestCount, + }; + if (context.request?.getHeader("content-length") !== undefined) + { + requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); + } + // if(context.response?.getHeader("content-length") !== undefined) + // { + // // Not work, as responds normally don't have "content-length" header, even has body. + // requestProperties["respondsContentSize"] = context.response?.getHeader("content-length"); + // } AzuriteTelemetryClient.requestClient.trackRequest( { name:"T_" + TableOperation[context.operation??0], @@ -220,14 +258,7 @@ export class AzuriteTelemetryClient { success:true, id: context.contextID, source: context.request?.getHeader("user-agent"), - properties: - { - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", - requestContentSize: context.request?.getBody.length, - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, - }, + properties: requestProperties, contextObjects: { operationId: "", @@ -280,6 +311,7 @@ export class AzuriteTelemetryClient { blobRequest: AzuriteTelemetryClient._totalBlobRequestCount, queueRequest: AzuriteTelemetryClient._totalQueueRequestCount, tableRequest: AzuriteTelemetryClient._totalTableRequestCount, + totalIngress: this._totalIngressSize, } }); } @@ -315,7 +347,7 @@ export class AzuriteTelemetryClient { } - private static GetInstanceID(): string { + private static GetInstanceID(inMemoryPersistence : boolean = false): string { const configFilePath = join( AzuriteTelemetryClient.location, AzuriteTelemetryClient.configFileName @@ -323,23 +355,27 @@ export class AzuriteTelemetryClient { //const fs = require('fs'); let instaceID = ""; + if (inMemoryPersistence) + { + return uuid(); + } try { if(!fs.existsSync(configFilePath)) { instaceID = uuid(); - fs.writeFile(configFilePath, instaceID, (err) => { - //TODO: write warning for write file failed. + fs.writeFile(configFilePath, `{"instaceID":"${instaceID}"}`, (err) => { + logger.warn('Fail to save instaceID, error: ' + err?.message); }); } else{ let data = fs.readFileSync(configFilePath, 'utf8'); - instaceID = data.toString(); + instaceID = JSON.parse(data.toString()).instaceID; if(instaceID === "") { instaceID = uuid(); fs.writeFile(configFilePath, instaceID, (err) => { - //TODO: write warning for write file failed. + logger.warn('Fail to save instaceID, error: ' + err?.message); }); } @@ -358,8 +394,8 @@ export class AzuriteTelemetryClient { // }); } return instaceID; - } catch { - // TODO: Add warning log for instanceID is empty + } catch (e) { + logger.warn('Fail to generate and save instaceID will use empty instaceID, error: ' + e.message); return instaceID; } } From 6db973017a009a31a6fefc4f7b1f44faf5bae357 Mon Sep 17 00:00:00 2001 From: blueww Date: Mon, 2 Dec 2024 16:33:06 +0800 Subject: [PATCH 08/14] Temp add test coverage --- tests/BlobTestServerFactory.ts | 2 ++ tests/blob/blobCorsRequest.test.ts | 3 +++ tests/queue/oauth.test.ts | 3 +++ tests/queue/utils/QueueTestServerFactory.ts | 2 ++ tests/table/apis/table.entity.azure.data-tables.test.ts | 3 +++ tests/table/utils/TableTestServerFactory.ts | 2 ++ 6 files changed, 15 insertions(+) diff --git a/tests/BlobTestServerFactory.ts b/tests/BlobTestServerFactory.ts index d8c4311cf..9eaa63925 100644 --- a/tests/BlobTestServerFactory.ts +++ b/tests/BlobTestServerFactory.ts @@ -2,6 +2,7 @@ import BlobConfiguration from "../src/blob/BlobConfiguration"; import BlobServer from "../src/blob/BlobServer"; import SqlBlobConfiguration from "../src/blob/SqlBlobConfiguration"; import SqlBlobServer from "../src/blob/SqlBlobServer"; +import { AzuriteTelemetryClient } from "../src/common/Telemetry"; import { StoreDestinationArray } from "../src/common/persistence/IExtentStore"; import { DEFAULT_SQL_OPTIONS } from "../src/common/utils/constants"; import { DEFAULT_BLOB_KEEP_ALIVE_TIMEOUT } from "../src/blob/utils/constants"; @@ -78,6 +79,7 @@ export default class BlobTestServerFactory { undefined, inMemoryPersistence ); + AzuriteTelemetryClient.init("", true, undefined); return new BlobServer(config); } } diff --git a/tests/blob/blobCorsRequest.test.ts b/tests/blob/blobCorsRequest.test.ts index cd54d667f..143d97857 100644 --- a/tests/blob/blobCorsRequest.test.ts +++ b/tests/blob/blobCorsRequest.test.ts @@ -15,6 +15,7 @@ import { } from "../testutils"; import OPTIONSRequestPolicyFactory from "./RequestPolicy/OPTIONSRequestPolicyFactory"; import OriginPolicyFactory from "./RequestPolicy/OriginPolicyFactory"; +import { AzuriteTelemetryClient } from "../../src/common/Telemetry"; // Set true to enable debug log configLogger(false); @@ -41,11 +42,13 @@ describe("Blob Cors requests test", () => { before(async () => { await server.start(); + await AzuriteTelemetryClient.TraceStartEvent("Blob Test"); }); after(async () => { await server.close(); await server.clean(); + AzuriteTelemetryClient.TraceStopEvent("Blob Test"); }); it("OPTIONS request without cors rules in server should be fail @loki @sql", async () => { diff --git a/tests/queue/oauth.test.ts b/tests/queue/oauth.test.ts index 99f394181..176391cab 100644 --- a/tests/queue/oauth.test.ts +++ b/tests/queue/oauth.test.ts @@ -8,6 +8,7 @@ import { StoreDestinationArray } from "../../src/common/persistence/IExtentStore import { EMULATOR_ACCOUNT_KEY, generateJWTToken, getUniqueName } from "../testutils"; import { SimpleTokenCredential } from "../simpleTokenCredential"; import QueueTestServerFactory from "./utils/QueueTestServerFactory"; +import { AzuriteTelemetryClient } from "../../src/common/Telemetry"; // Set true to enable debug log configLogger(false); @@ -41,11 +42,13 @@ describe("Queue OAuth Basic", () => { oauth: "basic" }) await server.start(); + await AzuriteTelemetryClient.TraceStartEvent("Queue Test"); }); after(async () => { await server.close(); await server.clean(); + AzuriteTelemetryClient.TraceStopEvent("Queue Test"); }); it(`Should work with create container @loki @sql`, async () => { diff --git a/tests/queue/utils/QueueTestServerFactory.ts b/tests/queue/utils/QueueTestServerFactory.ts index 19f7078ba..7d541a8f3 100644 --- a/tests/queue/utils/QueueTestServerFactory.ts +++ b/tests/queue/utils/QueueTestServerFactory.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from "../../../src/common/Telemetry" import { StoreDestinationArray } from "../../../src/common/persistence/IExtentStore" import QueueConfiguration from "../../../src/queue/QueueConfiguration" import QueueServer from "../../../src/queue/QueueServer" @@ -45,6 +46,7 @@ export default class QueueTestServerFactory { undefined, inMemoryPersistence ); + AzuriteTelemetryClient.init("", true, undefined); return new QueueServer(config); } } diff --git a/tests/table/apis/table.entity.azure.data-tables.test.ts b/tests/table/apis/table.entity.azure.data-tables.test.ts index 3f4b9f3ff..a4d8ef0b0 100644 --- a/tests/table/apis/table.entity.azure.data-tables.test.ts +++ b/tests/table/apis/table.entity.azure.data-tables.test.ts @@ -20,6 +20,7 @@ import { LargeDataTablesTestEntityFactory, LargeTableTestEntity } from "../models/LargeDataTablesTestEntityFactory"; +import { AzuriteTelemetryClient } from "../../../src/common/Telemetry"; // Set true to enable debug log configLogger(false); // For convenience, we have a switch to control the use @@ -38,10 +39,12 @@ describe("table Entity APIs test - using Azure/data-tables", () => { before(async () => { server = createTableServerForTestHttps(); await server.start(); + await AzuriteTelemetryClient.TraceStartEvent("Table Test"); }); after(async () => { await server.close(); + AzuriteTelemetryClient.TraceStopEvent("Table Test"); }); it("01. Batch API should return row keys in format understood by @azure/data-tables, @loki", async () => { diff --git a/tests/table/utils/TableTestServerFactory.ts b/tests/table/utils/TableTestServerFactory.ts index 026ebddd6..d4c05239a 100644 --- a/tests/table/utils/TableTestServerFactory.ts +++ b/tests/table/utils/TableTestServerFactory.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from "../../../src/common/Telemetry"; import TableConfiguration from "../../../src/table/TableConfiguration"; import TableServer from "../../../src/table/TableServer"; import { DEFAULT_TABLE_KEEP_ALIVE_TIMEOUT } from "../../../src/table/utils/constants"; @@ -44,6 +45,7 @@ export default class TableTestServerFactory { undefined, inMemoryPersistence ); + AzuriteTelemetryClient.init("", true, undefined); return new TableServer(config); } } From 803761584f196c7ffd527b6c9d7d63aeb18a1a33 Mon Sep 17 00:00:00 2001 From: blueww Date: Mon, 2 Dec 2024 16:54:21 +0800 Subject: [PATCH 09/14] REvise the debug config --- .gitignore | 3 ++- src/common/Telemetry.ts | 55 ++++++++++++++--------------------------- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index c3f59e447..4ab63a552 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ temp azurite.exe .pkg-cache release -querydb*.json \ No newline at end of file +querydb*.json +AzuriteConfig \ No newline at end of file diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 7ed2b3998..f9638e5e8 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -32,17 +32,23 @@ export class AzuriteTelemetryClient { public static envAccountIsSet = false; public static envDBIsSet = false; + // Debug options + private static isDebug = false; + private static requestCollectPercentage = AzuriteTelemetryClient.isDebug ? 100 : 1; + private static enableAppInsightLog = AzuriteTelemetryClient.isDebug? true : false; + private static cloudRole = AzuriteTelemetryClient.isDebug ? "AzuriteTest" : "Azurite"; + // 0 means send as soon as it's collected, use it in both debug and release mode, since set any other value will make Azurite exist slower + private static requestMaxBatchSize = AzuriteTelemetryClient.isDebug ? 0 : 0; + + private static appInsights = require('applicationinsights'); public static init(location: string, enableTelemetry: boolean, env: any) { try{ - //TODO: check in VSCODE extension AzuriteTelemetryClient.enableTelemetry = enableTelemetry; if (enableTelemetry !== false && AzuriteTelemetryClient.initialized != true) { - //Get instaceID and sessionID - //TODO: need check if this works on VScode extension AzuriteTelemetryClient.location = location; AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(typeof env?.inMemoryPersistence === "function" && env?.inMemoryPersistence()); @@ -50,12 +56,12 @@ export class AzuriteTelemetryClient { AzuriteTelemetryClient.env = env; if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) { - this.eventClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100, 0); + // for start/stop event, will collect 100%, and send asap + this.eventClient = AzuriteTelemetryClient.createAppInsigntClient(AzuriteTelemetryClient.cloudRole, 100, 0); } if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) { - //TODO: change to 1% in product - this.requestClient = AzuriteTelemetryClient.createAppInsigntClient("AzuriteTest", 100, 0); + this.requestClient = AzuriteTelemetryClient.createAppInsigntClient(AzuriteTelemetryClient.cloudRole, AzuriteTelemetryClient.requestCollectPercentage, AzuriteTelemetryClient.requestMaxBatchSize); } AzuriteTelemetryClient.appInsights.start(); @@ -75,8 +81,7 @@ export class AzuriteTelemetryClient { } private static removeRoleInstance ( envelope: Contracts.EnvelopeTelemetry) : boolean { - //var data = envelope.data.baseData; - // envelope.tags["ai.cloud.role"] = ""; + // per privacy review, will not collect roleInstance name envelope.tags["ai.cloud.roleInstance"] = createHash('sha256').update(envelope.tags["ai.cloud.roleInstance"]).digest('hex'); // per privacy review, we will not collect operation name as it contains request path @@ -88,7 +93,7 @@ export class AzuriteTelemetryClient { public static createAppInsigntClient(cloudRole:string, samplingPercentage:number|undefined, maxBatchSize:number|undefined) : TelemetryClient { - // Xclient APP + // Xclient APP: AzuriteTelemetryProd //const ConnectionString = 'InstrumentationKey=feb4ae36-1db7-4808-abaa-e0b94996d665;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=9af871a3-75b5-417c-8a2f-7f2eb1ba6a6c'; //weiapp @@ -117,9 +122,11 @@ export class AzuriteTelemetryClient { telemetryClient.config.samplingPercentage = samplingPercentage??100; - // For development only, make your telemetry to be sent as soon as it's collected. // Enable AppInsight log, should enable in develoipment only - // appConfig.setInternalLogging(true, true); + if (AzuriteTelemetryClient.enableAppInsightLog) + { + appConfig.setInternalLogging(true, true); + } if (maxBatchSize !== undefined) { telemetryClient.config.maxBatchSize = maxBatchSize??0; @@ -195,11 +202,6 @@ export class AzuriteTelemetryClient { { requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); } - // if(context.response?.getHeader("content-length") !== undefined) - // { - // // Not work, as responds normally don't have "content-length" header, even has body. - // requestProperties["respondsContentSize"] = context.response?.getHeader("content-length"); - // } AzuriteTelemetryClient.requestClient.trackRequest( { name:"Q_" + QueueOperation[context.operation??0], @@ -244,11 +246,6 @@ export class AzuriteTelemetryClient { { requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); } - // if(context.response?.getHeader("content-length") !== undefined) - // { - // // Not work, as responds normally don't have "content-length" header, even has body. - // requestProperties["respondsContentSize"] = context.response?.getHeader("content-length"); - // } AzuriteTelemetryClient.requestClient.trackRequest( { name:"T_" + TableOperation[context.operation??0], @@ -287,7 +284,6 @@ export class AzuriteTelemetryClient { instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, parameters: await AzuriteTelemetryClient.GetAllParameterString() - // TODO: Add start Parameters } }); } @@ -353,7 +349,6 @@ export class AzuriteTelemetryClient { AzuriteTelemetryClient.configFileName ); - //const fs = require('fs'); let instaceID = ""; if (inMemoryPersistence) { @@ -378,20 +373,6 @@ export class AzuriteTelemetryClient { logger.warn('Fail to save instaceID, error: ' + err?.message); }); } - - // fs.readFile(configFilePath, function (err, data) { - // if (!err) - // { - // instaceID = data.toString(); - // } - // else - // { - // instaceID = uuid(); - // fs.writeFile(configFilePath, instaceID, (err) => { - // //TODO: write warning for write file failed. - // }); - // } - // }); } return instaceID; } catch (e) { From b21e3d34fa8d14290b7baa254dbcd578bfe179e9 Mon Sep 17 00:00:00 2001 From: blueww Date: Thu, 5 Dec 2024 09:43:10 +0800 Subject: [PATCH 10/14] Update the way to get parameters --- package-lock.json | 372 ++++++++++++---------------- package.json | 4 +- src/common/Telemetry.ts | 214 ++++++++++------ src/common/VSCEnvironment.ts | 2 +- src/common/VSCServerManagerBlob.ts | 2 +- src/common/VSCServerManagerQueue.ts | 2 +- src/common/VSCServerManagerTable.ts | 2 +- 7 files changed, 308 insertions(+), 290 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51f3105fb..4b292c0cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@azure/ms-rest-js": "^1.5.0", - "applicationinsights": "^2.9.5", + "applicationinsights": "^2.9.6", "args": "^5.0.1", "axios": "^0.27.0", "etag": "^1.8.1", @@ -117,16 +117,29 @@ "integrity": "sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg==" }, "node_modules/@azure/core-auth": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.5.0.tgz", - "integrity": "sha512-udzoBuYG1VBoHVohDTrvKjyzel34zt77Bhp7dQntVGGD0ehVq48owENbBG8fIgkHRNUBQH5k1r0hpoMu5L8+kw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "license": "MIT", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.1.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-client": { @@ -240,22 +253,34 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.12.2.tgz", - "integrity": "sha512-wLLJQdL4v1yoqYtEtjKNjf8pJ/G/BqVomAWxcKOR1KbZJyCEnCv04yks7Y1NhJ3JzxbDs307W67uX0JzklFdCg==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.3.tgz", + "integrity": "sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w==", + "license": "MIT", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.3.0", + "@azure/core-util": "^1.9.0", "@azure/logger": "^1.0.0", - "form-data": "^4.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0" + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-rest-pipeline/node_modules/@azure/core-tracing": { @@ -269,17 +294,29 @@ "node": ">=12.0.0" } }, - "node_modules/@azure/core-rest-pipeline/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/@azure/core-rest-pipeline/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/@azure/core-tracing": { @@ -295,12 +332,13 @@ } }, "node_modules/@azure/core-util": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.7.0.tgz", - "integrity": "sha512-Zq2i3QO6k9DA8vnm29mYM4G8IE9u1mhF1GUabVEqPNX8Lj833gdxQ2NAFxt2BZsfAL+e9cT8SyVN7dFVJ/Hf0g==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", + "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", + "license": "MIT", "dependencies": { "@azure/abort-controller": "^2.0.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" @@ -1210,14 +1248,6 @@ "node": ">=14" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -1867,6 +1897,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "dependencies": { "debug": "4" }, @@ -1948,13 +1979,13 @@ } }, "node_modules/applicationinsights": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.9.5.tgz", - "integrity": "sha512-APQ8IWyYDHFvKbitFKpsmZXxkzQh0yYTFacQqoVW7HwlPo3eeLprwnq5RFNmmG6iqLmvQ+xRJSDLEQCgqPh+bw==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.9.6.tgz", + "integrity": "sha512-BLeBYJUZaKmnzqG/6Q/IFSCqpiVECjSTIvwozLex/1ZZpSxOjPiBxGMev+iIBfNZ2pc7vvnV7DuPOtsoG2DJeQ==", + "license": "MIT", "dependencies": { - "@azure/core-auth": "^1.5.0", - "@azure/core-rest-pipeline": "1.10.1", - "@azure/core-util": "1.2.0", + "@azure/core-auth": "1.7.2", + "@azure/core-rest-pipeline": "1.16.3", "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.5", "@microsoft/applicationinsights-web-snippet": "1.0.1", "@opentelemetry/api": "^1.7.0", @@ -1978,70 +2009,6 @@ } } }, - "node_modules/applicationinsights/node_modules/@azure/core-rest-pipeline": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.1.tgz", - "integrity": "sha512-Kji9k6TOFRDB5ZMTw8qUf2IJ+CeJtsuMdAHox9eqpTf1cefiNMpzrfnF6sINEBZJsaVaWgQ0o48B6kcUH68niA==", - "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.4.0", - "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.0.0", - "@azure/logger": "^1.0.0", - "form-data": "^4.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/applicationinsights/node_modules/@azure/core-tracing": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", - "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", - "dependencies": { - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/applicationinsights/node_modules/@azure/core-util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz", - "integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==", - "dependencies": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/applicationinsights/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/applicationinsights/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -6054,16 +6021,28 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/http-signature": { @@ -6085,6 +6064,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -10700,13 +10680,23 @@ "integrity": "sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg==" }, "@azure/core-auth": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.5.0.tgz", - "integrity": "sha512-udzoBuYG1VBoHVohDTrvKjyzel34zt77Bhp7dQntVGGD0ehVq48owENbBG8fIgkHRNUBQH5k1r0hpoMu5L8+kw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", "requires": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.1.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + } } }, "@azure/core-client": { @@ -10801,21 +10791,28 @@ } }, "@azure/core-rest-pipeline": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.12.2.tgz", - "integrity": "sha512-wLLJQdL4v1yoqYtEtjKNjf8pJ/G/BqVomAWxcKOR1KbZJyCEnCv04yks7Y1NhJ3JzxbDs307W67uX0JzklFdCg==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.3.tgz", + "integrity": "sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w==", "requires": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.3.0", + "@azure/core-util": "^1.9.0", "@azure/logger": "^1.0.0", - "form-data": "^4.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0" + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" }, "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + }, "@azure/core-tracing": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", @@ -10824,14 +10821,21 @@ "tslib": "^2.2.0" } }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" } } } @@ -10846,12 +10850,12 @@ } }, "@azure/core-util": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.7.0.tgz", - "integrity": "sha512-Zq2i3QO6k9DA8vnm29mYM4G8IE9u1mhF1GUabVEqPNX8Lj833gdxQ2NAFxt2BZsfAL+e9cT8SyVN7dFVJ/Hf0g==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", + "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", "requires": { "@azure/abort-controller": "^2.0.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "dependencies": { "@azure/abort-controller": { @@ -11553,11 +11557,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==" }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" - }, "@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -12064,6 +12063,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "requires": { "debug": "4" } @@ -12120,13 +12120,12 @@ } }, "applicationinsights": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.9.5.tgz", - "integrity": "sha512-APQ8IWyYDHFvKbitFKpsmZXxkzQh0yYTFacQqoVW7HwlPo3eeLprwnq5RFNmmG6iqLmvQ+xRJSDLEQCgqPh+bw==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-2.9.6.tgz", + "integrity": "sha512-BLeBYJUZaKmnzqG/6Q/IFSCqpiVECjSTIvwozLex/1ZZpSxOjPiBxGMev+iIBfNZ2pc7vvnV7DuPOtsoG2DJeQ==", "requires": { - "@azure/core-auth": "^1.5.0", - "@azure/core-rest-pipeline": "1.10.1", - "@azure/core-util": "1.2.0", + "@azure/core-auth": "1.7.2", + "@azure/core-rest-pipeline": "1.16.3", "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.5", "@microsoft/applicationinsights-web-snippet": "1.0.1", "@opentelemetry/api": "^1.7.0", @@ -12137,57 +12136,6 @@ "continuation-local-storage": "^3.2.1", "diagnostic-channel": "1.1.1", "diagnostic-channel-publishers": "1.0.8" - }, - "dependencies": { - "@azure/core-rest-pipeline": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.1.tgz", - "integrity": "sha512-Kji9k6TOFRDB5ZMTw8qUf2IJ+CeJtsuMdAHox9eqpTf1cefiNMpzrfnF6sINEBZJsaVaWgQ0o48B6kcUH68niA==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.4.0", - "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.0.0", - "@azure/logger": "^1.0.0", - "form-data": "^4.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0", - "uuid": "^8.3.0" - } - }, - "@azure/core-tracing": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", - "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", - "requires": { - "tslib": "^2.2.0" - } - }, - "@azure/core-util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz", - "integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" - } - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - } } }, "arg": { @@ -15366,13 +15314,22 @@ } }, "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "dependencies": { + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "requires": { + "debug": "^4.3.4" + } + } } }, "http-signature": { @@ -15390,6 +15347,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, "requires": { "agent-base": "6", "debug": "4" diff --git a/package.json b/package.json index 02dbf7815..37522d2aa 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "@azure/ms-rest-js": "^1.5.0", - "applicationinsights": "^2.9.5", + "applicationinsights": "^2.9.6", "args": "^5.0.1", "axios": "^0.27.0", "etag": "^1.8.1", @@ -346,4 +346,4 @@ "url": "https://github.com/azure/azurite/issues" }, "homepage": "https://github.com/azure/azurite#readme" -} \ No newline at end of file +} diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index f9638e5e8..76b85b193 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -31,6 +31,7 @@ export class AzuriteTelemetryClient { private static env: any = undefined; public static envAccountIsSet = false; public static envDBIsSet = false; + public static isVSC = false; // Debug options private static isDebug = false; @@ -43,12 +44,13 @@ export class AzuriteTelemetryClient { private static appInsights = require('applicationinsights'); - public static init(location: string, enableTelemetry: boolean, env: any) { + public static init(location: string, enableTelemetry: boolean, env: any, isVSC: boolean = false) { try{ AzuriteTelemetryClient.enableTelemetry = enableTelemetry; if (enableTelemetry !== false && AzuriteTelemetryClient.initialized != true) { + AzuriteTelemetryClient.isVSC = isVSC; AzuriteTelemetryClient.location = location; AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(typeof env?.inMemoryPersistence === "function" && env?.inMemoryPersistence()); @@ -163,7 +165,7 @@ export class AzuriteTelemetryClient { url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, resultCode:context.response?.getStatusCode()??0, - success:true, + success:context.response?.getStatusCode()?.toString().startsWith("2")??false, // Question: should we move InstanceID and SessionID to telemetry properties id & source, and move requestID and useragent to properties (customDimensions)? id: context.contextId, // Request ID source: context.request?.getHeader("user-agent"), // User Agent @@ -208,7 +210,7 @@ export class AzuriteTelemetryClient { url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, resultCode:context.response?.getStatusCode()??0, - success:true, + success:context.response?.getStatusCode()?.toString().startsWith("2")??false, id: context.contextID, source: context.request?.getHeader("user-agent"), properties: requestProperties, @@ -252,7 +254,7 @@ export class AzuriteTelemetryClient { url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, resultCode:context.response?.getStatusCode()??0, - success:true, + success:context.response?.getStatusCode()?.toString().startsWith("2")??false, id: context.contextID, source: context.request?.getHeader("user-agent"), properties: requestProperties, @@ -411,83 +413,141 @@ export class AzuriteTelemetryClient { { return parameters; } + let longParameters = ["blobHost","queueHost","tableHost","blobPort","queuePort","tablePort","blobKeepAliveTimeout","queueKeepAliveTimeout","tableKeepAliveTimeout","location","cert","key","pwd","oauth","extentMemoryLimit","debug","silent","loose","skipApiVersionCheck","disableProductStyleUrl","inMemoryPersistence","disableTelemetry"]; + let shortParameters: { [string: string]: any } = {"d": "debug", "l": "location", "L": "loose", "s": "silent"}; - if (typeof AzuriteTelemetryClient.env?.blobHost === "function" && AzuriteTelemetryClient.env?.blobHost() !== undefined && AzuriteTelemetryClient.env?.blobHost() !== "127.0.0.1") + if (AzuriteTelemetryClient.isVSC) // VSC { - parameters += "blobHost,"; - } - if (typeof AzuriteTelemetryClient.env?.queueHost === "function" && AzuriteTelemetryClient.env?.queueHost() !== undefined && AzuriteTelemetryClient.env?.queueHost() !== "127.0.0.1") - { - parameters += "queueHost,"; - } - if (typeof AzuriteTelemetryClient.env?.tableHost === "function" && AzuriteTelemetryClient.env?.tableHost() !== undefined && AzuriteTelemetryClient.env?.tableHost() !== "127.0.0.1") - { - parameters += "tableHost,"; - } - if (typeof AzuriteTelemetryClient.env?.blobPort === "function" && AzuriteTelemetryClient.env?.blobPort() !== undefined && AzuriteTelemetryClient.env?.blobPort() !== 10000) - { - parameters += "blobPort,"; - } - if (typeof AzuriteTelemetryClient.env?.queuePort === "function" && AzuriteTelemetryClient.env?.queuePort() !== undefined && AzuriteTelemetryClient.env?.queuePort() !== 10001) - { - parameters += "queuePort,"; - } - if (typeof AzuriteTelemetryClient.env?.tablePort === "function" && AzuriteTelemetryClient.env?.tablePort() !== undefined && AzuriteTelemetryClient.env?.tablePort() !== 10002) - { - parameters += "tablePort,"; - } - if (typeof AzuriteTelemetryClient.env?.location === "function" && (await AzuriteTelemetryClient.env?.location()) !== undefined) - { - parameters += "location,"; - } - if (typeof AzuriteTelemetryClient.env?.silent === "function" && AzuriteTelemetryClient.env?.silent()) - { - parameters += "silent,"; - } - if (typeof AzuriteTelemetryClient.env?.loose === "function" && AzuriteTelemetryClient.env?.loose()) - { - parameters += "loose,"; - } - if (typeof AzuriteTelemetryClient.env?.skipApiVersionCheck === "function" && AzuriteTelemetryClient.env?.skipApiVersionCheck()) - { - parameters += "skipApiVersionCheck,"; - } - if (typeof AzuriteTelemetryClient.env?.disableProductStyleUrl === "function" && AzuriteTelemetryClient.env?.disableProductStyleUrl()) - { - parameters += "disableProductStyleUrl,"; - } - if (typeof AzuriteTelemetryClient.env?.cert === "function" && AzuriteTelemetryClient.env?.cert() !== undefined) - { - parameters += "cert,"; - } - if (typeof AzuriteTelemetryClient.env?.key === "function" && AzuriteTelemetryClient.env?.key() !== undefined) - { - parameters += "key,"; - } - if (typeof AzuriteTelemetryClient.env?.pwd === "function" && AzuriteTelemetryClient.env?.pwd() !== undefined) - { - parameters += "pwd,"; - } - if (typeof AzuriteTelemetryClient.env?.oauth === "function" && AzuriteTelemetryClient.env?.oauth() !== undefined) - { - parameters += "oauth,"; - } - if (typeof AzuriteTelemetryClient.env?.inMemoryPersistence === "function" && AzuriteTelemetryClient.env?.inMemoryPersistence()) - { - parameters += "inMemoryPersistence,"; - } - if (typeof AzuriteTelemetryClient.env?.extentMemoryLimit === "function" && AzuriteTelemetryClient.env?.extentMemoryLimit() !== undefined) - { - parameters += "extentMemoryLimit,"; - } - if (typeof AzuriteTelemetryClient.env?.disableTelemetry === "function" && AzuriteTelemetryClient.env?.disableTelemetry()) - { - parameters += "disableTelemetry,"; + let workspaceConfiguration = AzuriteTelemetryClient.env; + if (workspaceConfiguration === undefined) + { + return parameters; + } + else + { + longParameters.forEach((flag) => { + let value = workspaceConfiguration.get(flag); + if (value !== undefined && value !== "" && value !== false && value !== null + && !(flag.endsWith("Host") && value === "localhost") + && !(flag.endsWith("KeepAliveTimeout") && value === 5) + && !(flag == "blobPort" && value === 10000) + && !(flag == "queuePort" && value === 10001) + && !(flag == "tablePort" && value === 10002)) + { + parameters += flag + ","; + } + }); + } } - if (typeof AzuriteTelemetryClient.env?.debug === "function" && (await AzuriteTelemetryClient.env?.debug()) !== undefined) + else // npm (exe, docker) { - parameters += "debug,"; + process.argv.forEach((val, index) => { + if (val.startsWith("--")) + { + longParameters.forEach((flag) => { + if (val.toLowerCase() === (`--${flag}`).toLowerCase()) + { + parameters += flag + ","; + } + }); + } + else if(val.startsWith("-")) { + if(shortParameters[val.substring(1)] !== undefined) + { + parameters += shortParameters[val.substring(1)] + ","; + } + } + }); } - return parameters; + + // if (typeof AzuriteTelemetryClient.env?.blobHost === "function" && AzuriteTelemetryClient.env?.blobHost() !== undefined && AzuriteTelemetryClient.env?.blobHost() !== "127.0.0.1") + // { + // parameters += "blobHost,"; + // } + // if (typeof AzuriteTelemetryClient.env?.queueHost === "function" && AzuriteTelemetryClient.env?.queueHost() !== undefined && AzuriteTelemetryClient.env?.queueHost() !== "127.0.0.1") + // { + // parameters += "queueHost,"; + // } + // if (typeof AzuriteTelemetryClient.env?.tableHost === "function" && AzuriteTelemetryClient.env?.tableHost() !== undefined && AzuriteTelemetryClient.env?.tableHost() !== "127.0.0.1") + // { + // parameters += "tableHost,"; + // } + // if (typeof AzuriteTelemetryClient.env?.blobPort === "function" && AzuriteTelemetryClient.env?.blobPort() !== undefined && AzuriteTelemetryClient.env?.blobPort() !== 10000) + // { + // parameters += "blobPort,"; + // } + // if (typeof AzuriteTelemetryClient.env?.queuePort === "function" && AzuriteTelemetryClient.env?.queuePort() !== undefined && AzuriteTelemetryClient.env?.queuePort() !== 10001) + // { + // parameters += "queuePort,"; + // } + // if (typeof AzuriteTelemetryClient.env?.tablePort === "function" && AzuriteTelemetryClient.env?.tablePort() !== undefined && AzuriteTelemetryClient.env?.tablePort() !== 10002) + // { + // parameters += "tablePort,"; + // } + // if (typeof AzuriteTelemetryClient.env?.blobKeepAliveTimeout === "function" && AzuriteTelemetryClient.env?.blobKeepAliveTimeout() !== undefined && AzuriteTelemetryClient.env?.blobKeepAliveTimeout() !== 5) + // { + // parameters += "blobKeepAliveTimeout,"; + // } + // if (typeof AzuriteTelemetryClient.env?.queueKeepAliveTimeout === "function" && AzuriteTelemetryClient.env?.queueKeepAliveTimeout() !== undefined && AzuriteTelemetryClient.env?.queueKeepAliveTimeout() !== 5) + // { + // parameters += "queueKeepAliveTimeout,"; + // } + // if (typeof AzuriteTelemetryClient.env?.tableKeepAliveTimeout === "function" && AzuriteTelemetryClient.env?.tableKeepAliveTimeout() !== undefined && AzuriteTelemetryClient.env?.tableKeepAliveTimeout() !== 5) + // { + // parameters += "tableKeepAliveTimeout,"; + // } + // if (typeof AzuriteTelemetryClient.env?.location === "function" && (await AzuriteTelemetryClient.env?.location()) !== undefined) + // { + // parameters += "location,"; + // } + // if (typeof AzuriteTelemetryClient.env?.silent === "function" && AzuriteTelemetryClient.env?.silent()) + // { + // parameters += "silent,"; + // } + // if (typeof AzuriteTelemetryClient.env?.loose === "function" && AzuriteTelemetryClient.env?.loose()) + // { + // parameters += "loose,"; + // } + // if (typeof AzuriteTelemetryClient.env?.skipApiVersionCheck === "function" && AzuriteTelemetryClient.env?.skipApiVersionCheck()) + // { + // parameters += "skipApiVersionCheck,"; + // } + // if (typeof AzuriteTelemetryClient.env?.disableProductStyleUrl === "function" && AzuriteTelemetryClient.env?.disableProductStyleUrl()) + // { + // parameters += "disableProductStyleUrl,"; + // } + // if (typeof AzuriteTelemetryClient.env?.cert === "function" && AzuriteTelemetryClient.env?.cert() !== undefined) + // { + // parameters += "cert,"; + // } + // if (typeof AzuriteTelemetryClient.env?.key === "function" && AzuriteTelemetryClient.env?.key() !== undefined) + // { + // parameters += "key,"; + // } + // if (typeof AzuriteTelemetryClient.env?.pwd === "function" && AzuriteTelemetryClient.env?.pwd() !== undefined) + // { + // parameters += "pwd,"; + // } + // if (typeof AzuriteTelemetryClient.env?.oauth === "function" && AzuriteTelemetryClient.env?.oauth() !== undefined) + // { + // parameters += "oauth,"; + // } + // if (typeof AzuriteTelemetryClient.env?.inMemoryPersistence === "function" && AzuriteTelemetryClient.env?.inMemoryPersistence()) + // { + // parameters += "inMemoryPersistence,"; + // } + // if (typeof AzuriteTelemetryClient.env?.extentMemoryLimit === "function" && AzuriteTelemetryClient.env?.extentMemoryLimit() !== undefined) + // { + // parameters += "extentMemoryLimit,"; + // } + // if (typeof AzuriteTelemetryClient.env?.disableTelemetry === "function" && AzuriteTelemetryClient.env?.disableTelemetry()) + // { + // parameters += "disableTelemetry,"; + // } + // if (typeof AzuriteTelemetryClient.env?.debug === "function" && (await AzuriteTelemetryClient.env?.debug()) !== undefined) + // { + // parameters += "debug,"; + // } + return parameters.endsWith(",") ? parameters.substring(0, parameters.length - 1) : parameters; } } \ No newline at end of file diff --git a/src/common/VSCEnvironment.ts b/src/common/VSCEnvironment.ts index 04e0ea771..0bcff08f5 100644 --- a/src/common/VSCEnvironment.ts +++ b/src/common/VSCEnvironment.ts @@ -5,7 +5,7 @@ import { window, workspace, WorkspaceFolder } from "vscode"; import IEnvironment from "./IEnvironment"; export default class VSCEnvironment implements IEnvironment { - private workspaceConfiguration = workspace.getConfiguration("azurite"); + public workspaceConfiguration = workspace.getConfiguration("azurite"); public blobHost(): string | undefined { return this.workspaceConfiguration.get("blobHost"); diff --git a/src/common/VSCServerManagerBlob.ts b/src/common/VSCServerManagerBlob.ts index 0667187e4..30639d85d 100644 --- a/src/common/VSCServerManagerBlob.ts +++ b/src/common/VSCServerManagerBlob.ts @@ -72,7 +72,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { location, DEFAULT_BLOB_PERSISTENCE_PATH ); - AzuriteTelemetryClient.init(DEFAULT_BLOB_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry(), env); + AzuriteTelemetryClient.init(DEFAULT_BLOB_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry(), env.workspaceConfiguration, true); // Initialize server configuration const config = new BlobConfiguration( diff --git a/src/common/VSCServerManagerQueue.ts b/src/common/VSCServerManagerQueue.ts index 0c1c1dc98..ef880a575 100644 --- a/src/common/VSCServerManagerQueue.ts +++ b/src/common/VSCServerManagerQueue.ts @@ -75,7 +75,7 @@ export default class VSCServerManagerBlob extends VSCServerManagerBase { location, DEFAULT_QUEUE_PERSISTENCE_PATH ); - AzuriteTelemetryClient.init(DEFAULT_QUEUE_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry(), env); + AzuriteTelemetryClient.init(DEFAULT_QUEUE_PERSISTENCE_ARRAY[0].locationPath, !env.disableTelemetry(), env.workspaceConfiguration, true); // Initialize server configuration const config = new QueueConfiguration( diff --git a/src/common/VSCServerManagerTable.ts b/src/common/VSCServerManagerTable.ts index dd88861e3..0ea1c6d74 100644 --- a/src/common/VSCServerManagerTable.ts +++ b/src/common/VSCServerManagerTable.ts @@ -64,7 +64,7 @@ export default class VSCServerManagerTable extends VSCServerManagerBase { private async getConfiguration(): Promise { const env = new VSCEnvironment(); const location = await env.location(); - AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env.workspaceConfiguration, true); // Initialize server configuration const config = new TableConfiguration( From 74afb5fc91f494259c5c4f0b513a18672ec3dd9f Mon Sep 17 00:00:00 2001 From: blueww Date: Thu, 5 Dec 2024 17:13:13 +0800 Subject: [PATCH 11/14] Add doc --- ChangeLog.md | 4 ++++ README.mcr.md | 4 +++- README.md | 15 +++++++++++++-- src/common/Telemetry.ts | 24 ++++++++++++++---------- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 2d45ef3d9..3b202afcb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,6 +4,10 @@ ## Upcoming Release +General: + +- Add telemetry data collection to help improve the product. By default telemetry data will be collected. Add `--disableTelemetry` options disable telemetry data collection of this Azurite execution. + ## 2024.10 Version 3.33.0 General: diff --git a/README.mcr.md b/README.mcr.md index 7dea96e80..a6d06e5cd 100644 --- a/README.mcr.md +++ b/README.mcr.md @@ -47,7 +47,7 @@ docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 -v c:/azurite:/data mcr. **Customize Azurite V3 supported parameters for docker image** ```bash -docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --queuePort 8888 --queueHost 0.0.0.0 --tablePort 9999 --tableHost 0.0.0.0 --loose --skipApiVersionCheck --disableProductStyleUrl +docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --queuePort 8888 --queueHost 0.0.0.0 --tablePort 9999 --tableHost 0.0.0.0 --loose --skipApiVersionCheck --disableProductStyleUrl --disableTelemetry ``` Above command will try to start Azurite image with configurations: @@ -74,6 +74,8 @@ Above command will try to start Azurite image with configurations: `--disableProductStyleUrl` force parsing storage account name from request URI path, instead of from request URI host. +`--disableTelemetry` disable telemetry data collection of this Azurite execution. By default, Azurite will collect telemetry data to help improve the product. + > If you use customized azurite parameters for docker image, `--blobHost 0.0.0.0`, `--queueHost 0.0.0.0` are required parameters. > In above sample, you need to use **double first forward slash** for location and debug path parameters to avoid a [known issue](https://stackoverflow.com/questions/48427366/docker-build-command-add-c-program-files-git-to-the-path-passed-as-build-argu) for Git on Windows. diff --git a/README.md b/README.md index cc26b4280..856459329 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ Following extension configurations are supported: - `azurite.disableProductStyleUrl` Force parsing storage account name from request URI path, instead of from request URI host. - `azurite.inMemoryPersistence` Disable persisting any data to disk. If the Azurite process is terminated, all data is lost. - `azurite.extentMemoryLimit` When using in-memory persistence, limit the total size of extents (blob and queue content) to a specific number of megabytes. This does not limit blob, queue, or table metadata. Defaults to 50% of total memory. +- `azurite.disableTelemetry` Disable telemetry data collection of this Azurite execution. By default, Azurite will collect telemetry data to help improve the product. ### [DockerHub](https://hub.docker.com/_/microsoft-azure-storage-azurite) @@ -236,7 +237,7 @@ docker run -p 10000:10000 -p 10001:10001 -v c:/azurite:/data mcr.microsoft.com/a #### Customize all Azurite V3 supported parameters for docker image ```bash -docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --blobKeepAliveTimeout 5 --queuePort 8888 --queueHost 0.0.0.0 --queueKeepAliveTimeout 5 --tablePort 9999 --tableHost 0.0.0.0 --tableKeepAliveTimeout 5 --loose --skipApiVersionCheck --disableProductStyleUrl +docker run -p 7777:7777 -p 8888:8888 -p 9999:9999 -v c:/azurite:/workspace mcr.microsoft.com/azure-storage/azurite azurite -l /workspace -d /workspace/debug.log --blobPort 7777 --blobHost 0.0.0.0 --blobKeepAliveTimeout 5 --queuePort 8888 --queueHost 0.0.0.0 --queueKeepAliveTimeout 5 --tablePort 9999 --tableHost 0.0.0.0 --tableKeepAliveTimeout 5 --loose --skipApiVersionCheck --disableProductStyleUrl --disableTelemetry ``` Above command will try to start Azurite image with configurations: @@ -269,6 +270,8 @@ Above command will try to start Azurite image with configurations: `--disableProductStyleUrl` force parsing storage account name from request URI path, instead of from request URI host. +`--azurite.disableTelemetry` disable telemetry data collection of this Azurite execution. By default, Azurite will collect telemetry data to help improve the product. + > If you use customized azurite parameters for docker image, `--blobHost 0.0.0.0`, `--queueHost 0.0.0.0` are required parameters. > In above sample, you need to use **double first forward slash** for location and debug path parameters to avoid a [known issue](https://stackoverflow.com/questions/48427366/docker-build-command-add-c-program-files-git-to-the-path-passed-as-build-argu) for Git on Windows. @@ -442,6 +445,14 @@ Optional. When using FQDN instead of IP in request URI host, by default Azurite --disableProductStyleUrl ``` +### Disable Telemetry Collection + +Optional. By default, Azurite will collect telemetry data to help improve the product. Disable telemetry data collection of this Azurite execution by: + +```cmd +--disableTelemetry +``` + ### Use in-memory storage Optional. Disable persisting any data to disk and only store data in-memory. If the Azurite process is terminated, all @@ -989,7 +1000,7 @@ Detailed support matrix: - OAuth authentication - Shared Access Signature Account Level - Shared Access Signature Service Level (Not support response header override in service SAS) - - Container Public Access + - Container Public Access - Blob Tags (preview) - Supported REST APIs - List Containers diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 76b85b193..40e88d489 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -11,6 +11,9 @@ import * as fs from "fs"; import uuid from "uuid"; import { join } from "path"; import logger from "./Logger"; +import { DEFAULT_BLOB_KEEP_ALIVE_TIMEOUT, DEFAULT_BLOB_LISTENING_PORT, DEFAULT_BLOB_SERVER_HOST_NAME } from "../blob/utils/constants"; +import { DEFAULT_QUEUE_LISTENING_PORT } from "../queue/utils/constants"; +import { DEFAULT_TABLE_LISTENING_PORT } from "../table/utils/constants"; export class AzuriteTelemetryClient { private static eventClient : TelemetryClient | undefined; @@ -34,10 +37,10 @@ export class AzuriteTelemetryClient { public static isVSC = false; // Debug options - private static isDebug = false; + private static isDebug = true; // change to false in production private static requestCollectPercentage = AzuriteTelemetryClient.isDebug ? 100 : 1; private static enableAppInsightLog = AzuriteTelemetryClient.isDebug? true : false; - private static cloudRole = AzuriteTelemetryClient.isDebug ? "AzuriteTest" : "Azurite"; + private static cloudRole = AzuriteTelemetryClient.isDebug ? "AzuriteTest" : "Azurite_SchemaV1.0"; // 0 means send as soon as it's collected, use it in both debug and release mode, since set any other value will make Azurite exist slower private static requestMaxBatchSize = AzuriteTelemetryClient.isDebug ? 0 : 0; @@ -147,7 +150,7 @@ export class AzuriteTelemetryClient { authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, - //totalReqs:AzuriteTelemetryClient._totalBlobRequestCount, + totalReqs:AzuriteTelemetryClient._totalBlobRequestCount, }; if (context.request?.getHeader("content-length") !== undefined) { @@ -198,12 +201,13 @@ export class AzuriteTelemetryClient { authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, - //totalReqs:AzuriteTelemetryClient._totalQueueRequestCount, + totalReqs:AzuriteTelemetryClient._totalQueueRequestCount, }; if (context.request?.getHeader("content-length") !== undefined) { requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); } + // Responds "content-length" Not work, as responds normally don't have "content-length" header even has body. AzuriteTelemetryClient.requestClient.trackRequest( { name:"Q_" + QueueOperation[context.operation??0], @@ -242,7 +246,7 @@ export class AzuriteTelemetryClient { authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, - // totalReqs:AzuriteTelemetryClient._totalTableRequestCount, + totalReqs:AzuriteTelemetryClient._totalTableRequestCount, }; if (context.request?.getHeader("content-length") !== undefined) { @@ -428,11 +432,11 @@ export class AzuriteTelemetryClient { longParameters.forEach((flag) => { let value = workspaceConfiguration.get(flag); if (value !== undefined && value !== "" && value !== false && value !== null - && !(flag.endsWith("Host") && value === "localhost") - && !(flag.endsWith("KeepAliveTimeout") && value === 5) - && !(flag == "blobPort" && value === 10000) - && !(flag == "queuePort" && value === 10001) - && !(flag == "tablePort" && value === 10002)) + && !(flag.endsWith("Host") && value === DEFAULT_BLOB_SERVER_HOST_NAME) + && !(flag.endsWith("KeepAliveTimeout") && value === DEFAULT_BLOB_KEEP_ALIVE_TIMEOUT) + && !(flag == "blobPort" && value === DEFAULT_BLOB_LISTENING_PORT) + && !(flag == "queuePort" && value === DEFAULT_QUEUE_LISTENING_PORT) + && !(flag == "tablePort" && value === DEFAULT_TABLE_LISTENING_PORT)) { parameters += flag + ","; } From 00520be889e5687474b41c79047cba4ee6cf6d5f Mon Sep 17 00:00:00 2001 From: blueww Date: Tue, 10 Dec 2024 16:02:21 +0800 Subject: [PATCH 12/14] modify per code review feedback 1 --- .../generated/middleware/end.middleware.ts | 2 +- .../generated/middleware/error.middleware.ts | 2 + src/common/Telemetry.ts | 283 ++++++++++-------- .../generated/middleware/end.middleware.ts | 2 +- .../generated/middleware/error.middleware.ts | 2 + .../generated/middleware/end.middleware.ts | 2 +- .../generated/middleware/error.middleware.ts | 2 + tests/BlobTestServerFactory.ts | 2 - tests/blob/blobCorsRequest.test.ts | 1 + tests/queue/oauth.test.ts | 1 + tests/queue/utils/QueueTestServerFactory.ts | 2 - .../table.entity.azure.data-tables.test.ts | 1 + tests/table/utils/TableTestServerFactory.ts | 2 - 13 files changed, 164 insertions(+), 140 deletions(-) diff --git a/src/blob/generated/middleware/end.middleware.ts b/src/blob/generated/middleware/end.middleware.ts index 710e8deb8..40c1744cc 100644 --- a/src/blob/generated/middleware/end.middleware.ts +++ b/src/blob/generated/middleware/end.middleware.ts @@ -28,7 +28,7 @@ export default function endMiddleware( )}`, context.contextId ); - AzuriteTelemetryClient.TraceBlobRequest(context); + AzuriteTelemetryClient.TraceRequest(context); res.getBodyStream().end(); } diff --git a/src/blob/generated/middleware/error.middleware.ts b/src/blob/generated/middleware/error.middleware.ts index 080dd7250..d8676275f 100644 --- a/src/blob/generated/middleware/error.middleware.ts +++ b/src/blob/generated/middleware/error.middleware.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from '../../../common/Telemetry'; import Context from '../Context'; import MiddlewareError from '../errors/MiddlewareError'; import IRequest from '../IRequest'; @@ -129,6 +130,7 @@ export default function errorMiddleware( context.contextId ); } + AzuriteTelemetryClient.TraceRequest(context); next(); } diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 40e88d489..efcd151b1 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -37,10 +37,10 @@ export class AzuriteTelemetryClient { public static isVSC = false; // Debug options - private static isDebug = true; // change to false in production - private static requestCollectPercentage = AzuriteTelemetryClient.isDebug ? 100 : 1; + private static isDebug = false; // false in production, true in development + private static requestCollectPercentage = AzuriteTelemetryClient.isDebug ? 100 : 100; private static enableAppInsightLog = AzuriteTelemetryClient.isDebug? true : false; - private static cloudRole = AzuriteTelemetryClient.isDebug ? "AzuriteTest" : "Azurite_SchemaV1.0"; + private static cloudRole = AzuriteTelemetryClient.isDebug ? "AzuriteTest" : "Azurite_V1.0"; // 0 means send as soon as it's collected, use it in both debug and release mode, since set any other value will make Azurite exist slower private static requestMaxBatchSize = AzuriteTelemetryClient.isDebug ? 0 : 0; @@ -56,6 +56,7 @@ export class AzuriteTelemetryClient { AzuriteTelemetryClient.isVSC = isVSC; AzuriteTelemetryClient.location = location; AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(typeof env?.inMemoryPersistence === "function" && env?.inMemoryPersistence()); + logger.info(`InstaceID ${AzuriteTelemetryClient.instanceID}, SessionID ${AzuriteTelemetryClient.sessionID}.`); AzuriteTelemetryClient.enableTelemetry = enableTelemetry; AzuriteTelemetryClient.env = env; @@ -117,15 +118,13 @@ export class AzuriteTelemetryClient { // Remove some default telemetry item in the telemetry envelope let telemetryClient = new AzuriteTelemetryClient.appInsights.TelemetryClient(ConnectionString); telemetryClient.addTelemetryProcessor(AzuriteTelemetryClient.removeRoleInstance); - //appInsights.start(); - - + if (telemetryClient !== undefined) { - telemetryClient.context.tags[telemetryClient.context.keys.cloudRole] = "AzuriteTest"; + telemetryClient.context.tags[telemetryClient.context.keys.cloudRole] = AzuriteTelemetryClient.cloudRole; } - telemetryClient.config.samplingPercentage = samplingPercentage??100; + telemetryClient.config.samplingPercentage = samplingPercentage??1; // Enable AppInsight log, should enable in develoipment only if (AzuriteTelemetryClient.enableAppInsightLog) @@ -140,18 +139,42 @@ export class AzuriteTelemetryClient { return telemetryClient; } - public static TraceBlobRequest(context: BlobContext) { + public static TraceRequest(context: any) { + let serviceType = ""; + let totalReqs = 0; + let reqName = ""; try{ if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) { - AzuriteTelemetryClient._totalBlobRequestCount++; + if (context instanceof BlobContext) + { + serviceType = "Blob"; + AzuriteTelemetryClient._totalBlobRequestCount++; + totalReqs = AzuriteTelemetryClient._totalBlobRequestCount; + reqName = "B_" + BlobOperation[context.operation??0]; + } + else if (context instanceof QueueContext) + { + serviceType = "Queue"; + AzuriteTelemetryClient._totalQueueRequestCount++; + totalReqs = AzuriteTelemetryClient._totalQueueRequestCount; + reqName = "Q_" + QueueOperation[context.operation??0]; + } + else if (context instanceof TableContext) + { + serviceType = "Table"; + AzuriteTelemetryClient._totalTableRequestCount++; + totalReqs = AzuriteTelemetryClient._totalTableRequestCount; + reqName = "T_" + TableOperation[context.operation??0]; + } let requestProperties: { [key: string]: any } = { apiVersion: "v"+context.request?.getHeader("x-ms-version"), authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, - totalReqs:AzuriteTelemetryClient._totalBlobRequestCount, + ReqNo:totalReqs, }; + // Can't collect egress not since responds normally don't have "content-length" header even has body. So only collect ingress now. if (context.request?.getHeader("content-length") !== undefined) { const contentLength = context.request?.getHeader("content-length"); @@ -160,16 +183,14 @@ export class AzuriteTelemetryClient { this._totalIngressSize += parseInt(contentLength); } } - // Responds "content-length" Not work, as responds normally don't have "content-length" header even has body. AzuriteTelemetryClient.requestClient.trackRequest( { - name:"B_" + BlobOperation[context.operation??0], + name:reqName, url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, resultCode:context.response?.getStatusCode()??0, - success:context.response?.getStatusCode()?.toString().startsWith("2")??false, - // Question: should we move InstanceID and SessionID to telemetry properties id & source, and move requestID and useragent to properties (customDimensions)? + success:(context.response?.getStatusCode() ?? 500) <= 399, id: context.contextId, // Request ID source: context.request?.getHeader("user-agent"), // User Agent properties: requestProperties, @@ -183,102 +204,102 @@ export class AzuriteTelemetryClient { } }); } - logger.verbose('Send blob telemetry: ' + BlobOperation[context.operation??0], context.contextId); - } - catch (e) - { - logger.warn('Fail to telemetry a blob request, error: ' + e.message); - } - } - - public static TraceQueueRequest(context: QueueContext) { - try{ - if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) - { - AzuriteTelemetryClient._totalQueueRequestCount++; - let requestProperties: { [key: string]: any } = { - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, - totalReqs:AzuriteTelemetryClient._totalQueueRequestCount, - }; - if (context.request?.getHeader("content-length") !== undefined) - { - requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); - } - // Responds "content-length" Not work, as responds normally don't have "content-length" header even has body. - AzuriteTelemetryClient.requestClient.trackRequest( - { - name:"Q_" + QueueOperation[context.operation??0], - url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", - duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, - resultCode:context.response?.getStatusCode()??0, - success:context.response?.getStatusCode()?.toString().startsWith("2")??false, - id: context.contextID, - source: context.request?.getHeader("user-agent"), - properties: requestProperties, - contextObjects: - { - operationId: "", - operationParentId: "", - operationName: "test", - operation_Name: "test", - appName: "" - } - }); - } - logger.verbose('Send queue telemetry: ' + QueueOperation[context.operation??0], context.contextID); + logger.verbose(`Send ${serviceType} telemetry: ` + reqName, context.contextId === undefined ? context.contextID : context.contextId); } catch (e) { - logger.warn('Fail to telemetry a queue request, error: ' + e.message); + logger.warn(`Fail to telemetry a ${serviceType} request, error: ` + e.message); } } - public static TraceTableRequest(context: TableContext) { - try{ - if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) - { - AzuriteTelemetryClient._totalTableRequestCount++; - let requestProperties: { [key: string]: any } = { - apiVersion: "v"+context.request?.getHeader("x-ms-version"), - authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", - instanceID: AzuriteTelemetryClient.instanceID, - sessionID: AzuriteTelemetryClient.sessionID, - totalReqs:AzuriteTelemetryClient._totalTableRequestCount, - }; - if (context.request?.getHeader("content-length") !== undefined) - { - requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); - } - AzuriteTelemetryClient.requestClient.trackRequest( - { - name:"T_" + TableOperation[context.operation??0], - url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", - duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, - resultCode:context.response?.getStatusCode()??0, - success:context.response?.getStatusCode()?.toString().startsWith("2")??false, - id: context.contextID, - source: context.request?.getHeader("user-agent"), - properties: requestProperties, - contextObjects: - { - operationId: "", - operationParentId: "", - operationName: "test", - operation_Name: "test", - appName: "" - } - }); - } - logger.verbose('Send table telemetry: ' + TableOperation[context.operation??0], context.contextID); - } - catch (e) - { - logger.warn('Fail to telemetry a table request, error: ' + e.message); - } - } + // public static TraceQueueRequest(context: QueueContext) { + // try{ + // if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) + // { + // AzuriteTelemetryClient._totalQueueRequestCount++; + // let requestProperties: { [key: string]: any } = { + // apiVersion: "v"+context.request?.getHeader("x-ms-version"), + // authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + // instanceID: AzuriteTelemetryClient.instanceID, + // sessionID: AzuriteTelemetryClient.sessionID, + // totalReqs:AzuriteTelemetryClient._totalQueueRequestCount, + // }; + // if (context.request?.getHeader("content-length") !== undefined) + // { + // requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); + // } + // // Responds "content-length" Not work, as responds normally don't have "content-length" header even has body. + // AzuriteTelemetryClient.requestClient.trackRequest( + // { + // name:"Q_" + QueueOperation[context.operation??0], + // url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", + // duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + // resultCode:context.response?.getStatusCode()??0, + // success:context.response?.getStatusCode()?.toString().startsWith("2")??false, + // id: context.contextID, + // source: context.request?.getHeader("user-agent"), + // properties: requestProperties, + // contextObjects: + // { + // operationId: "", + // operationParentId: "", + // operationName: "test", + // operation_Name: "test", + // appName: "" + // } + // }); + // } + // logger.verbose('Send queue telemetry: ' + QueueOperation[context.operation??0], context.contextID); + // } + // catch (e) + // { + // logger.warn('Fail to telemetry a queue request, error: ' + e.message); + // } + // } + + // public static TraceTableRequest(context: TableContext) { + // try{ + // if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) + // { + // AzuriteTelemetryClient._totalTableRequestCount++; + // let requestProperties: { [key: string]: any } = { + // apiVersion: "v"+context.request?.getHeader("x-ms-version"), + // authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", + // instanceID: AzuriteTelemetryClient.instanceID, + // sessionID: AzuriteTelemetryClient.sessionID, + // totalReqs:AzuriteTelemetryClient._totalTableRequestCount, + // }; + // if (context.request?.getHeader("content-length") !== undefined) + // { + // requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); + // } + // AzuriteTelemetryClient.requestClient.trackRequest( + // { + // name:"T_" + TableOperation[context.operation??0], + // url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", + // duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + // resultCode:context.response?.getStatusCode()??0, + // success:context.response?.getStatusCode()?.toString().startsWith("2")??false, + // id: context.contextID, + // source: context.request?.getHeader("user-agent"), + // properties: requestProperties, + // contextObjects: + // { + // operationId: "", + // operationParentId: "", + // operationName: "test", + // operation_Name: "test", + // appName: "" + // } + // }); + // } + // logger.verbose('Send table telemetry: ' + TableOperation[context.operation??0], context.contextID); + // } + // catch (e) + // { + // logger.warn('Fail to telemetry a table request, error: ' + e.message); + // } + // } public static async TraceStartEvent(serviceType: string = "") { try{ @@ -337,15 +358,6 @@ export class AzuriteTelemetryClient { { return endpoint; } - - // let request = context.request; - // let requestUri = request.getUrl(); - // let sig = request.getQuery("sig"); - // if (sig!=undefined) - // { - // requestUri = requestUri.replace(encodeURIComponent(sig), "[hidden]"); - // } - // return `${request.getEndpoint()}${requestUri}`; } @@ -362,34 +374,43 @@ export class AzuriteTelemetryClient { } try { if(!fs.existsSync(configFilePath)) - { - instaceID = uuid(); - fs.writeFile(configFilePath, `{"instaceID":"${instaceID}"}`, (err) => { - logger.warn('Fail to save instaceID, error: ' + err?.message); - }); - } - else{ - + { + instaceID = uuid(); + fs.writeFileSync(configFilePath, `{"instaceID":"${instaceID}"}`); + } + else{ + try{ let data = fs.readFileSync(configFilePath, 'utf8'); instaceID = JSON.parse(data.toString()).instaceID; - if(instaceID === "") - { - instaceID = uuid(); - fs.writeFile(configFilePath, instaceID, (err) => { - logger.warn('Fail to save instaceID, error: ' + err?.message); - }); - } } + catch(e){ + logger.warn(`Failed to read instaceID from file ${configFilePath} and will regenerate instanceID, error: ` + e.message); + } + if(instaceID === undefined || instaceID === "") + { + instaceID = uuid(); + fs.writeFileSync(configFilePath, `{"instaceID":"${instaceID}"}`); + } + } return instaceID; } catch (e) { - logger.warn('Fail to generate and save instaceID will use empty instaceID, error: ' + e.message); + logger.warn(`Failed to read or generate/save instaceID, will use instaceID "${instaceID}", error: ` + e.message); return instaceID; } } private static GetRequestAuthentication(authorizationHeader: string|undefined, sigQuery: string|undefined): string { + let auth = authorizationHeader?.split(" ")[0]; - if (auth === undefined) + if (auth !== undefined && auth !== "") + { + if (sigQuery !== undefined) + { + auth = auth + ",Sas"; + } + //else auth in head is already retrived, no need to add more + } + else // no auth header { if (sigQuery !== undefined) { diff --git a/src/queue/generated/middleware/end.middleware.ts b/src/queue/generated/middleware/end.middleware.ts index 402ace575..13dcb7756 100644 --- a/src/queue/generated/middleware/end.middleware.ts +++ b/src/queue/generated/middleware/end.middleware.ts @@ -28,7 +28,7 @@ export default function endMiddleware( )}`, context.contextID ); - AzuriteTelemetryClient.TraceQueueRequest(context); + AzuriteTelemetryClient.TraceRequest(context); res.getBodyStream().end(); } diff --git a/src/queue/generated/middleware/error.middleware.ts b/src/queue/generated/middleware/error.middleware.ts index e923e0c65..cb8f64173 100644 --- a/src/queue/generated/middleware/error.middleware.ts +++ b/src/queue/generated/middleware/error.middleware.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import MiddlewareError from "../errors/MiddlewareError"; import IRequest from "../IRequest"; @@ -129,6 +130,7 @@ export default function errorMiddleware( context.contextID ); } + AzuriteTelemetryClient.TraceRequest(context) ; next(); } diff --git a/src/table/generated/middleware/end.middleware.ts b/src/table/generated/middleware/end.middleware.ts index d2ec9047c..f7ec7addc 100644 --- a/src/table/generated/middleware/end.middleware.ts +++ b/src/table/generated/middleware/end.middleware.ts @@ -28,7 +28,7 @@ export default function endMiddleware( )}`, context.contextID ); - AzuriteTelemetryClient.TraceTableRequest(context) ; + AzuriteTelemetryClient.TraceRequest(context) ; res.getBodyStream().end(); } diff --git a/src/table/generated/middleware/error.middleware.ts b/src/table/generated/middleware/error.middleware.ts index 696788b04..83087532b 100644 --- a/src/table/generated/middleware/error.middleware.ts +++ b/src/table/generated/middleware/error.middleware.ts @@ -1,3 +1,4 @@ +import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import MiddlewareError from "../errors/MiddlewareError"; import IRequest from "../IRequest"; @@ -126,6 +127,7 @@ export default function errorMiddleware( context.contextID ); } + AzuriteTelemetryClient.TraceRequest(context) ; next(); } diff --git a/tests/BlobTestServerFactory.ts b/tests/BlobTestServerFactory.ts index 9eaa63925..d8c4311cf 100644 --- a/tests/BlobTestServerFactory.ts +++ b/tests/BlobTestServerFactory.ts @@ -2,7 +2,6 @@ import BlobConfiguration from "../src/blob/BlobConfiguration"; import BlobServer from "../src/blob/BlobServer"; import SqlBlobConfiguration from "../src/blob/SqlBlobConfiguration"; import SqlBlobServer from "../src/blob/SqlBlobServer"; -import { AzuriteTelemetryClient } from "../src/common/Telemetry"; import { StoreDestinationArray } from "../src/common/persistence/IExtentStore"; import { DEFAULT_SQL_OPTIONS } from "../src/common/utils/constants"; import { DEFAULT_BLOB_KEEP_ALIVE_TIMEOUT } from "../src/blob/utils/constants"; @@ -79,7 +78,6 @@ export default class BlobTestServerFactory { undefined, inMemoryPersistence ); - AzuriteTelemetryClient.init("", true, undefined); return new BlobServer(config); } } diff --git a/tests/blob/blobCorsRequest.test.ts b/tests/blob/blobCorsRequest.test.ts index 143d97857..edfddd96e 100644 --- a/tests/blob/blobCorsRequest.test.ts +++ b/tests/blob/blobCorsRequest.test.ts @@ -42,6 +42,7 @@ describe("Blob Cors requests test", () => { before(async () => { await server.start(); + AzuriteTelemetryClient.init("", true, undefined); await AzuriteTelemetryClient.TraceStartEvent("Blob Test"); }); diff --git a/tests/queue/oauth.test.ts b/tests/queue/oauth.test.ts index 176391cab..6c34841df 100644 --- a/tests/queue/oauth.test.ts +++ b/tests/queue/oauth.test.ts @@ -42,6 +42,7 @@ describe("Queue OAuth Basic", () => { oauth: "basic" }) await server.start(); + AzuriteTelemetryClient.init("", true, undefined); await AzuriteTelemetryClient.TraceStartEvent("Queue Test"); }); diff --git a/tests/queue/utils/QueueTestServerFactory.ts b/tests/queue/utils/QueueTestServerFactory.ts index 7d541a8f3..19f7078ba 100644 --- a/tests/queue/utils/QueueTestServerFactory.ts +++ b/tests/queue/utils/QueueTestServerFactory.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from "../../../src/common/Telemetry" import { StoreDestinationArray } from "../../../src/common/persistence/IExtentStore" import QueueConfiguration from "../../../src/queue/QueueConfiguration" import QueueServer from "../../../src/queue/QueueServer" @@ -46,7 +45,6 @@ export default class QueueTestServerFactory { undefined, inMemoryPersistence ); - AzuriteTelemetryClient.init("", true, undefined); return new QueueServer(config); } } diff --git a/tests/table/apis/table.entity.azure.data-tables.test.ts b/tests/table/apis/table.entity.azure.data-tables.test.ts index a4d8ef0b0..552b32b40 100644 --- a/tests/table/apis/table.entity.azure.data-tables.test.ts +++ b/tests/table/apis/table.entity.azure.data-tables.test.ts @@ -39,6 +39,7 @@ describe("table Entity APIs test - using Azure/data-tables", () => { before(async () => { server = createTableServerForTestHttps(); await server.start(); + AzuriteTelemetryClient.init("", true, undefined); await AzuriteTelemetryClient.TraceStartEvent("Table Test"); }); diff --git a/tests/table/utils/TableTestServerFactory.ts b/tests/table/utils/TableTestServerFactory.ts index d4c05239a..026ebddd6 100644 --- a/tests/table/utils/TableTestServerFactory.ts +++ b/tests/table/utils/TableTestServerFactory.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from "../../../src/common/Telemetry"; import TableConfiguration from "../../../src/table/TableConfiguration"; import TableServer from "../../../src/table/TableServer"; import { DEFAULT_TABLE_KEEP_ALIVE_TIMEOUT } from "../../../src/table/utils/constants"; @@ -45,7 +44,6 @@ export default class TableTestServerFactory { undefined, inMemoryPersistence ); - AzuriteTelemetryClient.init("", true, undefined); return new TableServer(config); } } From f7b2abacbafb1a92d32dcf84b593c8b5af7aeae6 Mon Sep 17 00:00:00 2001 From: blueww Date: Wed, 11 Dec 2024 15:06:21 +0800 Subject: [PATCH 13/14] Add telemetry middleware --- src/blob/BlobRequestListenerFactory.ts | 9 ++++ src/blob/BlobServerFactory.ts | 2 - .../generated/middleware/end.middleware.ts | 2 - .../generated/middleware/error.middleware.ts | 2 - src/blob/middlewares/telemetry.middleware.ts | 51 +++++++++++++++++++ src/common/AccountDataStore.ts | 2 - src/common/Telemetry.ts | 41 ++++++++++----- src/queue/QueueRequestListenerFactory.ts | 8 +++ .../generated/middleware/end.middleware.ts | 2 - .../generated/middleware/error.middleware.ts | 2 - src/queue/middlewares/telemetry.middleware.ts | 51 +++++++++++++++++++ src/table/TableRequestListenerFactory.ts | 8 +++ .../generated/middleware/end.middleware.ts | 2 - .../generated/middleware/error.middleware.ts | 2 - src/table/middleware/telemetry.middleware.ts | 51 +++++++++++++++++++ 15 files changed, 205 insertions(+), 30 deletions(-) create mode 100644 src/blob/middlewares/telemetry.middleware.ts create mode 100644 src/queue/middlewares/telemetry.middleware.ts create mode 100644 src/table/middleware/telemetry.middleware.ts diff --git a/src/blob/BlobRequestListenerFactory.ts b/src/blob/BlobRequestListenerFactory.ts index c01f248b2..498bf4d6d 100644 --- a/src/blob/BlobRequestListenerFactory.ts +++ b/src/blob/BlobRequestListenerFactory.ts @@ -33,6 +33,7 @@ import morgan = require("morgan"); import { OAuthLevel } from "../common/models"; import IAuthenticator from "./authentication/IAuthenticator"; import createStorageBlobContextMiddleware from "./middlewares/blobStorageContext.middleware"; +import TelemetryMiddlewareFactory from "./middlewares/telemetry.middleware"; /** * Default RequestListenerFactory based on express framework. @@ -121,6 +122,10 @@ export default class BlobRequestListenerFactory // CORS request handling, preflight request and the corresponding actual request const preflightMiddlewareFactory = new PreflightMiddlewareFactory(logger); + // Send Telemetry data + const telemetryMiddlewareFactory = new TelemetryMiddlewareFactory( + DEFAULT_CONTEXT_PATH); + // Strict mode unsupported features blocker const strictModelMiddlewareFactory = new StrictModelMiddlewareFactory( logger, @@ -207,9 +212,13 @@ export default class BlobRequestListenerFactory ) ); + // Generated, will return MiddlewareError and Errors thrown in previous middleware/handlers to HTTP response app.use(middlewareFactory.createErrorMiddleware()); + // Send out telemetry data + app.use(telemetryMiddlewareFactory.createTelemetryMiddleware()); + // Generated, will end and return HTTP response immediately app.use(middlewareFactory.createEndMiddleware()); diff --git a/src/blob/BlobServerFactory.ts b/src/blob/BlobServerFactory.ts index 8590347f2..158456476 100644 --- a/src/blob/BlobServerFactory.ts +++ b/src/blob/BlobServerFactory.ts @@ -13,7 +13,6 @@ import { DEFAULT_BLOB_LOKI_DB_PATH, DEFAULT_BLOB_PERSISTENCE_ARRAY } from "./utils/constants"; -import { AzuriteTelemetryClient } from "../common/Telemetry"; export class BlobServerFactory { public async createServer( @@ -43,7 +42,6 @@ export class BlobServerFactory { const isSQL = databaseConnectionString !== undefined; if (isSQL) { - AzuriteTelemetryClient.envDBIsSet = true; if (env.inMemoryPersistence()) { throw new Error(`The --inMemoryPersistence option is not supported when using SQL-based metadata storage.`) } diff --git a/src/blob/generated/middleware/end.middleware.ts b/src/blob/generated/middleware/end.middleware.ts index 40c1744cc..91692225c 100644 --- a/src/blob/generated/middleware/end.middleware.ts +++ b/src/blob/generated/middleware/end.middleware.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from '../../../common/Telemetry'; import Context from '../Context'; import IResponse from '../IResponse'; import ILogger from '../utils/ILogger'; @@ -28,7 +27,6 @@ export default function endMiddleware( )}`, context.contextId ); - AzuriteTelemetryClient.TraceRequest(context); res.getBodyStream().end(); } diff --git a/src/blob/generated/middleware/error.middleware.ts b/src/blob/generated/middleware/error.middleware.ts index d8676275f..080dd7250 100644 --- a/src/blob/generated/middleware/error.middleware.ts +++ b/src/blob/generated/middleware/error.middleware.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from '../../../common/Telemetry'; import Context from '../Context'; import MiddlewareError from '../errors/MiddlewareError'; import IRequest from '../IRequest'; @@ -130,7 +129,6 @@ export default function errorMiddleware( context.contextId ); } - AzuriteTelemetryClient.TraceRequest(context); next(); } diff --git a/src/blob/middlewares/telemetry.middleware.ts b/src/blob/middlewares/telemetry.middleware.ts new file mode 100644 index 000000000..341d921bb --- /dev/null +++ b/src/blob/middlewares/telemetry.middleware.ts @@ -0,0 +1,51 @@ +import { AzuriteTelemetryClient } from '../../common/Telemetry'; +import Context from '../generated/Context'; +import { NextFunction } from '../generated/MiddlewareFactory'; +import { + Request, + RequestHandler, + Response +} from "express"; +import ExpressRequestAdapter from '../generated/ExpressRequestAdapter'; +import ExpressResponseAdapter from '../generated/ExpressResponseAdapter'; + +/** + * End middleware is used to send out final HTTP response. + * + * @export + * @param {Context} context + * @param {Request} req An express compatible Request object + * @param {Response} res An express compatible Response object + * @param {ILogger} logger A valid logger + */ +function telemetryMiddleware( + context: Context, + next: NextFunction, +): void { + AzuriteTelemetryClient.TraceRequest(context); + + next(); +} + + +export default class TelemetryMiddlewareFactory { + constructor( + private readonly contextPath: string = "default_context") {} + + /** + * TelemetryMiddleware is used to send telemetry for requests. + * + * @returns {RequestHandler} + * @memberof MiddlewareFactory + */ + public createTelemetryMiddleware(): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + telemetryMiddleware( + new Context(res.locals, this.contextPath, request, response), + next + ); + }; + } +} diff --git a/src/common/AccountDataStore.ts b/src/common/AccountDataStore.ts index a1fd501b6..65a88eec9 100644 --- a/src/common/AccountDataStore.ts +++ b/src/common/AccountDataStore.ts @@ -4,7 +4,6 @@ import { } from "../common/utils/constants"; import ILogger from "../queue/generated/utils/ILogger"; import IAccountDataStore, { IAccountProperties } from "./IAccountDataStore"; -import { AzuriteTelemetryClient } from "./Telemetry"; import { AZURITE_ACCOUNTS_ENV, DEFAULT_ACCOUNTS_REFRESH_INTERVAL @@ -81,7 +80,6 @@ export default class AccountDataStore implements IAccountDataStore { if (env) { try { this.accounts = this.parserAccountsEnvironmentString(env); - AzuriteTelemetryClient.envAccountIsSet = true; } catch (err) { this.logger.error( `AccountDataStore:init() Fallback to default emulator account ${EMULATOR_ACCOUNT_NAME}. Refresh accounts from environment variable ${AZURITE_ACCOUNTS_ENV} failed. ${JSON.stringify( diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index efcd151b1..5b8ec0320 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -23,7 +23,7 @@ export class AzuriteTelemetryClient { private static location: string; private static configFileName = "AzuriteConfig"; private static _totalIngressSize: number = 0; - //private static _totalEgressSize: number = 0; + private static _totalEgressSize: number = 0; private static _totalBlobRequestCount: number = 0; private static _totalQueueRequestCount: number = 0; private static _totalTableRequestCount: number = 0; @@ -32,8 +32,6 @@ export class AzuriteTelemetryClient { private static instanceID = ""; private static initialized = false; private static env: any = undefined; - public static envAccountIsSet = false; - public static envDBIsSet = false; public static isVSC = false; // Debug options @@ -174,15 +172,29 @@ export class AzuriteTelemetryClient { sessionID: AzuriteTelemetryClient.sessionID, ReqNo:totalReqs, }; - // Can't collect egress not since responds normally don't have "content-length" header even has body. So only collect ingress now. - if (context.request?.getHeader("content-length") !== undefined) - { - const contentLength = context.request?.getHeader("content-length"); - if (contentLength && parseInt(contentLength)) { - requestProperties["requestContentSize"] = contentLength; - this._totalIngressSize += parseInt(contentLength); + + const ingress = context.request?.getHeader("content-length"); + if (ingress !== undefined) + { + if (ingress && parseInt(ingress)) { + requestProperties["ingress"] = ingress; + this._totalIngressSize += parseInt(ingress); + } + } + + // When body is xml or json, "content-length" header won't return even has body, so currently can't be caculated into egress in telemetry. + // Head request don't has body but can has "content-length" header, like in GetBlobProperties "content-length" header means the blob length but not body length + if (context.request?.getMethod() !== "HEAD") + { + const egress = context.response?.getHeader("content-length"); + if (egress !== undefined) + { + if (egress && parseInt(egress)) { + requestProperties["egress"] = egress; + this._totalEgressSize += parseInt(egress); + } + } } - } AzuriteTelemetryClient.requestClient.trackRequest( { @@ -334,7 +346,8 @@ export class AzuriteTelemetryClient { blobRequest: AzuriteTelemetryClient._totalBlobRequestCount, queueRequest: AzuriteTelemetryClient._totalQueueRequestCount, tableRequest: AzuriteTelemetryClient._totalTableRequestCount, - totalIngress: this._totalIngressSize, + totalIngress: AzuriteTelemetryClient._totalIngressSize, + totalEgress: AzuriteTelemetryClient._totalEgressSize, } }); } @@ -426,11 +439,11 @@ export class AzuriteTelemetryClient { private static async GetAllParameterString(): Promise { let parameters = ""; - if (this.envAccountIsSet) + if (process.env.AZURITE_ACCOUNTS) { parameters += "AZURITE_ACCOUNTS,"; } - if (this.envDBIsSet) + if (process.env.AZURITE_DB) { parameters += "AZURITE_DB,"; } diff --git a/src/queue/QueueRequestListenerFactory.ts b/src/queue/QueueRequestListenerFactory.ts index e64c0a0d0..a954e8f59 100644 --- a/src/queue/QueueRequestListenerFactory.ts +++ b/src/queue/QueueRequestListenerFactory.ts @@ -25,6 +25,7 @@ import morgan = require("morgan"); import { OAuthLevel } from "../common/models"; import IAuthenticator from "./authentication/IAuthenticator"; import createQueueStorageContextMiddleware from "./middlewares/queueStorageContext.middleware"; +import TelemetryMiddlewareFactory from "./middlewares/telemetry.middleware"; /** * Default RequestListenerFactory based on express framework. @@ -57,6 +58,10 @@ export default class QueueRequestListenerFactory logger, DEFAULT_QUEUE_CONTEXT_PATH ); + + // Send Telemetry data + const telemetryMiddlewareFactory = new TelemetryMiddlewareFactory( + DEFAULT_QUEUE_CONTEXT_PATH); // Create handlers into handler middleware factory const handlers: IHandlers = { @@ -160,6 +165,9 @@ export default class QueueRequestListenerFactory // Generated, will return MiddlewareError and Errors thrown in previous middleware/handlers to HTTP response app.use(middlewareFactory.createErrorMiddleware()); + // Send out telemetry data + app.use(telemetryMiddlewareFactory.createTelemetryMiddleware()); + // Generated, will end and return HTTP response immediately app.use(middlewareFactory.createEndMiddleware()); diff --git a/src/queue/generated/middleware/end.middleware.ts b/src/queue/generated/middleware/end.middleware.ts index 13dcb7756..cc75e6b8b 100644 --- a/src/queue/generated/middleware/end.middleware.ts +++ b/src/queue/generated/middleware/end.middleware.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import IResponse from "../IResponse"; import ILogger from "../utils/ILogger"; @@ -28,7 +27,6 @@ export default function endMiddleware( )}`, context.contextID ); - AzuriteTelemetryClient.TraceRequest(context); res.getBodyStream().end(); } diff --git a/src/queue/generated/middleware/error.middleware.ts b/src/queue/generated/middleware/error.middleware.ts index cb8f64173..e923e0c65 100644 --- a/src/queue/generated/middleware/error.middleware.ts +++ b/src/queue/generated/middleware/error.middleware.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import MiddlewareError from "../errors/MiddlewareError"; import IRequest from "../IRequest"; @@ -130,7 +129,6 @@ export default function errorMiddleware( context.contextID ); } - AzuriteTelemetryClient.TraceRequest(context) ; next(); } diff --git a/src/queue/middlewares/telemetry.middleware.ts b/src/queue/middlewares/telemetry.middleware.ts new file mode 100644 index 000000000..341d921bb --- /dev/null +++ b/src/queue/middlewares/telemetry.middleware.ts @@ -0,0 +1,51 @@ +import { AzuriteTelemetryClient } from '../../common/Telemetry'; +import Context from '../generated/Context'; +import { NextFunction } from '../generated/MiddlewareFactory'; +import { + Request, + RequestHandler, + Response +} from "express"; +import ExpressRequestAdapter from '../generated/ExpressRequestAdapter'; +import ExpressResponseAdapter from '../generated/ExpressResponseAdapter'; + +/** + * End middleware is used to send out final HTTP response. + * + * @export + * @param {Context} context + * @param {Request} req An express compatible Request object + * @param {Response} res An express compatible Response object + * @param {ILogger} logger A valid logger + */ +function telemetryMiddleware( + context: Context, + next: NextFunction, +): void { + AzuriteTelemetryClient.TraceRequest(context); + + next(); +} + + +export default class TelemetryMiddlewareFactory { + constructor( + private readonly contextPath: string = "default_context") {} + + /** + * TelemetryMiddleware is used to send telemetry for requests. + * + * @returns {RequestHandler} + * @memberof MiddlewareFactory + */ + public createTelemetryMiddleware(): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + telemetryMiddleware( + new Context(res.locals, this.contextPath, request, response), + next + ); + }; + } +} diff --git a/src/table/TableRequestListenerFactory.ts b/src/table/TableRequestListenerFactory.ts index fe51218ad..281f33ea5 100644 --- a/src/table/TableRequestListenerFactory.ts +++ b/src/table/TableRequestListenerFactory.ts @@ -26,6 +26,7 @@ import morgan = require("morgan"); import { OAuthLevel } from "../common/models"; import TableSharedKeyAuthenticator from "./authentication/TableSharedKeyAuthenticator"; import TableSharedKeyLiteAuthenticator from "./authentication/TableSharedKeyLiteAuthenticator"; +import TelemetryMiddlewareFactory from "./middleware/telemetry.middleware"; /** * Default RequestListenerFactory based on express framework. * @@ -87,6 +88,10 @@ export default class TableRequestListenerFactory logger, DEFAULT_TABLE_CONTEXT_PATH ); + + // Send Telemetry data + const telemetryMiddlewareFactory = new TelemetryMiddlewareFactory( + DEFAULT_TABLE_CONTEXT_PATH); // Create handlers into handler middleware factory const handlers: IHandlers = { @@ -178,6 +183,9 @@ export default class TableRequestListenerFactory // Generated, will return MiddlewareError and Errors thrown in previous middleware/handlers to HTTP response app.use(middlewareFactory.createErrorMiddleware()); + // Send out telemetry data + app.use(telemetryMiddlewareFactory.createTelemetryMiddleware()); + // Generated, will end and return HTTP response immediately app.use(middlewareFactory.createEndMiddleware()); diff --git a/src/table/generated/middleware/end.middleware.ts b/src/table/generated/middleware/end.middleware.ts index f7ec7addc..cc75e6b8b 100644 --- a/src/table/generated/middleware/end.middleware.ts +++ b/src/table/generated/middleware/end.middleware.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import IResponse from "../IResponse"; import ILogger from "../utils/ILogger"; @@ -28,7 +27,6 @@ export default function endMiddleware( )}`, context.contextID ); - AzuriteTelemetryClient.TraceRequest(context) ; res.getBodyStream().end(); } diff --git a/src/table/generated/middleware/error.middleware.ts b/src/table/generated/middleware/error.middleware.ts index 83087532b..696788b04 100644 --- a/src/table/generated/middleware/error.middleware.ts +++ b/src/table/generated/middleware/error.middleware.ts @@ -1,4 +1,3 @@ -import { AzuriteTelemetryClient } from "../../../common/Telemetry"; import Context from "../Context"; import MiddlewareError from "../errors/MiddlewareError"; import IRequest from "../IRequest"; @@ -127,7 +126,6 @@ export default function errorMiddleware( context.contextID ); } - AzuriteTelemetryClient.TraceRequest(context) ; next(); } diff --git a/src/table/middleware/telemetry.middleware.ts b/src/table/middleware/telemetry.middleware.ts new file mode 100644 index 000000000..341d921bb --- /dev/null +++ b/src/table/middleware/telemetry.middleware.ts @@ -0,0 +1,51 @@ +import { AzuriteTelemetryClient } from '../../common/Telemetry'; +import Context from '../generated/Context'; +import { NextFunction } from '../generated/MiddlewareFactory'; +import { + Request, + RequestHandler, + Response +} from "express"; +import ExpressRequestAdapter from '../generated/ExpressRequestAdapter'; +import ExpressResponseAdapter from '../generated/ExpressResponseAdapter'; + +/** + * End middleware is used to send out final HTTP response. + * + * @export + * @param {Context} context + * @param {Request} req An express compatible Request object + * @param {Response} res An express compatible Response object + * @param {ILogger} logger A valid logger + */ +function telemetryMiddleware( + context: Context, + next: NextFunction, +): void { + AzuriteTelemetryClient.TraceRequest(context); + + next(); +} + + +export default class TelemetryMiddlewareFactory { + constructor( + private readonly contextPath: string = "default_context") {} + + /** + * TelemetryMiddleware is used to send telemetry for requests. + * + * @returns {RequestHandler} + * @memberof MiddlewareFactory + */ + public createTelemetryMiddleware(): RequestHandler { + return (req: Request, res: Response, next: NextFunction) => { + const request = new ExpressRequestAdapter(req); + const response = new ExpressResponseAdapter(res); + telemetryMiddleware( + new Context(res.locals, this.contextPath, request, response), + next + ); + }; + } +} From f4abf9dc3502e681b7869d18a35a03c31f4b97f8 Mon Sep 17 00:00:00 2001 From: blueww Date: Wed, 11 Dec 2024 17:49:02 +0800 Subject: [PATCH 14/14] code cleanup --- .vscode/launch.json | 3 +- README.md | 1 + src/blob/middlewares/telemetry.middleware.ts | 6 +- src/common/Environment.ts | 4 - src/common/Telemetry.ts | 230 ++---------------- src/queue/middlewares/telemetry.middleware.ts | 6 +- src/table/middleware/telemetry.middleware.ts | 6 +- 7 files changed, 35 insertions(+), 221 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 86f2f3d7a..3ba7e4335 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,8 +10,7 @@ "name": "Azurite Service - Loki", "cwd": "${workspaceFolder}", "runtimeArgs": ["-r", "ts-node/register"], - "args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log"],//,"--DisableTelemetry"], - //"args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log","--DisableTelemetry"], + "args": ["${workspaceFolder}/src/azurite.ts", "-d", "debug.log"], "env": { "AZURITE_ACCOUNTS": "" }, diff --git a/README.md b/README.md index 856459329..13ec69946 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ - [OAuth Configuration](#oauth-configuration) - [Skip API Version Check](#skip-api-version-check) - [Disable Product Style Url](#disable-product-style-url) + - [Disable Telemetry Collection](#disable-telemetry-collection) - [Use in-memory storage](#use-in-memory-storage) - [Command Line Options Differences between Azurite V2](#command-line-options-differences-between-azurite-v2) - [Supported Environment Variable Options](#supported-environment-variable-options) diff --git a/src/blob/middlewares/telemetry.middleware.ts b/src/blob/middlewares/telemetry.middleware.ts index 341d921bb..c7fedf76e 100644 --- a/src/blob/middlewares/telemetry.middleware.ts +++ b/src/blob/middlewares/telemetry.middleware.ts @@ -10,13 +10,11 @@ import ExpressRequestAdapter from '../generated/ExpressRequestAdapter'; import ExpressResponseAdapter from '../generated/ExpressResponseAdapter'; /** - * End middleware is used to send out final HTTP response. + * TelemetryMiddleware is used to send telemetry for requests. * * @export * @param {Context} context - * @param {Request} req An express compatible Request object - * @param {Response} res An express compatible Response object - * @param {ILogger} logger A valid logger + * @param {NextFunction} next An express middleware next callback */ function telemetryMiddleware( context: Context, diff --git a/src/common/Environment.ts b/src/common/Environment.ts index be0ced2cf..e42c4fddb 100644 --- a/src/common/Environment.ts +++ b/src/common/Environment.ts @@ -117,10 +117,6 @@ args export default class Environment implements IEnvironment { private flags = args.parse(process.argv); - //public ToString(): string | undefined { - // return Object.getOwnPropertyNames(this.flags).join(", "); - //} - public blobHost(): string | undefined { return this.flags.blobHost; } diff --git a/src/common/Telemetry.ts b/src/common/Telemetry.ts index 5b8ec0320..430146631 100644 --- a/src/common/Telemetry.ts +++ b/src/common/Telemetry.ts @@ -36,7 +36,7 @@ export class AzuriteTelemetryClient { // Debug options private static isDebug = false; // false in production, true in development - private static requestCollectPercentage = AzuriteTelemetryClient.isDebug ? 100 : 100; + private static requestCollectPercentage = AzuriteTelemetryClient.isDebug ? 100 : 1; private static enableAppInsightLog = AzuriteTelemetryClient.isDebug? true : false; private static cloudRole = AzuriteTelemetryClient.isDebug ? "AzuriteTest" : "Azurite_V1.0"; // 0 means send as soon as it's collected, use it in both debug and release mode, since set any other value will make Azurite exist slower @@ -197,26 +197,27 @@ export class AzuriteTelemetryClient { } AzuriteTelemetryClient.requestClient.trackRequest( + { + name:reqName, + url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", + duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, + resultCode:context.response?.getStatusCode()??0, + success:(context.response?.getStatusCode() ?? 500) <= 399, + id: context.contextId, // Request ID + source: context.request?.getHeader("user-agent"), // User Agent + properties: requestProperties, + contextObjects: { - name:reqName, - url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", - duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, - resultCode:context.response?.getStatusCode()??0, - success:(context.response?.getStatusCode() ?? 500) <= 399, - id: context.contextId, // Request ID - source: context.request?.getHeader("user-agent"), // User Agent - properties: requestProperties, - contextObjects: - { - operationId: "", - operationParentId: "", - operationName: "test", - operation_Name: "test", - appName: "" - } - }); + operationId: "", + operationParentId: "", + operationName: "test", + operation_Name: "test", + appName: "" + } + }); + + logger.verbose(`Send ${serviceType} telemetry: ` + reqName, context.contextId === undefined ? context.contextID : context.contextId); } - logger.verbose(`Send ${serviceType} telemetry: ` + reqName, context.contextId === undefined ? context.contextID : context.contextId); } catch (e) { @@ -224,95 +225,6 @@ export class AzuriteTelemetryClient { } } - // public static TraceQueueRequest(context: QueueContext) { - // try{ - // if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) - // { - // AzuriteTelemetryClient._totalQueueRequestCount++; - // let requestProperties: { [key: string]: any } = { - // apiVersion: "v"+context.request?.getHeader("x-ms-version"), - // authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", - // instanceID: AzuriteTelemetryClient.instanceID, - // sessionID: AzuriteTelemetryClient.sessionID, - // totalReqs:AzuriteTelemetryClient._totalQueueRequestCount, - // }; - // if (context.request?.getHeader("content-length") !== undefined) - // { - // requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); - // } - // // Responds "content-length" Not work, as responds normally don't have "content-length" header even has body. - // AzuriteTelemetryClient.requestClient.trackRequest( - // { - // name:"Q_" + QueueOperation[context.operation??0], - // url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", - // duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, - // resultCode:context.response?.getStatusCode()??0, - // success:context.response?.getStatusCode()?.toString().startsWith("2")??false, - // id: context.contextID, - // source: context.request?.getHeader("user-agent"), - // properties: requestProperties, - // contextObjects: - // { - // operationId: "", - // operationParentId: "", - // operationName: "test", - // operation_Name: "test", - // appName: "" - // } - // }); - // } - // logger.verbose('Send queue telemetry: ' + QueueOperation[context.operation??0], context.contextID); - // } - // catch (e) - // { - // logger.warn('Fail to telemetry a queue request, error: ' + e.message); - // } - // } - - // public static TraceTableRequest(context: TableContext) { - // try{ - // if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) - // { - // AzuriteTelemetryClient._totalTableRequestCount++; - // let requestProperties: { [key: string]: any } = { - // apiVersion: "v"+context.request?.getHeader("x-ms-version"), - // authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", - // instanceID: AzuriteTelemetryClient.instanceID, - // sessionID: AzuriteTelemetryClient.sessionID, - // totalReqs:AzuriteTelemetryClient._totalTableRequestCount, - // }; - // if (context.request?.getHeader("content-length") !== undefined) - // { - // requestProperties["requestContentSize"] = context.request?.getHeader("content-length"); - // } - // AzuriteTelemetryClient.requestClient.trackRequest( - // { - // name:"T_" + TableOperation[context.operation??0], - // url:context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", - // duration:context.startTime?((new Date()).getTime() - context.startTime?.getTime()):0, - // resultCode:context.response?.getStatusCode()??0, - // success:context.response?.getStatusCode()?.toString().startsWith("2")??false, - // id: context.contextID, - // source: context.request?.getHeader("user-agent"), - // properties: requestProperties, - // contextObjects: - // { - // operationId: "", - // operationParentId: "", - // operationName: "test", - // operation_Name: "test", - // appName: "" - // } - // }); - // } - // logger.verbose('Send table telemetry: ' + TableOperation[context.operation??0], context.contextID); - // } - // catch (e) - // { - // logger.warn('Fail to telemetry a table request, error: ' + e.message); - // } - // } - public static async TraceStartEvent(serviceType: string = "") { try{ if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) @@ -325,8 +237,8 @@ export class AzuriteTelemetryClient { parameters: await AzuriteTelemetryClient.GetAllParameterString() } }); + logger.verbose('Send start telemetry'); } - logger.verbose('Send start telemetry'); } catch (e) { @@ -350,8 +262,8 @@ export class AzuriteTelemetryClient { totalEgress: AzuriteTelemetryClient._totalEgressSize, } }); + logger.verbose('Send stop telemetry'); } - logger.verbose('Send stop telemetry'); } catch (e) { @@ -447,15 +359,15 @@ export class AzuriteTelemetryClient { { parameters += "AZURITE_DB,"; } - if (AzuriteTelemetryClient.env === undefined) - { - return parameters; - } let longParameters = ["blobHost","queueHost","tableHost","blobPort","queuePort","tablePort","blobKeepAliveTimeout","queueKeepAliveTimeout","tableKeepAliveTimeout","location","cert","key","pwd","oauth","extentMemoryLimit","debug","silent","loose","skipApiVersionCheck","disableProductStyleUrl","inMemoryPersistence","disableTelemetry"]; let shortParameters: { [string: string]: any } = {"d": "debug", "l": "location", "L": "loose", "s": "silent"}; if (AzuriteTelemetryClient.isVSC) // VSC { + if (AzuriteTelemetryClient.env === undefined) + { + return parameters; + } let workspaceConfiguration = AzuriteTelemetryClient.env; if (workspaceConfiguration === undefined) { @@ -497,95 +409,7 @@ export class AzuriteTelemetryClient { } }); } - - // if (typeof AzuriteTelemetryClient.env?.blobHost === "function" && AzuriteTelemetryClient.env?.blobHost() !== undefined && AzuriteTelemetryClient.env?.blobHost() !== "127.0.0.1") - // { - // parameters += "blobHost,"; - // } - // if (typeof AzuriteTelemetryClient.env?.queueHost === "function" && AzuriteTelemetryClient.env?.queueHost() !== undefined && AzuriteTelemetryClient.env?.queueHost() !== "127.0.0.1") - // { - // parameters += "queueHost,"; - // } - // if (typeof AzuriteTelemetryClient.env?.tableHost === "function" && AzuriteTelemetryClient.env?.tableHost() !== undefined && AzuriteTelemetryClient.env?.tableHost() !== "127.0.0.1") - // { - // parameters += "tableHost,"; - // } - // if (typeof AzuriteTelemetryClient.env?.blobPort === "function" && AzuriteTelemetryClient.env?.blobPort() !== undefined && AzuriteTelemetryClient.env?.blobPort() !== 10000) - // { - // parameters += "blobPort,"; - // } - // if (typeof AzuriteTelemetryClient.env?.queuePort === "function" && AzuriteTelemetryClient.env?.queuePort() !== undefined && AzuriteTelemetryClient.env?.queuePort() !== 10001) - // { - // parameters += "queuePort,"; - // } - // if (typeof AzuriteTelemetryClient.env?.tablePort === "function" && AzuriteTelemetryClient.env?.tablePort() !== undefined && AzuriteTelemetryClient.env?.tablePort() !== 10002) - // { - // parameters += "tablePort,"; - // } - // if (typeof AzuriteTelemetryClient.env?.blobKeepAliveTimeout === "function" && AzuriteTelemetryClient.env?.blobKeepAliveTimeout() !== undefined && AzuriteTelemetryClient.env?.blobKeepAliveTimeout() !== 5) - // { - // parameters += "blobKeepAliveTimeout,"; - // } - // if (typeof AzuriteTelemetryClient.env?.queueKeepAliveTimeout === "function" && AzuriteTelemetryClient.env?.queueKeepAliveTimeout() !== undefined && AzuriteTelemetryClient.env?.queueKeepAliveTimeout() !== 5) - // { - // parameters += "queueKeepAliveTimeout,"; - // } - // if (typeof AzuriteTelemetryClient.env?.tableKeepAliveTimeout === "function" && AzuriteTelemetryClient.env?.tableKeepAliveTimeout() !== undefined && AzuriteTelemetryClient.env?.tableKeepAliveTimeout() !== 5) - // { - // parameters += "tableKeepAliveTimeout,"; - // } - // if (typeof AzuriteTelemetryClient.env?.location === "function" && (await AzuriteTelemetryClient.env?.location()) !== undefined) - // { - // parameters += "location,"; - // } - // if (typeof AzuriteTelemetryClient.env?.silent === "function" && AzuriteTelemetryClient.env?.silent()) - // { - // parameters += "silent,"; - // } - // if (typeof AzuriteTelemetryClient.env?.loose === "function" && AzuriteTelemetryClient.env?.loose()) - // { - // parameters += "loose,"; - // } - // if (typeof AzuriteTelemetryClient.env?.skipApiVersionCheck === "function" && AzuriteTelemetryClient.env?.skipApiVersionCheck()) - // { - // parameters += "skipApiVersionCheck,"; - // } - // if (typeof AzuriteTelemetryClient.env?.disableProductStyleUrl === "function" && AzuriteTelemetryClient.env?.disableProductStyleUrl()) - // { - // parameters += "disableProductStyleUrl,"; - // } - // if (typeof AzuriteTelemetryClient.env?.cert === "function" && AzuriteTelemetryClient.env?.cert() !== undefined) - // { - // parameters += "cert,"; - // } - // if (typeof AzuriteTelemetryClient.env?.key === "function" && AzuriteTelemetryClient.env?.key() !== undefined) - // { - // parameters += "key,"; - // } - // if (typeof AzuriteTelemetryClient.env?.pwd === "function" && AzuriteTelemetryClient.env?.pwd() !== undefined) - // { - // parameters += "pwd,"; - // } - // if (typeof AzuriteTelemetryClient.env?.oauth === "function" && AzuriteTelemetryClient.env?.oauth() !== undefined) - // { - // parameters += "oauth,"; - // } - // if (typeof AzuriteTelemetryClient.env?.inMemoryPersistence === "function" && AzuriteTelemetryClient.env?.inMemoryPersistence()) - // { - // parameters += "inMemoryPersistence,"; - // } - // if (typeof AzuriteTelemetryClient.env?.extentMemoryLimit === "function" && AzuriteTelemetryClient.env?.extentMemoryLimit() !== undefined) - // { - // parameters += "extentMemoryLimit,"; - // } - // if (typeof AzuriteTelemetryClient.env?.disableTelemetry === "function" && AzuriteTelemetryClient.env?.disableTelemetry()) - // { - // parameters += "disableTelemetry,"; - // } - // if (typeof AzuriteTelemetryClient.env?.debug === "function" && (await AzuriteTelemetryClient.env?.debug()) !== undefined) - // { - // parameters += "debug,"; - // } + return parameters.endsWith(",") ? parameters.substring(0, parameters.length - 1) : parameters; } } \ No newline at end of file diff --git a/src/queue/middlewares/telemetry.middleware.ts b/src/queue/middlewares/telemetry.middleware.ts index 341d921bb..c7fedf76e 100644 --- a/src/queue/middlewares/telemetry.middleware.ts +++ b/src/queue/middlewares/telemetry.middleware.ts @@ -10,13 +10,11 @@ import ExpressRequestAdapter from '../generated/ExpressRequestAdapter'; import ExpressResponseAdapter from '../generated/ExpressResponseAdapter'; /** - * End middleware is used to send out final HTTP response. + * TelemetryMiddleware is used to send telemetry for requests. * * @export * @param {Context} context - * @param {Request} req An express compatible Request object - * @param {Response} res An express compatible Response object - * @param {ILogger} logger A valid logger + * @param {NextFunction} next An express middleware next callback */ function telemetryMiddleware( context: Context, diff --git a/src/table/middleware/telemetry.middleware.ts b/src/table/middleware/telemetry.middleware.ts index 341d921bb..c7fedf76e 100644 --- a/src/table/middleware/telemetry.middleware.ts +++ b/src/table/middleware/telemetry.middleware.ts @@ -10,13 +10,11 @@ import ExpressRequestAdapter from '../generated/ExpressRequestAdapter'; import ExpressResponseAdapter from '../generated/ExpressResponseAdapter'; /** - * End middleware is used to send out final HTTP response. + * TelemetryMiddleware is used to send telemetry for requests. * * @export * @param {Context} context - * @param {Request} req An express compatible Request object - * @param {Response} res An express compatible Response object - * @param {ILogger} logger A valid logger + * @param {NextFunction} next An express middleware next callback */ function telemetryMiddleware( context: Context,