commit 8cd250e8f8fa3ac23b28ab960a7e30c0614a62d6
parent 95053ec72011d16c922192e687ae5445e80260a1
Author: mtmn <miro@haravara.org>
Date: Sat, 18 Apr 2026 03:52:20 +0200
feat: add otel tracing
Diffstat:
5 files changed, 955 insertions(+), 13 deletions(-)
diff --git a/package-lock.json b/package-lock.json
@@ -9,6 +9,9 @@
"version": "1.0.0",
"dependencies": {
"@aws-sdk/client-s3": "^3.1029.0",
+ "@opentelemetry/api": "^1.9.1",
+ "@opentelemetry/exporter-trace-otlp-http": "^0.215.0",
+ "@opentelemetry/sdk-node": "^0.215.0",
"dotenv": "^17.4.1",
"duckdb": "^1.4.4",
"prom-client": "^15.1.3"
@@ -1323,6 +1326,61 @@
"integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
"license": "MIT"
},
+ "node_modules/@grpc/grpc-js": {
+ "version": "1.14.3",
+ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz",
+ "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@grpc/proto-loader": "^0.8.0",
+ "@js-sdsl/ordered-map": "^4.4.2"
+ },
+ "engines": {
+ "node": ">=12.10.0"
+ }
+ },
+ "node_modules/@grpc/proto-loader": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz",
+ "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "lodash.camelcase": "^4.3.0",
+ "long": "^5.0.0",
+ "protobufjs": "^7.5.3",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@grpc/proto-loader/node_modules/protobufjs": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz",
+ "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/node": ">=13.7.0",
+ "long": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
@@ -1354,6 +1412,16 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/@js-sdsl/ordered-map": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
+ "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/js-sdsl"
+ }
+ },
"node_modules/@mapbox/node-pre-gyp": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.3.tgz",
@@ -1449,6 +1517,575 @@
"node": ">=8.0.0"
}
},
+ "node_modules/@opentelemetry/api-logs": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.215.0.tgz",
+ "integrity": "sha512-xrFlqhdhUyO8wSRn6DjE0145/HPWSJ5Nm0C7vWua6TdL/FSEAZvEyvdsa9CRXuxo9ebb7j/NEPhEcO62IJ0qUA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/@opentelemetry/configuration": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/configuration/-/configuration-0.215.0.tgz",
+ "integrity": "sha512-FSWvDryxjinHROfzEVbJGBw10FqGzLEm2C1LPX6Lot6hvxq3lFJzNLlue8vm64C5yIbqSQVjWsPhYu56ThQS4Q==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "yaml": "^2.0.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.9.0"
+ }
+ },
+ "node_modules/@opentelemetry/context-async-hooks": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.0.tgz",
+ "integrity": "sha512-MWXggArM+Y11mPS8VOrqxOj+YMGQSRuvhM91eSBX4xFpJa05mpkeVvM8pPux5ElkEjV5RMgrkisrlP/R83SpBQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.0.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/core": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.0.tgz",
+ "integrity": "sha512-DT12SXVwV2eoJrGf4nnsvZojxxeQo+LlNAsoYGRRObPWTeN6APiqZ2+nqDCQDvQX40eLi1AePONS0onoASp3yQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/semantic-conventions": "^1.29.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.0.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-logs-otlp-grpc": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.215.0.tgz",
+ "integrity": "sha512-MVq+9ma/63XRXc0AcnS+XyWSD6VBYn39OucsvpzjqxTpzTOiGXNxTwsbV3zbnvgUexb5hc2ZjJlZUK2W/19UUw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@grpc/grpc-js": "^1.14.3",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-grpc-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/sdk-logs": "0.215.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-logs-otlp-http": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.215.0.tgz",
+ "integrity": "sha512-U7Qb+TVX2GZH5RSC+Gx9aE5zChKP1kPg87X3PlI/41lWVPJdBIzmgMmuE28MmQlrK84nLHCIqUOOben8YkSzBw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api-logs": "0.215.0",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/sdk-logs": "0.215.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-logs-otlp-proto": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.215.0.tgz",
+ "integrity": "sha512-vs2xKKTdt/vKWMuBzw+LZYYCKqulodCRoonWWiyToIQfa6JgbyWjTu/iy6qpBLhLi+t6fNc1bwJGwu3vkot2Jg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api-logs": "0.215.0",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-logs": "0.215.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.215.0.tgz",
+ "integrity": "sha512-1TAMliHQvzc+v1OtnLMHSk5sU8BSkJbxIKrWzuCWcQjajWrvem/r5ugLK6agI0PjPz/ADfZju5AVYedlNyeO9g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@grpc/grpc-js": "^1.14.3",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/exporter-metrics-otlp-http": "0.215.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-grpc-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-metrics": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-metrics-otlp-http": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.215.0.tgz",
+ "integrity": "sha512-FRydO5j7MWnXK9ghfykKxiSM8I5UeiicK/UNl3/mv86xoEKkb+LKz1I3WXgkuYVOQf22VNqbPO58s2W1mVWtEQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-metrics": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-metrics-otlp-proto": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.215.0.tgz",
+ "integrity": "sha512-d8/Sys9MtxLbn0S+RE1pUNcuoI9ZyI4SPfOO+yskSEQiPFoKCTMwwthB8MTY4S8qxCBAWyM+P7QMX+vEIT7PZw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/exporter-metrics-otlp-http": "0.215.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-metrics": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-prometheus": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.215.0.tgz",
+ "integrity": "sha512-7ghCl1G84jccmxG3B8UwUMZ1OlequBzB1jt5tZ4DDiAyVKeA4Roz5D6VK8SQ0ZyBQffVyX/rtXrpVXKVzRCGfg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-metrics": "2.7.0",
+ "@opentelemetry/semantic-conventions": "^1.29.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-trace-otlp-grpc": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.215.0.tgz",
+ "integrity": "sha512-+SuWfPFVjPTvHJhlzTCBetLsPVu86xSFPR3fv8TN+H7lpe5aZzF96TUsfMHDR0lwpIwlJpG57CJnGalIfrpXkg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@grpc/grpc-js": "^1.14.3",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-grpc-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-trace-otlp-http": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.215.0.tgz",
+ "integrity": "sha512-k4J9ISeGpb0Bm/wCrlcrbroMFTkiWMrdhNxQGrlktxLy127Yzd4/7nrTawn5d/ApktYTknvdixsE6++34Qfi1w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-trace-otlp-proto": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.215.0.tgz",
+ "integrity": "sha512-+QclHuJmlp/I3Z2fNn+j1dAajMjJqJ4Sgo8ajwiK6Tzmg5SNwBGmBX66AZvTLe/3/bc3L7bo90m9gsaJBrzEsA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/exporter-zipkin": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.7.0.tgz",
+ "integrity": "sha512-tbzcYDmZWtX4hgJn15qP7/iYFVd1yzbUloBuSYsQtn0XQTxJsG7vgwkPKEBellriH0XJmlZJxYtWkHpwzHBhaQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0",
+ "@opentelemetry/semantic-conventions": "^1.29.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.0.0"
+ }
+ },
+ "node_modules/@opentelemetry/instrumentation": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.215.0.tgz",
+ "integrity": "sha512-SyJONuqypQ2xWdYMy99vF7JhZ2kDTGx4oRmM/jZV+kRtZ96JTnJmEINbIJgHz7Gnhtw0bimHwbPy/pguA5wpPQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api-logs": "0.215.0",
+ "import-in-the-middle": "^3.0.0",
+ "require-in-the-middle": "^8.0.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/otlp-exporter-base": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.215.0.tgz",
+ "integrity": "sha512-lHrfbmeLSmesGSkkHiqDwOzfaEMSWXdc7q6UoLfbW8byONCb+bE/zkAr0kapN4US1baT/2nbpNT7Cn9XoB96Vg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-transformer": "0.215.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/otlp-grpc-exporter-base": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.215.0.tgz",
+ "integrity": "sha512-WkuHkUrhwNxTKrm7Xuf6S+HmLNbk2T8S2YiZhN606RfgetSQb9xLp4NizWLwXvw63uxGsBaK262dirFO2yht2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@grpc/grpc-js": "^1.14.3",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/otlp-transformer": "0.215.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/otlp-transformer": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.215.0.tgz",
+ "integrity": "sha512-cWwBvaV+vkXHkSoTYR8hGw+AW03UlgTr6xtrUKOMeum3T+8vffYXIfXu6KY5MLu8O9QtoBKqaKWw9I5xoOepng==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api-logs": "0.215.0",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-logs": "0.215.0",
+ "@opentelemetry/sdk-metrics": "2.7.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0",
+ "protobufjs": "^8.0.1"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.3.0"
+ }
+ },
+ "node_modules/@opentelemetry/propagator-b3": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.7.0.tgz",
+ "integrity": "sha512-HNm+tdXY5i8dzAo4YankchNWdZ4Z1Boop7lhbb3wltWT0MwEMo0QADRJwrF83pXEeDT+5Bmq4J8sStFaUywE3g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.0.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/propagator-jaeger": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.7.0.tgz",
+ "integrity": "sha512-lKMAjekRkFYWrjmPTaxUJt+V8Mr1iB94sP3HDZZCmdZ/LUV/wtqAGqXhgnkIbdlnWxxvEs9MGEIMdJC+xObMFg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.0.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/resources": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.0.tgz",
+ "integrity": "sha512-K+oi0hNMv94EpZbnW3eyu2X6SGVpD3O5DhG2NIp65Hc7lhAj9brRXTAVzh3wB82+q3ThakEf7Zd7RsFUqcTc7A==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/semantic-conventions": "^1.29.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.3.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/sdk-logs": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.215.0.tgz",
+ "integrity": "sha512-y3ucOmphzc4vgBTyIGchs+N/1rkACmoka8QalT2z1LBNM232Z17zMYayHcMl+dgMoOadZ0b72UZv7mDtqy1cFA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api-logs": "0.215.0",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/semantic-conventions": "^1.29.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.4.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/sdk-metrics": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.0.tgz",
+ "integrity": "sha512-Vd7h95av/LYRsAVN7wbprvvJnHkq7swMXAo7Uad0Uxf9jl6NSReLa0JNivrcc5BVIx/vl2t+cgdVQQbnVhsR9w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/resources": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.9.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/sdk-node": {
+ "version": "0.215.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.215.0.tgz",
+ "integrity": "sha512-YunKvZOMhYNMBJ66YRjbGShuoV/w1y21U7MGPRx0iPJenPszOddtYEQFJv8piAEOn94BUFIfJHtHjptrHsGiIA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/api-logs": "0.215.0",
+ "@opentelemetry/configuration": "0.215.0",
+ "@opentelemetry/context-async-hooks": "2.7.0",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/exporter-logs-otlp-grpc": "0.215.0",
+ "@opentelemetry/exporter-logs-otlp-http": "0.215.0",
+ "@opentelemetry/exporter-logs-otlp-proto": "0.215.0",
+ "@opentelemetry/exporter-metrics-otlp-grpc": "0.215.0",
+ "@opentelemetry/exporter-metrics-otlp-http": "0.215.0",
+ "@opentelemetry/exporter-metrics-otlp-proto": "0.215.0",
+ "@opentelemetry/exporter-prometheus": "0.215.0",
+ "@opentelemetry/exporter-trace-otlp-grpc": "0.215.0",
+ "@opentelemetry/exporter-trace-otlp-http": "0.215.0",
+ "@opentelemetry/exporter-trace-otlp-proto": "0.215.0",
+ "@opentelemetry/exporter-zipkin": "2.7.0",
+ "@opentelemetry/instrumentation": "0.215.0",
+ "@opentelemetry/otlp-exporter-base": "0.215.0",
+ "@opentelemetry/propagator-b3": "2.7.0",
+ "@opentelemetry/propagator-jaeger": "2.7.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/sdk-logs": "0.215.0",
+ "@opentelemetry/sdk-metrics": "2.7.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0",
+ "@opentelemetry/sdk-trace-node": "2.7.0",
+ "@opentelemetry/semantic-conventions": "^1.29.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.3.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/sdk-trace-base": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.0.tgz",
+ "integrity": "sha512-Yg9zEXJB50DLVLpsKPk7NmNqlPlS+OvqhJGh0A8oawIOTPOwlm4eXs9BMJV7L79lvEwI+dWtAj+YjTyddV336A==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/resources": "2.7.0",
+ "@opentelemetry/semantic-conventions": "^1.29.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.3.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/sdk-trace-node": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.0.tgz",
+ "integrity": "sha512-RrFHOXw0IYp/OThew6QORdybnnLitUAUMCJKcQNBYS0hDkCYarO2vTkVxfrGxCIqd5XHSMvbCpBd/T8ZMw8oSg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@opentelemetry/context-async-hooks": "2.7.0",
+ "@opentelemetry/core": "2.7.0",
+ "@opentelemetry/sdk-trace-base": "2.7.0"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.6.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": ">=1.0.0 <1.10.0"
+ }
+ },
+ "node_modules/@opentelemetry/semantic-conventions": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz",
+ "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/codegen": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/eventemitter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/fetch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.1",
+ "@protobufjs/inquire": "^1.1.0"
+ }
+ },
+ "node_modules/@protobufjs/float": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/inquire": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/utf8": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/@smithy/chunked-blob-reader": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.2.tgz",
@@ -2177,6 +2814,15 @@
"node": ">= 10"
}
},
+ "node_modules/@types/node": {
+ "version": "25.6.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
+ "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.19.0"
+ }
+ },
"node_modules/abbrev": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz",
@@ -2186,6 +2832,27 @@
"node": "^18.17.0 || >=20.5.0"
}
},
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-import-attributes": {
+ "version": "1.9.5",
+ "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
+ "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^8"
+ }
+ },
"node_modules/agent-base": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
@@ -2585,6 +3252,12 @@
"node": ">=10"
}
},
+ "node_modules/cjs-module-lexer": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz",
+ "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==",
+ "license": "MIT"
+ },
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -2607,6 +3280,70 @@
"node": ">=8"
}
},
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/cliui/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/cliui/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/cliui/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -3103,6 +3840,15 @@
"@esbuild/win32-x64": "0.28.0"
}
},
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -3504,6 +4250,15 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
"node_modules/get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
@@ -3688,6 +4443,21 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/import-in-the-middle": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.0.1.tgz",
+ "integrity": "sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-import-attributes": "^1.9.5",
+ "cjs-module-lexer": "^2.2.0",
+ "module-details-from-path": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -3947,6 +4717,12 @@
"uc.micro": "^2.0.0"
}
},
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "license": "MIT"
+ },
"node_modules/log-symbols": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
@@ -3979,6 +4755,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/long": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
+ "license": "Apache-2.0"
+ },
"node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
@@ -4278,6 +5060,12 @@
"node": ">=10"
}
},
+ "node_modules/module-details-from-path": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz",
+ "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==",
+ "license": "MIT"
+ },
"node_modules/move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -4755,6 +5543,30 @@
"node": ">=10"
}
},
+ "node_modules/protobufjs": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.0.1.tgz",
+ "integrity": "sha512-NWWCCscLjs+cOKF/s/XVNFRW7Yih0fdH+9brffR5NZCy8k42yRdl5KlWKMVXuI1vfCoy4o1z80XR/W/QUb3V3w==",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/node": ">=13.7.0",
+ "long": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/psl": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
@@ -5166,6 +5978,28 @@
"uuid": "bin/uuid"
}
},
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-in-the-middle": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz",
+ "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "module-details-from-path": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=9.3.0 || >=8.10.0 <9.0.0"
+ }
+ },
"node_modules/restore-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
@@ -5968,6 +6802,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/undici-types": {
+ "version": "7.19.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
+ "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
+ "license": "MIT"
+ },
"node_modules/unique-filename": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
@@ -6269,7 +7109,6 @@
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
- "dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
@@ -6281,6 +7120,42 @@
"url": "https://github.com/sponsors/eemeli"
}
},
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs/node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/zen-observable": {
"version": "0.8.15",
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
diff --git a/package.json b/package.json
@@ -5,7 +5,7 @@
"main": "index.js",
"type": "module",
"scripts": {
- "build": "npx spago build && npx purs-backend-es build && npx esbuild output-es/Main/index.js --bundle --platform=node --format=esm --footer:js='main();' --outfile=server.js --external:http --external:https --external:dotenv --external:url --external:duckdb --external:@aws-sdk/client-s3 --external:prom-client && elm make src/Client.elm --output=client.js",
+ "build": "npx spago build && npx purs-backend-es build && npx esbuild output-es/Main/index.js --bundle --platform=node --format=esm --footer:js='main();' --outfile=server.js --external:http --external:https --external:dotenv --external:url --external:duckdb --external:@aws-sdk/client-s3 --external:prom-client --external:@opentelemetry/* && elm make src/Client.elm --output=client.js",
"test": "npx spago test",
"tidy": "purs-tidy format-in-place src/**/*.purs"
},
@@ -21,6 +21,9 @@
},
"dependencies": {
"@aws-sdk/client-s3": "^3.1029.0",
+ "@opentelemetry/api": "^1.9.1",
+ "@opentelemetry/exporter-trace-otlp-http": "^0.215.0",
+ "@opentelemetry/sdk-node": "^0.215.0",
"dotenv": "^17.4.1",
"duckdb": "^1.4.4",
"prom-client": "^15.1.3"
diff --git a/src/Main.purs b/src/Main.purs
@@ -803,7 +803,7 @@ handleRequest contexts req res = do
Nothing -> serveNotFound res
Just url -> do
let path = URL.pathname url
- Metrics.observeHttpRequest method (normalizePath path) Log.info res
+ Metrics.observeHttpRequest method (normalizePath path) Log.info req res
case path of
"/client.js" -> serveClientJs res
"/favicon.png" -> serveAsset "image/png" "assets/favicon.png" res
diff --git a/src/Metrics.js b/src/Metrics.js
@@ -5,6 +5,19 @@ import {
Histogram,
collectDefaultMetrics,
} from "prom-client";
+import { NodeSDK } from "@opentelemetry/sdk-node";
+import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
+import {
+ trace,
+ context,
+ propagation,
+ SpanKind,
+ SpanStatusCode,
+} from "@opentelemetry/api";
+
+// ---------------------------------------------------------------------------
+// Prometheus metrics
+// ---------------------------------------------------------------------------
const registry = new Registry();
@@ -81,6 +94,53 @@ const dbBackupLastSuccessSeconds = new Gauge({
registers: [registry],
});
+// ---------------------------------------------------------------------------
+// OpenTelemetry — only active when OTEL_EXPORTER_OTLP_ENDPOINT is set
+// ---------------------------------------------------------------------------
+
+let tracer = null;
+
+if (process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {
+ const sdk = new NodeSDK({
+ traceExporter: new OTLPTraceExporter(),
+ });
+ sdk.start();
+ tracer = trace.getTracer(
+ process.env.OTEL_SERVICE_NAME || "corpus",
+ process.env.npm_package_version,
+ );
+ process.on("SIGTERM", () => sdk.shutdown().finally(() => process.exit(0)));
+}
+
+function startHttpSpan(method, path, headers) {
+ if (!tracer) return null;
+ const parentCtx = propagation.extract(context.active(), headers);
+ return tracer.startSpan(
+ `${method} ${path}`,
+ {
+ kind: SpanKind.SERVER,
+ attributes: {
+ "http.method": method,
+ "http.target": path,
+ },
+ },
+ parentCtx,
+ );
+}
+
+function endHttpSpan(span, statusCode) {
+ if (!span) return;
+ span.setAttribute("http.status_code", statusCode);
+ span.setStatus({
+ code: statusCode >= 500 ? SpanStatusCode.ERROR : SpanStatusCode.OK,
+ });
+ span.end();
+}
+
+// ---------------------------------------------------------------------------
+// Exports
+// ---------------------------------------------------------------------------
+
export const getMetricsImpl = (onSuccess) => (onError) => () => {
registry.metrics().then(
(s) => onSuccess(s)(),
@@ -90,18 +150,21 @@ export const getMetricsImpl = (onSuccess) => (onError) => () => {
export const getContentType = () => registry.contentType;
-// Attaches a 'finish' listener to the response to record latency and status
-// after the response is fully written. Safe to call before routing.
-// logFn: (String -> Effect Unit) — the structured logger to call on completion.
+// Attaches a 'finish' listener to `res` so that, once the response is fully
+// written, the request count, latency histogram, and OTEL span are updated.
+// logFn: String -> Effect Unit — the structured logger to call on completion.
+// req: Node IncomingMessage — used to extract W3C trace-context headers.
export const observeHttpRequest =
- (method) => (path) => (logFn) => (res) => () => {
+ (method) => (path) => (logFn) => (req) => (res) => () => {
const startMs = Date.now();
+ const span = startHttpSpan(method, path, req.headers || {});
res.once("finish", () => {
const durationMs = Date.now() - startMs;
const durationSecs = durationMs / 1000;
- const status = String(res.statusCode || 0);
- httpRequestsTotal.inc({ method, path, status });
+ const status = res.statusCode || 0;
+ httpRequestsTotal.inc({ method, path, status: String(status) });
httpRequestDurationSeconds.observe({ method, path }, durationSecs);
+ endHttpSpan(span, status);
logFn(`${method} ${path} ${status} ${durationMs}ms`)();
});
};
diff --git a/src/Metrics.purs b/src/Metrics.purs
@@ -6,7 +6,7 @@ import Data.Either (Either(..))
import Effect (Effect)
import Effect.Aff (Aff, makeAff, nonCanceler)
import Effect.Exception (error)
-import Node.HTTP.Types (ServerResponse)
+import Node.HTTP.Types (IMServer, IncomingMessage, ServerResponse)
-- | Async: serialises all registered metrics to Prometheus text format.
foreign import getMetricsImpl :: (String -> Effect Unit) -> (String -> Effect Unit) -> Effect Unit
@@ -15,10 +15,11 @@ foreign import getMetricsImpl :: (String -> Effect Unit) -> (String -> Effect Un
foreign import getContentType :: Effect String
-- | Attaches a 'finish' listener to `res` so that, once the response is
--- | fully written, the request count and latency histogram are updated,
--- | and the provided log function is called with "METHOD path status Nms".
+-- | fully written, the request count, latency histogram, and OTEL span are
+-- | updated, and logFn is called with "METHOD path status Nms".
+-- | W3C trace-context headers are extracted from `req` for span parenting.
-- | Call once at the top of the request handler before routing.
-foreign import observeHttpRequest :: String -> String -> (String -> Effect Unit) -> ServerResponse -> Effect Unit
+foreign import observeHttpRequest :: String -> String -> (String -> Effect Unit) -> IncomingMessage IMServer -> ServerResponse -> Effect Unit
-- Sync
foreign import incSyncRuns :: String -> String -> String -> Effect Unit