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/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..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) @@ -204,6 +205,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 +238,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 +271,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 +446,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 +1001,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/package-lock.json b/package-lock.json index d3c74c263..4b292c0cf 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.6", "args": "^5.0.1", "axios": "^0.27.0", "etag": "^1.8.1", @@ -116,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": { @@ -239,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": { @@ -268,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": { @@ -294,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" @@ -534,6 +573,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 +1129,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,19 +1170,82 @@ } }, "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/@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==", + "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": ">= 10" + "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/@tsconfig/node10": { @@ -1355,6 +1489,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 +1860,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 +1867,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", @@ -1751,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" }, @@ -1831,6 +1978,37 @@ "node": ">= 8" } }, + "node_modules/applicationinsights": { + "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.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", + "@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/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -1916,6 +2094,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 +3520,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", @@ -3424,6 +3638,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", @@ -3533,6 +3768,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 +4157,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 +4283,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", @@ -5753,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": { @@ -5784,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" @@ -5871,6 +6152,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 +7587,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 +8088,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 +8393,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 +8810,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 +8869,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 +9287,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 +9474,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 +9661,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" }, @@ -10331,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": { @@ -10432,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", @@ -10455,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" } } } @@ -10477,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": { @@ -10687,6 +11060,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 +11475,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,14 +11509,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==" }, - "@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==" + "@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==" }, "@tsconfig/node10": { "version": "1.0.8", @@ -11358,6 +11798,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 +12038,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", @@ -11613,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" } @@ -11668,6 +12119,25 @@ "picomatch": "^2.0.4" } }, + "applicationinsights": { + "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.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", + "@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" + } + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -11738,6 +12208,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 +13482,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", @@ -13069,6 +13568,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", @@ -13154,6 +13670,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 +13942,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 +14042,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", @@ -14767,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": { @@ -14791,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" @@ -14837,6 +15394,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 +16463,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 +16838,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 +16969,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 +17373,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 +17715,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 +17829,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 +17968,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..37522d2aa 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@azure/ms-rest-js": "^1.5.0", + "applicationinsights": "^2.9.6", "args": "^5.0.1", "axios": "^0.27.0", "etag": "^1.8.1", @@ -264,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." } } } @@ -340,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/azurite.ts b/src/azurite.ts index 74250b445..e856c3e25 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 @@ -39,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); @@ -59,9 +62,10 @@ function shutdown( * Entry for Azurite services. */ 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); @@ -163,6 +167,9 @@ async function main() { console.log( `Azurite Table service is successfully listening at ${tableServer.getHttpServerAddress()}` ); + + AzuriteTelemetryClient.init(location, !env.disableTelemetry(), env); + await AzuriteTelemetryClient.TraceStartEvent(); // Handle close event process diff --git a/src/blob/BlobEnvironment.ts b/src/blob/BlobEnvironment.ts index 481293a8b..19978e592 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 collect telemetry data + return false; + } + public inMemoryPersistence(): boolean { if (this.flags.inMemoryPersistence !== undefined) { if (this.flags.location) { 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/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 41af28052..43d4d3ce8 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(), env); + await AzuriteTelemetryClient.TraceStartEvent("Blob"); // Handle close event process diff --git a/src/blob/middlewares/telemetry.middleware.ts b/src/blob/middlewares/telemetry.middleware.ts new file mode 100644 index 000000000..c7fedf76e --- /dev/null +++ b/src/blob/middlewares/telemetry.middleware.ts @@ -0,0 +1,49 @@ +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'; + +/** + * TelemetryMiddleware is used to send telemetry for requests. + * + * @export + * @param {Context} context + * @param {NextFunction} next An express middleware next callback + */ +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/Environment.ts b/src/common/Environment.ts index 80ac881d1..e42c4fddb 100644 --- a/src/common/Environment.ts +++ b/src/common/Environment.ts @@ -102,6 +102,14 @@ 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" + ) + .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"; @@ -214,6 +222,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 new file mode 100644 index 000000000..430146631 --- /dev/null +++ b/src/common/Telemetry.ts @@ -0,0 +1,415 @@ +import TelemetryClient from "applicationinsights/out/Library/TelemetryClient"; +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 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; + private static requestClient : TelemetryClient | undefined; + + private static enableTelemetry: boolean = true; + private static location: string; + private static configFileName = "AzuriteConfig"; + 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 sessionID = uuid(); + private static instanceID = ""; + private static initialized = false; + private static env: any = undefined; + public static isVSC = false; + + // Debug options + private static isDebug = false; // false in production, true in development + 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 + private static requestMaxBatchSize = AzuriteTelemetryClient.isDebug ? 0 : 0; + + + private static appInsights = require('applicationinsights'); + + 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()); + logger.info(`InstaceID ${AzuriteTelemetryClient.instanceID}, SessionID ${AzuriteTelemetryClient.sessionID}.`); + + AzuriteTelemetryClient.enableTelemetry = enableTelemetry; + AzuriteTelemetryClient.env = env; + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) + { + // for start/stop event, will collect 100%, and send asap + this.eventClient = AzuriteTelemetryClient.createAppInsigntClient(AzuriteTelemetryClient.cloudRole, 100, 0); + } + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) + { + this.requestClient = AzuriteTelemetryClient.createAppInsigntClient(AzuriteTelemetryClient.cloudRole, AzuriteTelemetryClient.requestCollectPercentage, AzuriteTelemetryClient.requestMaxBatchSize); + } + + AzuriteTelemetryClient.appInsights.start(); + AzuriteTelemetryClient.initialized = true; + logger.info('Telemetry initialize successfully.'); + } + else + { + 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 { + // 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 + envelope.tags["ai.operation.name"] = ""; + + return true; + } + + + public static createAppInsigntClient(cloudRole:string, samplingPercentage:number|undefined, maxBatchSize:number|undefined) : TelemetryClient + { + // 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 + 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) + .setAutoCollectPerformance(false) + .setAutoCollectExceptions(false) + .setAutoCollectDependencies(false) + .setAutoCollectConsole(false) + .setAutoCollectHeartbeat(false) + .setAutoCollectConsole(false); + + // Remove some default telemetry item in the telemetry envelope + let telemetryClient = new AzuriteTelemetryClient.appInsights.TelemetryClient(ConnectionString); + telemetryClient.addTelemetryProcessor(AzuriteTelemetryClient.removeRoleInstance); + + if (telemetryClient !== undefined) + { + telemetryClient.context.tags[telemetryClient.context.keys.cloudRole] = AzuriteTelemetryClient.cloudRole; + } + + telemetryClient.config.samplingPercentage = samplingPercentage??1; + + // Enable AppInsight log, should enable in develoipment only + if (AzuriteTelemetryClient.enableAppInsightLog) + { + appConfig.setInternalLogging(true, true); + } + if (maxBatchSize !== undefined) + { + telemetryClient.config.maxBatchSize = maxBatchSize??0; + } + + return telemetryClient; + } + + public static TraceRequest(context: any) { + let serviceType = ""; + let totalReqs = 0; + let reqName = ""; + try{ + if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) + { + 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, + ReqNo:totalReqs, + }; + + 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( + { + 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: "" + } + }); + + logger.verbose(`Send ${serviceType} telemetry: ` + reqName, context.contextId === undefined ? context.contextID : context.contextId); + } + } + catch (e) + { + logger.warn(`Fail to telemetry a ${serviceType} request, error: ` + e.message); + } + } + + public static async 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: await AzuriteTelemetryClient.GetAllParameterString() + } + }); + logger.verbose('Send start telemetry'); + } + } + catch (e) + { + logger.warn('Fail to send start telemetry, error: ' + e.message); + } + } + + 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, + blobRequest: AzuriteTelemetryClient._totalBlobRequestCount, + queueRequest: AzuriteTelemetryClient._totalQueueRequestCount, + tableRequest: AzuriteTelemetryClient._totalTableRequestCount, + totalIngress: AzuriteTelemetryClient._totalIngressSize, + totalEgress: AzuriteTelemetryClient._totalEgressSize, + } + }); + logger.verbose('Send stop telemetry'); + } + } + catch (e) + { + logger.warn('Fail to send stop telemetry, error: ' + e.message); + } + } + + 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]"); + } + else + { + return endpoint; + } + } + + + private static GetInstanceID(inMemoryPersistence : boolean = false): string { + const configFilePath = join( + AzuriteTelemetryClient.location, + AzuriteTelemetryClient.configFileName + ); + + let instaceID = ""; + if (inMemoryPersistence) + { + return uuid(); + } + try { + if(!fs.existsSync(configFilePath)) + { + instaceID = uuid(); + fs.writeFileSync(configFilePath, `{"instaceID":"${instaceID}"}`); + } + else{ + try{ + let data = fs.readFileSync(configFilePath, 'utf8'); + instaceID = JSON.parse(data.toString()).instaceID; + } + 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(`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 && 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) + { + auth = "Sas"; + } + else + { + auth = "Anonymous"; + } + } + return auth; + } + + private static async GetAllParameterString(): Promise { + let parameters = ""; + if (process.env.AZURITE_ACCOUNTS) + { + parameters += "AZURITE_ACCOUNTS,"; + } + if (process.env.AZURITE_DB) + { + parameters += "AZURITE_DB,"; + } + 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) + { + return parameters; + } + else + { + longParameters.forEach((flag) => { + let value = workspaceConfiguration.get(flag); + if (value !== undefined && value !== "" && value !== false && value !== null + && !(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 + ","; + } + }); + } + } + else // npm (exe, docker) + { + 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.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 8b6c5a41a..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"); @@ -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 + ); + } } diff --git a/src/common/VSCServerManagerBlob.ts b/src/common/VSCServerManagerBlob.ts index 3ad33a061..30639d85d 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(); + await 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(), env.workspaceConfiguration, true); // Initialize server configuration const config = new BlobConfiguration( diff --git a/src/common/VSCServerManagerQueue.ts b/src/common/VSCServerManagerQueue.ts index 30f055025..ef880a575 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(); + await 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(), env.workspaceConfiguration, true); // Initialize server configuration const config = new QueueConfiguration( diff --git a/src/common/VSCServerManagerTable.ts b/src/common/VSCServerManagerTable.ts index df0403a04..0ea1c6d74 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(); + await 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(), env.workspaceConfiguration, true); // 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/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/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/main.ts b/src/queue/main.ts index 745a0bff9..8aa3f3262 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(), env); + await AzuriteTelemetryClient.TraceStartEvent("Queue"); // Handle close event process diff --git a/src/queue/middlewares/telemetry.middleware.ts b/src/queue/middlewares/telemetry.middleware.ts new file mode 100644 index 000000000..c7fedf76e --- /dev/null +++ b/src/queue/middlewares/telemetry.middleware.ts @@ -0,0 +1,49 @@ +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'; + +/** + * TelemetryMiddleware is used to send telemetry for requests. + * + * @export + * @param {Context} context + * @param {NextFunction} next An express middleware next callback + */ +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/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/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/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/main.ts b/src/table/main.ts index e86b952f9..c399d8ef9 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(), env); + await 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); }); diff --git a/src/table/middleware/telemetry.middleware.ts b/src/table/middleware/telemetry.middleware.ts new file mode 100644 index 000000000..c7fedf76e --- /dev/null +++ b/src/table/middleware/telemetry.middleware.ts @@ -0,0 +1,49 @@ +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'; + +/** + * TelemetryMiddleware is used to send telemetry for requests. + * + * @export + * @param {Context} context + * @param {NextFunction} next An express middleware next callback + */ +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/tests/blob/blobCorsRequest.test.ts b/tests/blob/blobCorsRequest.test.ts index cd54d667f..edfddd96e 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,14 @@ describe("Blob Cors requests test", () => { before(async () => { await server.start(); + AzuriteTelemetryClient.init("", true, undefined); + 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..6c34841df 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,14 @@ describe("Queue OAuth Basic", () => { oauth: "basic" }) await server.start(); + AzuriteTelemetryClient.init("", true, undefined); + 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/table/apis/table.entity.azure.data-tables.test.ts b/tests/table/apis/table.entity.azure.data-tables.test.ts index 3f4b9f3ff..552b32b40 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,13 @@ 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"); }); 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 () => {