qfix: Use measurements from published packages (#9984)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev
2025-09-30 23:24:48 +07:00
committed by GitHub
parent 295fad6523
commit aea7f8ab4e
23 changed files with 57 additions and 1842 deletions
-32
View File
@@ -79,10 +79,6 @@ jobs:
- name: Checking for mis-matching dependencies...
run: node common/scripts/install-run-rush.js check
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install
@@ -238,10 +234,6 @@ jobs:
- name: Checking for mis-matching dependencies...
run: node common/scripts/install-run-rush.js check
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install
@@ -368,10 +360,6 @@ jobs:
- name: Checking for mis-matching dependencies...
run: node common/scripts/install-run-rush.js check
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install
@@ -463,10 +451,6 @@ jobs:
- name: Checking for mis-matching dependencies...
run: node common/scripts/install-run-rush.js check
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install
@@ -541,10 +525,6 @@ jobs:
- name: Checking for mis-matching dependencies...
run: node common/scripts/install-run-rush.js check
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install
@@ -664,10 +644,6 @@ jobs:
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install
@@ -745,10 +721,6 @@ jobs:
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install --purge
- name: Model version from git tags
@@ -851,10 +823,6 @@ jobs:
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Prepare .npmrc for GitHub Packages
run: |
echo "//npm.pkg.github.com/:_authToken=${{secrets.GITHUB_TOKEN}}" > ~/.npmrc
- name: Installing...
run: node common/scripts/install-run-rush.js install --purge
- name: Model version from git tags
+55 -141
View File
@@ -34,6 +34,12 @@ importers:
'@faker-js/faker':
specifier: ^8.4.1
version: 8.4.1
'@hcengineering/measurements':
specifier: ^0.7.0
version: 0.7.0
'@hcengineering/measurements-otlp':
specifier: ^0.7.0
version: 0.7.0(encoding@0.1.13)
'@hocuspocus/provider':
specifier: ^2.15.2
version: 2.15.2(bufferutil@4.0.8)(utf-8-validate@6.0.4)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27)
@@ -61,48 +67,6 @@ importers:
'@octokit/webhooks-types':
specifier: ^7.3.1
version: 7.5.1
'@opentelemetry/api':
specifier: ^1.9.0
version: 1.9.0
'@opentelemetry/api-logs':
specifier: ^0.203.0
version: 0.203.0
'@opentelemetry/auto-instrumentations-node':
specifier: ^0.62.0
version: 0.62.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.0.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)
'@opentelemetry/core':
specifier: ^2.0.1
version: 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-logs-otlp-http':
specifier: ^0.203.0
version: 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-metrics-otlp-http':
specifier: ^0.203.0
version: 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-trace-otlp-http':
specifier: ^0.203.0
version: 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/id-generator-aws-xray':
specifier: ^2.0.0
version: 2.0.0(@opentelemetry/api@1.9.0)
'@opentelemetry/otlp-exporter-base':
specifier: ^0.203.0
version: 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/resources':
specifier: ^2.0.1
version: 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-logs':
specifier: ^0.203.0
version: 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-metrics':
specifier: ^2.0.1
version: 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-node':
specifier: ^0.203.0
version: 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-node':
specifier: ^2.0.1
version: 2.0.1(@opentelemetry/api@1.9.0)
'@playwright/test':
specifier: ^1.48.2
version: 1.49.1
@@ -165,7 +129,7 @@ importers:
version: file:projects/analytics-providers.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(encoding@0.1.13)(svelte@4.2.20)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
'@rush-temp/analytics-service':
specifier: file:./projects/analytics-service.tgz
version: file:projects/analytics-service.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
version: file:projects/analytics-service.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(encoding@0.1.13)(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
'@rush-temp/api-client':
specifier: file:./projects/api-client.tgz
version: file:projects/api-client.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@swc/core@1.13.5)(babel-jest@29.7.0(@babel/core@7.23.9))(bufferutil@4.0.8)(esbuild@0.25.9)(utf-8-validate@6.0.4)
@@ -535,12 +499,6 @@ importers:
'@rush-temp/mail-common':
specifier: file:./projects/mail-common.tgz
version: file:projects/mail-common.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@swc/core@1.13.5)(babel-jest@29.7.0(@babel/core@7.23.9))
'@rush-temp/measurements':
specifier: file:./projects/measurements.tgz
version: file:projects/measurements.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
'@rush-temp/measurements-otlp':
specifier: file:./projects/measurements-otlp.tgz
version: file:projects/measurements-otlp.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(encoding@0.1.13)(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
'@rush-temp/media':
specifier: file:./projects/media.tgz
version: file:projects/media.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
@@ -3057,6 +3015,12 @@ packages:
engines: {node: '>=6'}
hasBin: true
'@hcengineering/measurements-otlp@0.7.0':
resolution: {integrity: sha512-RTvUzeIKvCENCG1k8LOfBrC32GiF6fgPnqLRY5U7rXLZFISF+fLWXk1Kp7NtkbQXBUVj7C6jWfWb8psJKyIuKg==}
'@hcengineering/measurements@0.7.0':
resolution: {integrity: sha512-RxXi7LsInAZNkDPxoS/CcGoEM8FuzYvd5xDyaKu0gQblNXrmMpePzpf4Mk9riJkeocQvzeZnduGSUPdbC6FVCw==}
'@hocuspocus/common@2.15.2':
resolution: {integrity: sha512-wU1wxXNnQQMXyeL3mdSDYiQsm/r/QyJVjjQhF7sUBrLnjdsN7bA1cvfcSvJBr1ymrMSeYRmUL3UlQmEHEOaP7w==}
@@ -4419,7 +4383,7 @@ packages:
version: 0.0.0
'@rush-temp/analytics-service@file:projects/analytics-service.tgz':
resolution: {integrity: sha512-SbyEMU4sni8FrKq4fRlrYnrAXKOEXR+MtJq2rqR1H7tR+VHaCNToj9Sb4duvYetvhoMfrcMrJfDFdzALTmcmgw==, tarball: file:projects/analytics-service.tgz}
resolution: {integrity: sha512-nV/D7Umpfl8EbdeTJPWFf6TsSGJQBVJm0nzIkugVbscJxRPFXbvVQXvxIwIrciJHUSfJvyn+8PUGb4Io+urU+w==, tarball: file:projects/analytics-service.tgz}
version: 0.0.0
'@rush-temp/analytics@file:projects/analytics.tgz':
@@ -4583,7 +4547,7 @@ packages:
version: 0.0.0
'@rush-temp/communication-resources@file:projects/communication-resources.tgz':
resolution: {integrity: sha512-58n6XOZoF73Mv5xxduEr6qD7ROjeb/MfQk3l+0OUtZkYTex+O0bXw8sEuY4rG+zMLOxHVfJ3by+M3esndt2g6A==, tarball: file:projects/communication-resources.tgz}
resolution: {integrity: sha512-ZcX73ZcvQEn3fa+Pvs34vMTkSEnCnkMtEgTBzqTK+i6dKE4a1HZaTmu1JTTigG4lGmPv9nb+vkgfd8yHcSxiwA==, tarball: file:projects/communication-resources.tgz}
version: 0.0.0
'@rush-temp/communication-rest-client@file:projects/communication-rest-client.tgz':
@@ -4603,7 +4567,7 @@ packages:
version: 0.0.0
'@rush-temp/communication-types@file:projects/communication-types.tgz':
resolution: {integrity: sha512-uzZ82V1R+h+TmxBCrmKaAfUgoiX3Z8ciPGrkc42M++M5d5mlfIjTvPh0O+y50pHoFuQ5NQ3pNIjeDkrJE8Dp0w==, tarball: file:projects/communication-types.tgz}
resolution: {integrity: sha512-aXzOYngWVAf17BZO3jVuebv3HOlGDTs3l9+TQ7haGXEE4RbioRwfMEvDZUm7KiZvO/ejZlGc2Pu/3h7E54YWMA==, tarball: file:projects/communication-types.tgz}
version: 0.0.0
'@rush-temp/communication@file:projects/communication.tgz':
@@ -4635,7 +4599,7 @@ packages:
version: 0.0.0
'@rush-temp/core@file:projects/core.tgz':
resolution: {integrity: sha512-btPoIQ23cdSItu4ElKOMNXYuXZ5FxH5PjHKpl2aQXeRNgm48Wby1DAdYeTPseiLRRZhnr94amOd3StT1RbnUUA==, tarball: file:projects/core.tgz}
resolution: {integrity: sha512-UiUM+J5QIY+nftppcxUvIbrGVnOOrj3uGdiuCky1bYV9rWAvCBEotJ3oEyYhUUsQiGQlZIi82pyfXC1be0Pqrw==, tarball: file:projects/core.tgz}
version: 0.0.0
'@rush-temp/datalake@file:projects/datalake.tgz':
@@ -4918,14 +4882,6 @@ packages:
resolution: {integrity: sha512-FmcRe6dmbRK99u1paZJ2+f+JIpt/6rOoCZaSTUW0isvhc5+hNZaqwYFsOMAMuWRNcWlwIclEXwlwkIogHFReKA==, tarball: file:projects/mail.tgz}
version: 0.0.0
'@rush-temp/measurements-otlp@file:projects/measurements-otlp.tgz':
resolution: {integrity: sha512-OF0gOorTONul+LTXobiri6lEXqLNj5YcJnALqvFArHiEAdDnhu/2d9DqZF/+LyZ+SMtsEthL9UEbxTNb/v62Zg==, tarball: file:projects/measurements-otlp.tgz}
version: 0.0.0
'@rush-temp/measurements@file:projects/measurements.tgz':
resolution: {integrity: sha512-9yd6zagtxOkzBu0d8oBpu11i8L8a7mNJDQ4jQzb3qjlbLTeFXzOI49nJueQB4zO2d8lvSNrRWhTwJX0ZDHRp8w==, tarball: file:projects/measurements.tgz}
version: 0.0.0
'@rush-temp/media-assets@file:projects/media-assets.tgz':
resolution: {integrity: sha512-5Ppzy6nUxEpzPMKj0xuJTO5Ai0hLAnC7MpNSQ2/euFK56V7L4VeqP8RIuODpZbxtNQueZgVDe7/HrjQN6hDe+g==, tarball: file:projects/media-assets.tgz}
version: 0.0.0
@@ -5103,7 +5059,7 @@ packages:
version: 0.0.0
'@rush-temp/model-process@file:projects/model-process.tgz':
resolution: {integrity: sha512-/Qar0A6nR5NxD11A64Alers7Dugvmcdo5h7TAV8NB20EroGB2ATe+rqEb6IQzGQ95zwU0QdZ6znWIAXseFCiHA==, tarball: file:projects/model-process.tgz}
resolution: {integrity: sha512-KYA1lJziZLHn/H7Af60nn3W1BCKCp5XDUSH1nCwf3s1vpX/4dRCw9WTGDUYIf0VnpFlr2IaNacsv270ixP64NA==, tarball: file:projects/model-process.tgz}
version: 0.0.0
'@rush-temp/model-products@file:projects/model-products.tgz':
@@ -5451,7 +5407,7 @@ packages:
version: 0.0.0
'@rush-temp/pod-process@file:projects/pod-process.tgz':
resolution: {integrity: sha512-7KLw9Zd8C5hcal9nFPc8zsuWXy8udYCz70h1dsJ9V5vQUnxEL1wyUH2WKSssAsi+yOSy0p0TynCIuIWuH4W0yQ==, tarball: file:projects/pod-process.tgz}
resolution: {integrity: sha512-HNjCJu8XARw6z69jefA0UpCQGz64Ieklyr/0rljMQgsle2/S9BJZDgPZbh9JKHctvRWGOO6666JvaYFAxCKF9A==, tarball: file:projects/pod-process.tgz}
version: 0.0.0
'@rush-temp/pod-server@file:projects/pod-server.tgz':
@@ -5603,7 +5559,7 @@ packages:
version: 0.0.0
'@rush-temp/recruit@file:projects/recruit.tgz':
resolution: {integrity: sha512-haibbmoHj99CxThRcs1uk79phPTmJoU0N41EIR5nY76a8434F2H5HxAqVu+lLhZDGajZQitXtEQByDNqgK4kHg==, tarball: file:projects/recruit.tgz}
resolution: {integrity: sha512-Q6S3IsrawYcEoxt0bdEQri2gZUFXEw9muto9EviPHS/MUAr3WN/68WhNoq3uHmTbl2Un5zNXeM1nZeBLoo3rDQ==, tarball: file:projects/recruit.tgz}
version: 0.0.0
'@rush-temp/rekoni-service@file:projects/rekoni-service.tgz':
@@ -6059,7 +6015,7 @@ packages:
version: 0.0.0
'@rush-temp/text-editor-resources@file:projects/text-editor-resources.tgz':
resolution: {integrity: sha512-2aRRXC4H573M3+OR/vRe5pGoA4tAB3jEbufqAe4/EgKkUHvRlGVZBBUyDAfYtsIHQd7IrAEEVK1NQoC6iZE1Lg==, tarball: file:projects/text-editor-resources.tgz}
resolution: {integrity: sha512-cuY6deLmbq73Rd72z7F2kq8olFFWw+6E053bWb0LqIcJqxPlK2eJkZLgmCpOghVSMzQCb00bQ6lPI4PIUFlJGg==, tarball: file:projects/text-editor-resources.tgz}
version: 0.0.0
'@rush-temp/text-editor@file:projects/text-editor.tgz':
@@ -6075,7 +6031,7 @@ packages:
version: 0.0.0
'@rush-temp/text-ydoc@file:projects/text-ydoc.tgz':
resolution: {integrity: sha512-EdNN9bQUsIb2qPGpotFbm5xIQDH1GJilcCiV66EVTlrsRkQSAjqVDPZyhQALE8200gR8K7OCSayKoQPnb/nPEA==, tarball: file:projects/text-ydoc.tgz}
resolution: {integrity: sha512-7gAsQxiYN/g2MBMo+mvH8ck91Sd4FligskIYDHpwl6uI4mtn2qTLT6yTT3rWbsr/dvbIaLeDrzb4mEkE1ugM9Q==, tarball: file:projects/text-ydoc.tgz}
version: 0.0.0
'@rush-temp/text@file:projects/text.tgz':
@@ -15587,6 +15543,29 @@ snapshots:
protobufjs: 7.5.3
yargs: 17.7.2
'@hcengineering/measurements-otlp@0.7.0(encoding@0.1.13)':
dependencies:
'@hcengineering/measurements': 0.7.0
'@opentelemetry/api': 1.9.0
'@opentelemetry/api-logs': 0.203.0
'@opentelemetry/auto-instrumentations-node': 0.62.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.0.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)
'@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-logs-otlp-http': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-metrics-otlp-http': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-trace-otlp-http': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/id-generator-aws-xray': 2.0.0(@opentelemetry/api@1.9.0)
'@opentelemetry/otlp-exporter-base': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-logs': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-metrics': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-node': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0)
transitivePeerDependencies:
- encoding
- supports-color
'@hcengineering/measurements@0.7.0': {}
'@hocuspocus/common@2.15.2':
dependencies:
lib0: 0.2.114
@@ -17841,8 +17820,9 @@ snapshots:
- svelte
- ts-node
'@rush-temp/analytics-service@file:projects/analytics-service.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))':
'@rush-temp/analytics-service@file:projects/analytics-service.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(encoding@0.1.13)(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))':
dependencies:
'@hcengineering/measurements-otlp': 0.7.0(encoding@0.1.13)
'@types/jest': 29.5.12
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.8.3)
@@ -17864,6 +17844,7 @@ snapshots:
- '@types/node'
- babel-jest
- babel-plugin-macros
- encoding
- esbuild
- node-notifier
- supports-color
@@ -19473,6 +19454,7 @@ snapshots:
'@rush-temp/core@file:projects/core.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))':
dependencies:
'@hcengineering/measurements': 0.7.0
'@types/jest': 29.5.12
'@types/node': 22.15.29
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3)
@@ -21721,73 +21703,6 @@ snapshots:
- supports-color
- ts-node
'@rush-temp/measurements-otlp@file:projects/measurements-otlp.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(encoding@0.1.13)(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))':
dependencies:
'@opentelemetry/api': 1.9.0
'@opentelemetry/api-logs': 0.203.0
'@opentelemetry/auto-instrumentations-node': 0.62.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.0.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)
'@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-logs-otlp-http': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-metrics-otlp-http': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-trace-otlp-http': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/id-generator-aws-xray': 2.0.0(@opentelemetry/api@1.9.0)
'@opentelemetry/otlp-exporter-base': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-logs': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-metrics': 2.0.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-node': 0.203.0(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0)
'@types/jest': 29.5.12
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.8.3)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.8.3)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
prettier: 3.2.5
simplytyped: 3.3.0(typescript@5.8.3)
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- '@types/node'
- babel-jest
- babel-plugin-macros
- encoding
- esbuild
- node-notifier
- supports-color
- ts-node
'@rush-temp/measurements@file:projects/measurements.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@22.15.29)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))':
dependencies:
'@types/jest': 29.5.12
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.8.3)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.8.3))(eslint@8.56.0)(typescript@5.8.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.8.3)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
prettier: 3.2.5
simplytyped: 3.3.0(typescript@5.8.3)
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- '@types/node'
- babel-jest
- babel-plugin-macros
- esbuild
- node-notifier
- supports-color
- ts-node
'@rush-temp/media-assets@file:projects/media-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))':
dependencies:
'@types/jest': 29.5.12
@@ -30027,7 +29942,6 @@ snapshots:
fast-equals: 5.2.2
jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3))
jest-environment-jsdom: 29.7.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
lib0: 0.2.114
prettier: 3.2.5
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.25.9)(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.15.29)(typescript@5.8.3)))(typescript@5.8.3)
typescript: 5.8.3
@@ -32115,7 +32029,7 @@ snapshots:
'@types/pg-pool@2.0.6':
dependencies:
'@types/pg': 8.11.11
'@types/pg': 8.15.4
'@types/pg@8.11.11':
dependencies:
@@ -40650,19 +40564,19 @@ snapshots:
y-indexeddb@9.0.12(yjs@13.6.27):
dependencies:
lib0: 0.2.89
lib0: 0.2.114
yjs: 13.6.27
y-leveldb@0.1.2(yjs@13.6.27):
dependencies:
level: 6.0.1
lib0: 0.2.109
lib0: 0.2.114
yjs: 13.6.27
optional: true
y-prosemirror@1.3.7(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.37.2)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27):
dependencies:
lib0: 0.2.109
lib0: 0.2.114
prosemirror-model: 1.24.1
prosemirror-state: 1.4.3
prosemirror-view: 1.37.2
@@ -40671,7 +40585,7 @@ snapshots:
y-protocols@1.0.6(yjs@13.6.27):
dependencies:
lib0: 0.2.89
lib0: 0.2.114
yjs: 13.6.27
y-websocket@2.1.0(yjs@13.6.27):
@@ -40739,7 +40653,7 @@ snapshots:
yjs@13.6.27:
dependencies:
lib0: 0.2.109
lib0: 0.2.114
ylru@1.3.2: {}
+1 -1
View File
@@ -41,7 +41,7 @@
"@hcengineering/platform": "^0.6.11",
"@hcengineering/core": "^0.6.32",
"@hcengineering/analytics": "^0.6.0",
"@hcengineering/measurements-otlp": "^0.6.0",
"@hcengineering/measurements-otlp": "^0.7.0",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^5.0.0"
},
+1 -1
View File
@@ -41,7 +41,7 @@
"dependencies": {
"@hcengineering/platform": "^0.6.11",
"@hcengineering/analytics": "^0.6.0",
"@hcengineering/measurements": "^0.6.0",
"@hcengineering/measurements": "^0.7.0",
"fast-equals": "^5.2.2"
},
"repository": "https://github.com/hcengineering/platform",
-7
View File
@@ -1,7 +0,0 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
-4
View File
@@ -1,4 +0,0 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/
@@ -1,4 +0,0 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
@@ -1,7 +0,0 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
roots: ["./src"],
coverageReporters: ["text-summary", "html"]
}
-61
View File
@@ -1,61 +0,0 @@
{
"name": "@hcengineering/measurements-otlp",
"version": "0.6.0",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "compile",
"build:watch": "compile",
"test": "jest --passWithNoTests --silent",
"format": "format src",
"_phase:build": "compile transpile src",
"_phase:test": "jest --passWithNoTests --silent",
"_phase:format": "format src",
"_phase:validate": "compile validate"
},
"devDependencies": {
"@hcengineering/platform-rig": "^0.6.0",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-n": "^15.4.0",
"eslint": "^8.54.0",
"simplytyped": "^3.3.0",
"@typescript-eslint/parser": "^6.11.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3",
"jest": "^29.7.0",
"ts-jest": "^29.1.1",
"@types/jest": "^29.5.5"
},
"dependencies": {
"@hcengineering/measurements": "^0.6.0",
"@opentelemetry/sdk-node": "^0.203.0",
"@opentelemetry/sdk-logs": "^0.203.0",
"@opentelemetry/auto-instrumentations-node": "^0.62.0",
"@opentelemetry/resources": "^2.0.1",
"@opentelemetry/sdk-trace-node": "^2.0.1",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/core": "^2.0.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.203.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.203.0",
"@opentelemetry/otlp-exporter-base": "^0.203.0",
"@opentelemetry/id-generator-aws-xray": "^2.0.0",
"@opentelemetry/exporter-metrics-otlp-http": "^0.203.0",
"@opentelemetry/api-logs": "^0.203.0",
"@opentelemetry/sdk-metrics": "^2.0.1"
},
"repository": "https://github.com/hcengineering/platform",
"publishConfig": {
"access": "public"
}
}
-1
View File
@@ -1 +0,0 @@
export * from './telemetry'
-608
View File
@@ -1,608 +0,0 @@
import {
childMetrics,
consoleLogger,
MeasureContext,
MeasureMetricsContext,
newMetrics,
noParamsLogger,
nullPromise,
platformNow,
platformNowDiff,
updateMeasure,
type FullParamsType,
type MeasureLogger,
type Metrics,
type ParamsType,
type WithOptions
} from '@hcengineering/measurements'
import {
context,
metrics as otelMetrics,
propagation,
Span,
SpanStatusCode,
trace,
type Context,
type Gauge,
type Meter,
type Tracer
} from '@opentelemetry/api'
import { Logger, SeverityNumber } from '@opentelemetry/api-logs'
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { suppressTracing } from '@opentelemetry/core'
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { AWSXRayIdGenerator } from '@opentelemetry/id-generator-aws-xray'
import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base'
import { resourceFromAttributes } from '@opentelemetry/resources'
import { BatchLogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs'
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-node'
class MetricsContext {
counters = new Map<string, { counter: Gauge, value: 0 }>()
constructor (readonly meter?: Meter) {}
getCounter (name: string): { counter: Gauge, value: number } | undefined {
if (this.meter === undefined) {
return undefined
}
let counter = this.counters.get(name)
if (counter === undefined) {
counter = { counter: this.meter.createGauge(name), value: 0 }
this.counters.set(name, counter)
}
return counter
}
}
/**
* @public
*/
export class OpenTelemetryMetricsContext implements MeasureContext {
private readonly name: string
private readonly params: ParamsType
private readonly fullParams: FullParamsType | (() => FullParamsType) = {}
logger: MeasureLogger
metrics: Metrics
id?: string
st = platformNow()
contextData: object = {}
isDone = false
doneTrace: string = ''
private done (value?: number, override?: boolean): void {
if (!this.isDone) {
this.doneTrace = new Error().stack ?? ''
this.isDone = true
updateMeasure(this.metrics, this.st, this.params, this.fullParams, (spend) => {}, value, override)
this.span?.end()
}
}
constructor (
name: string,
readonly tracer: Tracer,
readonly context: Context | undefined,
readonly span: Span | undefined,
params: ParamsType,
fullParams: FullParamsType | (() => FullParamsType) = {},
metrics: Metrics = newMetrics(),
logger?: MeasureLogger,
readonly parent?: MeasureContext,
readonly logParams?: ParamsType,
readonly otlpLogger?: Logger,
readonly meter?: MetricsContext
) {
this.name = name
this.params = params
this.fullParams = fullParams
this.metrics = metrics
this.metrics.namedParams = this.metrics.namedParams ?? {}
for (const [k, v] of Object.entries(params)) {
if (this.metrics.namedParams[k] !== v) {
this.metrics.namedParams[k] = v
} else {
this.metrics.namedParams[k] = '*'
}
}
this.logger = logger ?? (this.logParams != null ? consoleLogger(this.logParams ?? {}) : noParamsLogger)
}
measure (name: string, value: number, override?: boolean): void {
const cnt = this.meter?.getCounter(name)
if (cnt !== undefined) {
if (cnt.value !== value) {
cnt.counter.record(value, this.params)
cnt.value = value
}
}
}
newChild (
name: string,
params: ParamsType,
opt?: {
fullParams?: FullParamsType
logger?: MeasureLogger
span?: WithOptions['span'] // By default true
meta?: Record<string, string | number | boolean>
}
): MeasureContext {
let _span: Span | undefined
let childContext: Context | undefined
if (opt?.span === true || opt?.span === 'inherit') {
childContext = opt?.span === 'inherit' ? context.active() : this.context ?? context.active()
if (opt.meta !== undefined && Object.keys(opt.meta).length > 0) {
// We need to set meta params
childContext = propagation.extract(childContext ?? context.active(), opt.meta)
}
_span = this.tracer.startSpan(name, undefined, childContext)
const spanParams = [...Object.entries(params)]
for (const [k, v] of spanParams) {
_span?.setAttribute(k, v as any)
}
}
if (opt?.span === 'disable') {
childContext = suppressTracing(childContext ?? context.active())
}
if (childContext !== undefined && _span !== undefined) {
childContext = trace.setSpan(childContext, _span)
}
const result = new OpenTelemetryMetricsContext(
name,
this.tracer,
childContext,
_span,
params,
opt?.fullParams ?? {},
childMetrics(this.metrics, [name]),
opt?.logger ?? this.logger,
this,
this.logParams,
this.otlpLogger,
this.meter
)
result.id = this.id
result.contextData = this.contextData
return result
}
extractMeta (): Record<string, string | number | boolean> {
const headers: Record<string, string> = {}
if (this.context !== undefined) {
propagation.inject(this.context, headers)
}
return headers
}
with<T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => T | Promise<T>,
fullParams?: ParamsType | (() => FullParamsType),
opt?: WithOptions
): Promise<T> {
const c = this.newChild(name, opt?.inheritParams === true ? { ...this.params, ...params } : params, {
fullParams,
logger: this.logger,
span: opt?.span ?? true,
meta: opt?.meta
})
let needFinally = true
try {
const _context = (c as OpenTelemetryMetricsContext).context
const span = (c as OpenTelemetryMetricsContext).span
const value = _context !== undefined ? context.with(_context, () => op(c)) : op(c)
if (value instanceof Promise) {
needFinally = false
if (span !== undefined) {
void value.catch((err) => {
span?.recordException(err)
span?.setStatus({
code: SpanStatusCode.ERROR,
message: err.message
})
})
}
return value.finally(() => {
if (span !== undefined) {
const fParams = typeof fullParams === 'function' ? fullParams() : fullParams
const spanParams = [...Object.entries(params), ...Object.entries(fParams ?? {})]
for (const [k, v] of spanParams) {
span?.setAttribute(k, typeof v === 'object' ? JSON.stringify(v) : v)
}
}
c.end()
if (opt?.log === true) {
this.logger.logOperation(name, platformNowDiff((c as OpenTelemetryMetricsContext).st), {
...params,
...fullParams
})
}
})
} else {
if (value == null) {
return nullPromise as Promise<T>
}
return Promise.resolve(value)
}
} finally {
if (needFinally) {
c.end()
}
}
}
withSync<T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => T,
fullParams?: ParamsType | (() => FullParamsType),
opt?: WithOptions
): T {
const c = this.newChild(name, params, { fullParams, logger: this.logger, span: opt?.span ?? true })
const _context = (c as OpenTelemetryMetricsContext).context
try {
return _context !== undefined ? context.with(_context, () => op(c)) : op(c)
} finally {
c.end()
}
}
error (message: string, args?: Record<string, any>): void {
if (this.otlpLogger !== undefined) {
this.otlpLogger.emit({
severityNumber: SeverityNumber.ERROR,
severityText: 'error',
context: this.context,
body: message,
attributes: {
'service.name': sdkServiceName,
...(args ?? {})
}
})
}
this.logger.error(message, { ...this.params, ...args, ...(this.logParams ?? {}) })
}
info (message: string, args?: Record<string, any>): void {
if (this.otlpLogger !== undefined) {
this.otlpLogger.emit({
context: this.context,
severityNumber: SeverityNumber.INFO,
severityText: 'info',
body: message,
attributes: {
'service.name': sdkServiceName,
...(args ?? {})
}
})
}
this.logger.info(message, { ...this.params, ...args, ...(this.logParams ?? {}) })
}
warn (message: string, args?: Record<string, any>): void {
if (this.otlpLogger !== undefined) {
this.otlpLogger.emit({
severityNumber: SeverityNumber.WARN,
severityText: 'warn',
context: this.context,
body: message,
attributes: {
'service.name': sdkServiceName,
...(args ?? {})
}
})
}
this.logger.warn(message, { ...this.params, ...args, ...(this.logParams ?? {}) })
}
end (): void {
this.done()
}
getParams (): ParamsType {
return this.params
}
}
/**
* Parse W3C baggage header format to Record<string, string>
*
* W3C baggage format: "key1=value1,key2=value2;property=value,key3=value3"
* Returns only the key-value pairs, ignoring properties
*/
function parseBaggage (baggageHeader?: string): Record<string, string> {
if (baggageHeader == null || typeof baggageHeader !== 'string') {
return {}
}
const result: Record<string, string> = {}
// Split by comma to get individual baggage members
const members = baggageHeader.split(',')
for (const member of members) {
const trimmedMember = member.trim()
if (trimmedMember === '') continue
// Split by semicolon to separate key=value from properties
const parts = trimmedMember.split(';')
const keyValuePart = parts[0]?.trim()
if (keyValuePart == null) continue
// Split by equals to get key and value
const equalIndex = keyValuePart.indexOf('=')
if (equalIndex === -1) continue
const key = keyValuePart.substring(0, equalIndex).trim()
const value = keyValuePart.substring(equalIndex + 1).trim()
if (key != null) {
// URL decode the key and value
try {
const decodedKey = decodeURIComponent(key)
const decodedValue = decodeURIComponent(value)
result[decodedKey] = decodedValue
} catch (error) {
// If decoding fails, use the original values
result[key] = value
}
}
}
return result
}
let sdk: NodeSDK | undefined
let sdkServiceName: string | undefined
let sdkServiceVersion: string | undefined
let loggerProvider: LoggerProvider | undefined
export function initOpenTelemetrySDK (serviceName: string, version: string): boolean {
if (sdk !== undefined) {
return true
}
process.env.OTEL_SERVICE_NAME = serviceName
process.env.OTEL_SERVICE_VERSION = version
sdkServiceName = serviceName
sdkServiceVersion = version
const tracesUrl = getTracesUrl()
if (tracesUrl === undefined) {
return false
}
const traceHeaders = parseTraceExporterHeaders()
const exporter = new OTLPTraceExporter({
url: tracesUrl,
headers: traceHeaders,
compression:
(process.env.OTEL_EXPORTER_OTLP_COMPRESSION as CompressionAlgorithm) ??
(process.env.OTEL_EXPORTER_OTLP_TRACES_COMPRESSION as CompressionAlgorithm) ??
CompressionAlgorithm.GZIP,
keepAlive: true
})
const batchSpanProcessor = new BatchSpanProcessor(exporter, {
maxExportBatchSize: parseInt(process.env.OTEL_EXPORTER_OTLP_TRACES_MAX_EXPORT_BATCH_SIZE ?? '1000'),
maxQueueSize: parseInt(process.env.OTEL_EXPORTER_OTLP_TRACES_MAX_QUEUE_SIZE ?? '1000')
})
// Logs
const logsEndpoint = getLogsUrl()
const logHeaders = parseLogsExporterHeaders()
const logExporter = new OTLPLogExporter({
url: logsEndpoint,
headers: logHeaders,
compression:
(process.env.OTEL_EXPORTER_OTLP_COMPRESSION as CompressionAlgorithm) ??
(process.env.OTEL_EXPORTER_OTLP_LOGS_COMPRESSION as CompressionAlgorithm) ??
CompressionAlgorithm.GZIP,
keepAlive: true
})
const batchLogProcessor = new BatchLogRecordProcessor(logExporter, {
maxExportBatchSize: parseInt(process.env.OTEL_EXPORTER_OTLP_LOGS_MAX_EXPORT_BATCH_SIZE ?? '1000'),
maxQueueSize: parseInt(process.env.OTEL_EXPORTER_OTLP_LOGS_MAX_QUEUE_SIZE ?? '1000')
})
// Metrics
const metricsUrl = getMetricsUrl()
const metricsHeaders = parseMetricsExporterHeaders()
const metricsExporter = new OTLPMetricExporter({
url: metricsUrl,
headers: metricsHeaders
})
const metricReader = new PeriodicExportingMetricReader({
exporter: metricsExporter,
exportIntervalMillis: 15000
})
// SDK
sdk = new NodeSDK({
spanProcessors: [batchSpanProcessor],
serviceName,
traceExporter: exporter,
resource: resourceFromAttributes({
'service-name': serviceName,
'service-version': version ?? '0.7',
'deployment-environment': process.env.OTEL_ENVIRONMENT
}),
instrumentations: [getNodeAutoInstrumentations()],
idGenerator: new AWSXRayIdGenerator(),
logRecordProcessors: [batchLogProcessor],
metricReader
})
sdk.start()
loggerProvider = new LoggerProvider({
processors: [batchLogProcessor]
})
// Graceful shutdown
process.on('SIGTERM', () => {
sdk
?.shutdown()
.then(() => {
console.log('Tracing terminated')
})
.catch((error) => {
console.log('Error terminating tracing', error)
})
.finally(() => process.exit(0))
})
console.log('Using open telemetry metrics context', {
traceEndpoint: tracesUrl,
tracerHeadersSet: Array.from(Object.keys(traceHeaders)),
logsEndpoint,
logHeadersSet: Array.from(Object.keys(logHeaders))
})
return true
}
export function reportOTELError (error: Error): void {
if (sdkServiceName !== undefined && sdkServiceVersion !== undefined && loggerProvider !== undefined) {
const otlpLogger = loggerProvider?.getLogger(sdkServiceName, sdkServiceVersion)
otlpLogger?.emit({
severityNumber: SeverityNumber.ERROR,
severityText: 'error',
body: error.message,
context: context.active(),
attributes: {
'service.name': sdkServiceName,
'service.version': sdkServiceVersion,
'error.stack': error.stack
}
})
}
}
export function createOpenTelemetryMetricsContext (
name: string,
params: ParamsType,
fullParams: FullParamsType | (() => FullParamsType) = {},
metrics: Metrics = newMetrics(),
logger?: MeasureLogger,
version?: string
): MeasureContext {
if (!initOpenTelemetrySDK(name, version ?? '')) {
console.warn('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is not set, OpenTelemetry metrics will not be sent')
return new MeasureMetricsContext(name, params, fullParams, metrics, logger)
}
// Traces
const tracer = trace.getTracer(name)
const otlpLogger =
process.env.OTEL_LOGGER_ENABLED === 'true' ? loggerProvider?.getLogger(sdkServiceName ?? name, version) : undefined
const meter = otelMetrics.getMeter(name, version)
const ctx = new OpenTelemetryMetricsContext(
name,
tracer,
undefined,
undefined,
params,
fullParams,
metrics,
logger,
undefined,
undefined,
otlpLogger,
new MetricsContext(meter)
)
return ctx
}
function parseTraceExporterHeaders (): Record<string, string> {
const headers: Record<string, string> = parseBaggage(process.env.OTEL_EXPORTER_OTLP_HEADERS) ?? {}
if (process.env.OTEL_EXPORTER_OTLP_TRACES_HEADERS !== undefined) {
const extraHeaders = parseBaggage(process.env.OTEL_EXPORTER_OTLP_TRACES_HEADERS)
for (const [key, value] of Object.entries(extraHeaders)) {
headers[key] = value
}
}
return headers
}
function getTracesUrl (): string | undefined {
let tracesUrl = process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT
if (tracesUrl !== undefined && !tracesUrl.endsWith('/v1/traces')) {
if (tracesUrl.endsWith('/')) {
tracesUrl += 'v1/traces'
} else {
tracesUrl += '/v1/traces'
}
}
return tracesUrl
}
function getLogsUrl (): string | undefined {
let logsUrl = process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT
if (logsUrl !== undefined && !logsUrl.endsWith('/v1/logs')) {
if (logsUrl.endsWith('/')) {
logsUrl += 'v1/logs'
} else {
logsUrl += '/v1/logs'
}
}
return logsUrl
}
function parseLogsExporterHeaders (): Record<string, string> {
const headers: Record<string, string> = parseBaggage(process.env.OTEL_EXPORTER_OTLP_HEADERS) ?? {}
if (process.env.OTEL_EXPORTER_OTLP_LOGS_HEADERS !== undefined) {
const extraHeaders = parseBaggage(process.env.OTEL_EXPORTER_OTLP_LOGS_HEADERS)
for (const [key, value] of Object.entries(extraHeaders)) {
headers[key] = value
}
}
return headers
}
function getMetricsUrl (): string | undefined {
let metricsUrl = process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT
if (metricsUrl !== undefined && !metricsUrl.endsWith('/v1/metrics')) {
if (metricsUrl.endsWith('/')) {
metricsUrl += 'v1/metrics'
} else {
metricsUrl += '/v1/metrics'
}
}
return metricsUrl
}
function parseMetricsExporterHeaders (): Record<string, string> {
const headers: Record<string, string> = parseBaggage(process.env.OTEL_EXPORTER_OTLP_HEADERS) ?? {}
if (process.env.OTEL_EXPORTER_OTLP_METRICS_HEADERS !== undefined) {
const extraHeaders = parseBaggage(process.env.OTEL_EXPORTER_OTLP_METRICS_HEADERS)
for (const [key, value] of Object.entries(extraHeaders)) {
headers[key] = value
}
}
return headers
}
-12
View File
@@ -1,12 +0,0 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"tsBuildInfoFile": ".build/build.tsbuildinfo"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "lib", "dist", "types", "bundle"]
}
-7
View File
@@ -1,7 +0,0 @@
module.exports = {
extends: ['./node_modules/@hcengineering/platform-rig/profiles/default/eslint.config.json'],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
}
-4
View File
@@ -1,4 +0,0 @@
*
!/lib/**
!CHANGELOG.md
/lib/**/__tests__/
-4
View File
@@ -1,4 +0,0 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@hcengineering/platform-rig"
}
-7
View File
@@ -1,7 +0,0 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
roots: ["./src"],
coverageReporters: ["text-summary", "html"]
}
-51
View File
@@ -1,51 +0,0 @@
{
"name": "@hcengineering/measurements",
"version": "0.6.0",
"main": "lib/index.js",
"svelte": "src/index.ts",
"types": "types/index.d.ts",
"files": [
"lib/**/*",
"types/**/*",
"tsconfig.json"
],
"author": "Anticrm Platform Contributors",
"license": "EPL-2.0",
"scripts": {
"build": "compile",
"build:watch": "compile",
"test": "jest --passWithNoTests --silent",
"format": "format src",
"_phase:build": "compile transpile src",
"_phase:test": "jest --passWithNoTests --silent",
"_phase:format": "format src",
"_phase:validate": "compile validate"
},
"devDependencies": {
"@hcengineering/platform-rig": "^0.6.0",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-n": "^15.4.0",
"eslint": "^8.54.0",
"simplytyped": "^3.3.0",
"@typescript-eslint/parser": "^6.11.0",
"eslint-config-standard-with-typescript": "^40.0.0",
"prettier": "^3.1.0",
"typescript": "^5.8.3",
"jest": "^29.7.0",
"ts-jest": "^29.1.1",
"@types/jest": "^29.5.5"
},
"repository": "https://github.com/hcengineering/platform",
"publishConfig": {
"access": "public"
},
"exports": {
".": {
"types": "./types/index.d.ts",
"require": "./lib/index.js",
"import": "./lib/index.js"
}
}
}
-386
View File
@@ -1,386 +0,0 @@
// Basic performance metrics suite.
import { platformNow, platformNowDiff } from '.'
import { childMetrics, newMetrics, updateMeasure } from './metrics'
import {
type FullParamsType,
type MeasureContext,
type MeasureLogger,
type Metrics,
type ParamsType,
type OperationLog,
type OperationLogEntry,
type WithOptions
} from './types'
const errorPrinter = ({ message, stack, ...rest }: Error): object => ({
message,
stack,
...rest
})
function replacer (value: any): any {
return value instanceof Error ? errorPrinter(value) : value
}
export const consoleLogger = (logParams: Record<string, any>): MeasureLogger => ({
info: (msg, args) => {
console.info(
msg,
...Object.entries({ ...(args ?? {}), ...(logParams ?? {}) }).map(
(it) => `${it[0]}=${JSON.stringify(replacer(it[1]))}`
)
)
},
error: (msg, args) => {
console.error(
msg,
...Object.entries({ ...(args ?? {}), ...(logParams ?? {}) }).map(
(it) => `${it[0]}=${JSON.stringify(replacer(it[1]))}`
)
)
},
warn: (msg, args) => {
console.warn(msg, ...Object.entries(args ?? {}).map((it) => `${it[0]}=${JSON.stringify(replacer(it[1]))}`))
},
close: async () => {},
logOperation: (operation, time, params) => {}
})
export const noParamsLogger = consoleLogger({})
export const nullPromise = Promise.resolve()
/**
* @public
*/
export class MeasureMetricsContext implements MeasureContext {
private readonly name: string
private readonly params: ParamsType
private readonly fullParams: FullParamsType | (() => FullParamsType) = {}
logger: MeasureLogger
metrics: Metrics
id?: string
st = platformNow()
contextData: object = {}
private done (value?: number, override?: boolean): void {
updateMeasure(this.metrics, this.st, this.params, this.fullParams, (spend) => {}, value, override)
}
constructor (
name: string,
params: ParamsType,
fullParams: FullParamsType | (() => FullParamsType) = {},
metrics: Metrics = newMetrics(),
logger?: MeasureLogger,
readonly parent?: MeasureContext,
readonly logParams?: ParamsType
) {
this.name = name
this.params = params
this.fullParams = fullParams
this.metrics = metrics
this.metrics.namedParams = this.metrics.namedParams ?? {}
for (const [k, v] of Object.entries(params)) {
if (this.metrics.namedParams[k] !== v) {
this.metrics.namedParams[k] = v
} else {
this.metrics.namedParams[k] = '*'
}
}
this.logger = logger ?? (this.logParams != null ? consoleLogger(this.logParams ?? {}) : noParamsLogger)
}
measure (name: string, value: number, override?: boolean): void {
const c = new MeasureMetricsContext('#' + name, {}, {}, childMetrics(this.metrics, ['#' + name]), this.logger, this)
c.contextData = this.contextData
c.done(value, override)
}
newChild (
name: string,
params: ParamsType,
opt?: {
fullParams?: FullParamsType
logger?: MeasureLogger
span?: WithOptions['span'] // By default true
}
): MeasureContext {
const result = new MeasureMetricsContext(
name,
params,
opt?.fullParams ?? {},
childMetrics(this.metrics, [name]),
opt?.logger ?? this.logger,
this,
this.logParams
)
result.id = this.id
result.contextData = this.contextData
return result
}
with<T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => T | Promise<T>,
fullParams?: ParamsType | (() => FullParamsType),
opt?: WithOptions
): Promise<T> {
const c = this.newChild(name, params, { fullParams, logger: this.logger })
let needFinally = true
try {
const value = op(c)
if (value instanceof Promise) {
needFinally = false
return value.finally(() => {
c.end()
if (opt?.log === true) {
this.logger.logOperation(name, platformNowDiff((c as MeasureMetricsContext).st), {
...params,
...fullParams
})
}
})
} else {
if (value == null) {
return nullPromise as Promise<T>
}
return Promise.resolve(value)
}
} finally {
if (needFinally) {
c.end()
}
}
}
extractMeta (): Record<string, string | number | boolean> {
return {}
}
withSync<T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => T,
fullParams?: ParamsType | (() => FullParamsType)
): T {
const c = this.newChild(name, params, { fullParams, logger: this.logger })
try {
return op(c)
} finally {
c.end()
}
}
error (message: string, args?: Record<string, any>): void {
this.logger.error(message, { ...this.params, ...args, ...(this.logParams ?? {}) })
}
info (message: string, args?: Record<string, any>): void {
this.logger.info(message, { ...this.params, ...args, ...(this.logParams ?? {}) })
}
warn (message: string, args?: Record<string, any>): void {
this.logger.warn(message, { ...this.params, ...args, ...(this.logParams ?? {}) })
}
end (): void {
this.done()
}
getParams (): ParamsType {
return this.params
}
}
export class NoMetricsContext implements MeasureContext {
logger: MeasureLogger
id?: string
contextData: object = {}
constructor (logger?: MeasureLogger) {
this.logger = logger ?? consoleLogger({})
}
measure (name: string, value: number, override?: boolean): void {}
newChild (
name: string,
params: ParamsType,
fullParams?: FullParamsType | (() => FullParamsType),
logger?: MeasureLogger
): MeasureContext {
const result = new NoMetricsContext(logger ?? this.logger)
result.id = this.id
result.contextData = this.contextData
return result
}
with<T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => T | Promise<T>,
fullParams?: ParamsType | (() => FullParamsType)
): Promise<T> {
const r = op(this.newChild(name, params, fullParams, this.logger))
return r instanceof Promise ? r : Promise.resolve(r)
}
extractMeta (): Record<string, string | number | boolean> {
return {}
}
withSync<T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => T,
fullParams?: ParamsType | (() => FullParamsType)
): T {
const c = this.newChild(name, params, fullParams, this.logger)
return op(c)
}
withLog<T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => T | Promise<T>,
fullParams?: ParamsType
): Promise<T> {
const r = op(this.newChild(name, params, fullParams, this.logger))
return r instanceof Promise ? r : Promise.resolve(r)
}
error (message: string, args?: Record<string, any>): void {
this.logger.error(message, { ...args })
}
info (message: string, args?: Record<string, any>): void {
this.logger.info(message, { ...args })
}
warn (message: string, args?: Record<string, any>): void {
this.logger.warn(message, { ...args })
}
end (): void {}
getParams (): ParamsType {
return {}
}
}
/**
* Allow to use decorator for context enabled functions
*/
export function withContext (name: string, params: ParamsType = {}): any {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor => {
const originalMethod = descriptor.value
descriptor.value = function (...args: any[]): Promise<any> {
const ctx = args[0] as MeasureContext
return ctx.with(name, params, (ctx) => originalMethod.apply(this, [ctx, ...args.slice(1)]) as Promise<any>)
}
return descriptor
}
}
let operationProfiling = false
export function setOperationLogProfiling (value: boolean): void {
operationProfiling = value
}
let globalId: number = 0
export function registerOperationLog (ctx: MeasureContext): { opLogMetrics?: Metrics, op?: OperationLog } {
if (!operationProfiling) {
return {}
}
const op: OperationLog = { start: platformNow(), ops: [], end: -1 }
let opLogMetrics: Metrics | undefined
if (ctx.id === undefined) {
ctx.id = 'op_' + (++globalId).toString(16)
}
if (ctx.metrics !== undefined) {
if (ctx.metrics.opLog === undefined) {
ctx.metrics.opLog = {}
}
ctx.metrics.opLog[ctx.id] = op
opLogMetrics = ctx.metrics
}
return { opLogMetrics, op }
}
export function updateOperationLog (opLogMetrics: Metrics | undefined, op: OperationLog | undefined): void {
if (!operationProfiling) {
return
}
if (op !== undefined) {
op.end = platformNow()
}
// We should keep only longest one entry
if (opLogMetrics?.opLog !== undefined) {
const entries = Object.entries(opLogMetrics.opLog)
const incomplete = entries.filter((it) => it[1].end === -1)
const complete = entries.filter((it) => it[1].end !== -1)
complete.sort((a, b) => a[1].start - b[1].start)
if (complete.length > 30) {
complete.splice(0, complete.length - 30)
}
opLogMetrics.opLog = Object.fromEntries(incomplete.concat(complete))
}
}
export function addOperation<T> (
ctx: MeasureContext,
name: string,
params: ParamsType,
op: (ctx: MeasureContext) => Promise<T>,
fullParams?: FullParamsType
): Promise<T> {
if (!operationProfiling) {
return op(ctx)
}
let opEntry: OperationLogEntry | undefined
let p: MeasureContext | undefined = ctx
let opLogMetrics: Metrics | undefined
let id: string | undefined
while (p !== undefined) {
if (p.metrics?.opLog !== undefined) {
opLogMetrics = p.metrics
}
if (id === undefined && p.id !== undefined) {
id = p.id
}
p = p.parent
}
const opLog = id !== undefined ? opLogMetrics?.opLog?.[id] : undefined
if (opLog !== undefined) {
opEntry = {
op: name,
start: performance.now(),
params: {},
end: -1
}
}
const result = op(ctx)
if (opEntry !== undefined && opLog !== undefined) {
void result.finally(() => {
if (opEntry !== undefined && opLog !== undefined) {
opEntry.end = performance.now()
opEntry.params = { ...params, ...(typeof fullParams === 'function' ? fullParams() : fullParams) }
opLog.ops.push(opEntry)
}
})
}
return result
}
-13
View File
@@ -1,13 +0,0 @@
export * from './context'
export * from './metrics'
export * from './types'
/**
* Return a current performance timestamp
*/
export const platformNow: () => number = () => performance.now()
/**
* Return a diff with previous performance snapshot with 2 digits after . max.
*/
export const platformNowDiff = (old: number): number => Math.round((performance.now() - old) * 100) / 100
-337
View File
@@ -1,337 +0,0 @@
// Basic performance metrics suite.
import { platformNow, type MetricsData } from '.'
import { type FullParamsType, type Metrics, type ParamsType } from './types'
/**
* @public
*/
export const globals: Metrics = newMetrics()
/**
* @public
* @returns
*/
export function newMetrics (): Metrics {
return {
operations: 0,
value: 0,
measurements: {},
params: {},
namedParams: {}
}
}
function getUpdatedTopResult (
current: Metrics['topResult'],
time: number,
params: FullParamsType
): Metrics['topResult'] {
if (time === 0) {
return current
}
const result: Metrics['topResult'] = current ?? []
const newValue = {
value: time,
params
}
if (result.length > 6) {
if (result[0].value < newValue.value) {
result[0] = newValue
return result
}
if (result[result.length - 1].value > newValue.value) {
result[result.length - 1] = newValue
return result
}
// Shift the middle
return [result[0], newValue, ...result.slice(1, 3), result[5]]
} else {
result.push(newValue)
return result
}
}
/**
* Measure with tree expansion. Operation counter will be added only to leaf's.
* @public
*/
export function measure (
metrics: Metrics,
params: ParamsType,
fullParams: FullParamsType | (() => FullParamsType) = {},
endOp?: (spend: number) => void
): () => void {
const st = platformNow()
return () => {
updateMeasure(metrics, st, params, fullParams, endOp)
}
}
export function updateMeasure (
metrics: Metrics,
st: number,
params: ParamsType,
fullParams: FullParamsType | (() => FullParamsType),
endOp?: (spend: number) => void,
value?: number,
override?: boolean
): void {
const ed = platformNow()
const fParams = typeof fullParams === 'function' ? fullParams() : fullParams
// Update params if required
const pparams = Object.entries(params)
if (pparams.length > 0) {
const [k, v] = pparams[0]
let params = metrics.params[k]
if (params === undefined) {
params = {}
metrics.params[k] = params
}
const vKey = `${v?.toString() ?? ''}`
let param = params[vKey]
if (param === undefined) {
param = {
operations: 0,
value: 0
}
params[vKey] = param
}
if (override === true) {
param.operations = value ?? ed - st
} else {
param.value += value ?? ed - st
param.operations++
}
// Do not update top results for params.
if (pparams.length > 1) {
// We need to update all other params as counters.
if (param.topResult === undefined) {
param.topResult = []
}
for (const [, v] of pparams.slice(1)) {
const r = (param.topResult ?? []).find((it) => it.params[`${v}`] === true)
if (r !== undefined) {
r.value += 1 // Counter of operations
r.time = (r.time ?? 0) + (value ?? ed - st)
} else {
param.topResult.push({ params: { [`${v}`]: true }, value: 1, time: value ?? ed - st })
}
}
param.topResult.sort((a, b) => b.value - a.value)
}
}
// Update leaf data
if (override === true) {
metrics.operations = value ?? ed - st
} else {
metrics.value += value ?? ed - st
metrics.operations++
}
metrics.topResult = getUpdatedTopResult(metrics.topResult, ed - st, fParams)
endOp?.(ed - st)
}
/**
* @public
*/
export function childMetrics (root: Metrics, path: string[]): Metrics {
const segments = path
let oop = root
for (const p of segments) {
const v = oop.measurements[p] ?? { operations: 0, value: 0, measurements: {}, params: {} }
oop.measurements[p] = v
oop = v
}
return oop
}
/**
* @public
*/
export function metricsAggregate (m: Metrics, limit: number = -1, roundMath: boolean = false): Metrics {
let ms = aggregateMetrics(m.measurements, limit)
// Use child overage, if there is no top level value specified.
const me = Object.entries(ms)
const sumVal: number =
(me.length === 0 ? m.value : 0) +
me
.filter((it) => !it[0].startsWith('#'))
.map((it) => it[1])
.reduce((p, v) => {
return p + v.value
}, 0)
if (limit !== -1) {
// We need to keep only top limit items in ms
if (Object.keys(ms).length > 0) {
const newMs: typeof ms = {}
let added = 0
for (const [k, v] of Object.entries(ms)) {
newMs[k] = v
added++
if (added >= limit) {
break
}
}
ms = newMs
}
}
return {
operations: m.operations,
measurements: ms,
params: m.params,
value: sumVal,
topResult: m.topResult,
namedParams: m.namedParams,
opLog: m.opLog
}
}
function aggregateMetrics (m: Record<string, Metrics>, limit: number = -1): Record<string, Metrics> {
const result: Record<string, Metrics> = {}
for (const [k, v] of Object.entries(m).sort((a, b) => b[1].value - a[1].value)) {
result[k] = metricsAggregate(v, limit)
}
return result
}
function toLen (val: string, sep: string, len: number): string {
while (val.length < len) {
val += sep
}
return val
}
function printMetricsChildren (params: Record<string, Metrics>, offset: number, length: number): string {
let r = ''
if (Object.keys(params).length > 0) {
r += '\n' + toLen('', ' ', offset)
r += Object.entries(params)
.filter((it) => it[1].value > 0.1)
.map(([k, vv]) => toString(k, vv, offset, length))
.join('\n' + toLen('', ' ', offset))
}
return r
}
function printMetricsParams (
params: Record<string, Record<string, MetricsData>>,
offset: number,
length: number
): string {
let r = ''
const joinP = (key: string, data: Record<string, MetricsData>): string[] => {
return Object.entries(data)
.filter((it) => it[1].value >= 0.1)
.map(([k, vv]) =>
`${toLen('', ' ', offset)}${toLen(key + '=' + k, '-', length - offset)}: avg ${
Math.round((vv.value / (vv.operations > 0 ? vv.operations : 1)) * 100) / 100
} total: ${Math.round(vv.value * 100) / 100} ops: ${vv.operations}`.trim()
)
}
const joinParams = Object.entries(params).reduce<string[]>((p, c) => [...p, ...joinP(c[0], c[1])], [])
if (Object.keys(joinParams).length > 0) {
r += '\n' + toLen('', ' ', offset)
r += joinParams.join('\n' + toLen('', ' ', offset))
}
return r
}
function toString (name: string, m: Metrics, offset: number, length: number): string {
let r = `${toLen('', ' ', offset)}${toLen(name, '-', length - offset)}: avg ${
Math.round((m.value / (m.operations > 0 ? m.operations : 1)) * 100) / 100
} total: ${Math.round(m.value * 100) / 100} ops: ${m.operations}`.trim()
r += printMetricsParams(m.params, offset + 4, length)
r += printMetricsChildren(m.measurements, offset + 4, length)
return r
}
function toJson (m: Metrics): any {
const obj: any = {
$total: m.value,
$ops: m.operations
}
if (m.operations > 1) {
obj.avg = Math.round((m.value / (m.operations > 0 ? m.operations : 1)) * 100) / 100
}
if (Object.keys(m.params).length > 0) {
obj.params = m.params
}
for (const [k, v] of Object.entries(m.measurements ?? {})) {
obj[
`${k} ${v.value} ${v.operations} ${
v.operations > 1 ? Math.round((v.value / (v.operations > 0 ? m.operations : 1)) * 100) / 100 : ''
}`
] = toJson(v)
}
return obj
}
/**
* @public
*/
export function metricsToString (metrics: Metrics, name = 'System', length: number): string {
return toString(name, metricsAggregate(metrics, 50, true), 0, length)
}
export function metricsToJson (metrics: Metrics): any {
return toJson(metricsAggregate(metrics))
}
function printMetricsParamsRows (
params: Record<string, Record<string, MetricsData>>,
offset: number
): (string | number)[][] {
const r: (string | number)[][] = []
function joinP (key: string, data: Record<string, MetricsData>): (string | number)[][] {
return Object.entries(data).map(([k, vv]) => [
offset,
`${key}=${k}`,
Math.round((vv.value / (vv.operations > 0 ? vv.operations : 1)) * 100) / 100,
Math.round(vv.value * 100) / 100,
vv.operations
])
}
for (const [k, v] of Object.entries(params)) {
r.push(...joinP(k, v))
}
return r
}
function printMetricsChildrenRows (params: Record<string, Metrics>, offset: number): (string | number)[][] {
const r: (string | number)[][] = []
if (Object.keys(params).length > 0) {
Object.entries(params).forEach(([k, vv]) => r.push(...toStringRows(k, vv, offset)))
}
return r
}
function toStringRows (name: string, m: Metrics, offset: number): (number | string)[][] {
const r: (number | string)[][] = [
[
offset,
name,
Math.round((m.value / (m.operations > 0 ? m.operations : 1)) * 100) / 100,
Math.round(m.value * 100) / 100,
m.operations
]
]
r.push(...printMetricsParamsRows(m.params, offset + 1))
r.push(...printMetricsChildrenRows(m.measurements, offset + 1))
return r
}
/**
* @public
*/
export function metricsToRows (metrics: Metrics, name = 'System'): (number | string)[][] {
return toStringRows(name, metricsAggregate(metrics, 50, true), 0)
}
-132
View File
@@ -1,132 +0,0 @@
/**
* @public
*/
export type ParamType = string | number | boolean | undefined
/**
* @public
*/
export type ParamsType = Record<string, ParamType>
/**
* @public
*/
export type FullParamsType = Record<string, any>
/**
* @public
*/
export interface MetricsData {
operations: number
value: number
topResult?: {
value: number
time?: number
params: FullParamsType
}[]
}
export interface OperationLogEntry {
op: string
params: ParamsType
start: number
end: number
}
export interface OperationLog {
ops: OperationLogEntry[]
start: number
end: number
}
/**
* @public
*/
export interface Metrics extends MetricsData {
namedParams: ParamsType
params: Record<string, Record<string, MetricsData>>
measurements: Record<string, Metrics>
opLog?: Record<string, OperationLog>
}
/**
* @public
*/
export interface MeasureLogger {
info: (message: string, obj?: Record<string, any>) => void
error: (message: string, obj?: Record<string, any>) => void
warn: (message: string, obj?: Record<string, any>) => void
logOperation: (operation: string, time: number, params: ParamsType) => void
childLogger?: (name: string, params: Record<string, any>) => MeasureLogger
close: () => Promise<void>
}
export interface WithOptions {
span?: true | false | 'disable' | 'skip' | 'inherit' // 'none' means no span will be created, 'disable' means context will be tracing disabled
log?: boolean
inheritParams?: boolean
// Passed context metadata
meta?: Record<string, string | number | boolean>
}
/**
* @public
*/
export interface MeasureContext<Q = any> {
id?: string
// Context data will be copied referenced for all child contexts.
contextData: Q
// Create a child metrics context
newChild: (
name: string,
params: ParamsType,
opt?: {
fullParams?: FullParamsType
logger?: MeasureLogger
span?: WithOptions['span'] // By default true
meta?: Record<string, string | number | boolean>
}
) => MeasureContext
metrics?: Metrics
with: <T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext<Q>) => T | Promise<T>,
fullParams?: FullParamsType | (() => FullParamsType),
opt?: WithOptions
) => Promise<T>
withSync: <T>(
name: string,
params: ParamsType,
op: (ctx: MeasureContext<Q>) => T,
fullParams?: FullParamsType | (() => FullParamsType),
opt?: WithOptions
) => T
extractMeta: () => Record<string, string | number | boolean>
logger: MeasureLogger
parent?: MeasureContext
getParams: () => ParamsType
measure: (name: string, value: number, override?: boolean) => void
// Capture error
error: (message: string, obj?: Record<string, any>) => void
info: (message: string, obj?: Record<string, any>) => void
warn: (message: string, obj?: Record<string, any>) => void
// Mark current context as complete
// If no value is passed, time difference will be used.
end: (value?: number) => void
}
-12
View File
@@ -1,12 +0,0 @@
{
"extends": "./node_modules/@hcengineering/platform-rig/profiles/default/tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./lib",
"declarationDir": "./types",
"tsBuildInfoFile": ".build/build.tsbuildinfo"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "lib", "dist", "types", "bundle"]
}
-10
View File
@@ -340,16 +340,6 @@
"projectFolder": "packages/platform",
"shouldPublish": true
},
{
"packageName": "@hcengineering/measurements",
"projectFolder": "packages/measurements",
"shouldPublish": true
},
{
"packageName": "@hcengineering/measurements-otlp",
"projectFolder": "packages/measurements-otlp",
"shouldPublish": true
},
{
"packageName": "@hcengineering/core",
"projectFolder": "packages/core",