From 510a5d554470c3160190687c8a20b9c2f04628a5 Mon Sep 17 00:00:00 2001 From: Thomas Flament Date: Thu, 2 Apr 2026 16:58:27 +0200 Subject: [PATCH 1/7] feat: add OpenTelemetry SDK setup with feature flag Set up the NodeSDK with OTLP/HTTP trace exporter, gated behind ENABLE_OTEL=true. Uses 1% sampling by default to limit collector load. Auto-instruments HTTP, Express and MongoDB while disabling high-volume fs and Redis instrumentations. Issue: CLDSRV-884 --- index.js | 3 + lib/otel.js | 62 +++ package.json | 9 +- yarn.lock | 1278 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 1348 insertions(+), 4 deletions(-) create mode 100644 lib/otel.js diff --git a/index.js b/index.js index f5fa36c2e2..d6de0f0a44 100644 --- a/index.js +++ b/index.js @@ -7,4 +7,7 @@ require('werelogs').stderrUtils.catchAndTimestampStderr( require('cluster').isPrimary ? 1 : null, ); +// Initialize OpenTelemetry SDK before everything else +require('./lib/otel.js'); + require('./lib/server.js')(); diff --git a/lib/otel.js b/lib/otel.js new file mode 100644 index 0000000000..9823333eed --- /dev/null +++ b/lib/otel.js @@ -0,0 +1,62 @@ +'use strict'; + +const enableOtel = process.env.ENABLE_OTEL === 'true'; + +let sdk = null; + +if (enableOtel) { + const { NodeSDK } = require('@opentelemetry/sdk-node'); + const { Resource } = require('@opentelemetry/resources'); + const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http'); + const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); + const { TraceIdRatioBasedSampler } = require('@opentelemetry/sdk-trace-base'); + const { version } = require('../package.json'); + + const exportUrl = process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || + 'http://otel-collector.default.svc.cluster.local:4318/v1/traces'; + + const traceExporter = new OTLPTraceExporter({ + url: exportUrl, + }); + + const parsedRatio = parseFloat(process.env.OTEL_SAMPLING_RATIO); + const samplingRatio = Number.isFinite(parsedRatio) ? parsedRatio : 0.01; + + sdk = new NodeSDK({ + resource: new Resource({ + 'service.name': process.env.OTEL_SERVICE_NAME || 'cloudserver', + 'service.version': process.env.OTEL_SERVICE_VERSION || version, + 'service.namespace': process.env.OTEL_SERVICE_NAMESPACE || 'scality', + }), + traceExporter, + sampler: new TraceIdRatioBasedSampler(samplingRatio), + instrumentations: [ + getNodeAutoInstrumentations({ + '@opentelemetry/instrumentation-fs': { enabled: false }, + '@opentelemetry/instrumentation-redis': { enabled: false }, + '@opentelemetry/instrumentation-redis-4': { enabled: false }, + '@opentelemetry/instrumentation-ioredis': { + enabled: true, + requireParentSpan: true, + }, + '@opentelemetry/instrumentation-http': { enabled: true }, + '@opentelemetry/instrumentation-express': { enabled: true }, + '@opentelemetry/instrumentation-mongodb': { + enabled: true, + enhancedDatabaseReporting: true, + useCollectionName: false, + captureCommandDetails: false, + }, + '@opentelemetry/instrumentation-aws-sdk': { enabled: false }, + }), + ], + }); + + sdk.start(); + + const shutdown = () => sdk.shutdown().catch(() => {}); + process.on('SIGTERM', shutdown); + process.on('SIGINT', shutdown); +} + +module.exports = { sdk }; diff --git a/package.json b/package.json index 10d2ecfc88..d4f028beba 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,12 @@ "@aws-sdk/signature-v4": "^3.374.0", "@azure/storage-blob": "^12.28.0", "@hapi/joi": "^17.1.1", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/auto-instrumentations-node": "^0.50.2", + "@opentelemetry/exporter-trace-otlp-http": "^0.55.0", + "@opentelemetry/resources": "^1.30.1", + "@opentelemetry/sdk-node": "^0.55.0", + "@opentelemetry/sdk-trace-base": "^1.28.0", "@smithy/node-http-handler": "^3.0.0", "arsenal": "git+https://github.com/scality/Arsenal#8.3.9", "async": "2.6.4", @@ -85,7 +91,8 @@ "resolutions": { "jsonwebtoken": "^9.0.0", "nan": "v2.22.0", - "fast-xml-parser": "^5.5.6" + "fast-xml-parser": "^5.5.6", + "@types/pg": "8.6.1" }, "mocha": { "recursive": true, diff --git a/yarn.lock b/yarn.lock index 07c99fcdc3..6d9697cc79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3209,6 +3209,24 @@ "@eslint/core" "^0.12.0" levn "^0.4.1" +"@grpc/grpc-js@^1.7.1": + version "1.14.3" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.14.3.tgz#4c9b817a900ae4020ddc28515ae4b52c78cfb8da" + integrity sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA== + dependencies: + "@grpc/proto-loader" "^0.8.0" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.8.0.tgz#b6c324dd909c458a0e4aa9bfd3d69cf78a4b9bd8" + integrity sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.5.3" + yargs "^17.7.2" + "@hapi/address@^4.0.1": version "4.1.0" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.1.0.tgz#d60c5c0d930e77456fdcde2598e77302e2955e1d" @@ -3383,6 +3401,11 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@js-sdsl/ordered-set@^4.4.2": version "4.4.2" resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-set/-/ordered-set-4.4.2.tgz#ab857eb63cf358b5a0f74fdd458b4601423779b7" @@ -3420,16 +3443,1026 @@ dependencies: semver "^7.3.5" +"@opentelemetry/api-logs@0.53.0", "@opentelemetry/api-logs@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.53.0.tgz#c478cbd8120ec2547b64edfa03a552cfe42170be" + integrity sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw== + dependencies: + "@opentelemetry/api" "^1.0.0" + +"@opentelemetry/api-logs@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.55.0.tgz#5cd7461820d864600250deb3803c32367a6bb2d2" + integrity sha512-3cpa+qI45VHYcA5c0bHM6VHo9gicv3p5mlLHNG3rLyjQU8b7e0st1rWtrUn3JbZ3DwwCfhKop4eQ9UuYlC6Pkg== + dependencies: + "@opentelemetry/api" "^1.3.0" + +"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.9.0": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.1.tgz#c1b0346de336ba55af2d5a7970882037baedec05" + integrity sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q== + "@opentelemetry/api@^1.4.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== +"@opentelemetry/auto-instrumentations-node@^0.50.2": + version "0.50.2" + resolved "https://registry.yarnpkg.com/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.50.2.tgz#fe94c131bee6de0b5c822d2bf1fff857b0f1b8c0" + integrity sha512-l1JWvNp5gt5Fze8X68+zjzBqiviB5B8zeepsbfpFgdDxoCVjmixg8gcMt/AmqI9Qntw2qaeXah84V14fCbVuMg== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/instrumentation-amqplib" "^0.42.0" + "@opentelemetry/instrumentation-aws-lambda" "^0.45.0" + "@opentelemetry/instrumentation-aws-sdk" "^0.44.0" + "@opentelemetry/instrumentation-bunyan" "^0.41.0" + "@opentelemetry/instrumentation-cassandra-driver" "^0.41.0" + "@opentelemetry/instrumentation-connect" "^0.39.0" + "@opentelemetry/instrumentation-cucumber" "^0.9.0" + "@opentelemetry/instrumentation-dataloader" "^0.12.0" + "@opentelemetry/instrumentation-dns" "^0.39.0" + "@opentelemetry/instrumentation-express" "^0.43.0" + "@opentelemetry/instrumentation-fastify" "^0.40.0" + "@opentelemetry/instrumentation-fs" "^0.15.0" + "@opentelemetry/instrumentation-generic-pool" "^0.39.0" + "@opentelemetry/instrumentation-graphql" "^0.43.0" + "@opentelemetry/instrumentation-grpc" "^0.53.0" + "@opentelemetry/instrumentation-hapi" "^0.41.0" + "@opentelemetry/instrumentation-http" "^0.53.0" + "@opentelemetry/instrumentation-ioredis" "^0.43.0" + "@opentelemetry/instrumentation-kafkajs" "^0.3.0" + "@opentelemetry/instrumentation-knex" "^0.40.0" + "@opentelemetry/instrumentation-koa" "^0.43.0" + "@opentelemetry/instrumentation-lru-memoizer" "^0.40.0" + "@opentelemetry/instrumentation-memcached" "^0.39.0" + "@opentelemetry/instrumentation-mongodb" "^0.47.0" + "@opentelemetry/instrumentation-mongoose" "^0.42.0" + "@opentelemetry/instrumentation-mysql" "^0.41.0" + "@opentelemetry/instrumentation-mysql2" "^0.41.0" + "@opentelemetry/instrumentation-nestjs-core" "^0.40.0" + "@opentelemetry/instrumentation-net" "^0.39.0" + "@opentelemetry/instrumentation-pg" "^0.45.1" + "@opentelemetry/instrumentation-pino" "^0.42.0" + "@opentelemetry/instrumentation-redis" "^0.42.0" + "@opentelemetry/instrumentation-redis-4" "^0.42.1" + "@opentelemetry/instrumentation-restify" "^0.41.0" + "@opentelemetry/instrumentation-router" "^0.40.0" + "@opentelemetry/instrumentation-socket.io" "^0.42.0" + "@opentelemetry/instrumentation-tedious" "^0.14.0" + "@opentelemetry/instrumentation-undici" "^0.6.0" + "@opentelemetry/instrumentation-winston" "^0.40.0" + "@opentelemetry/resource-detector-alibaba-cloud" "^0.29.3" + "@opentelemetry/resource-detector-aws" "^1.6.2" + "@opentelemetry/resource-detector-azure" "^0.2.11" + "@opentelemetry/resource-detector-container" "^0.4.3" + "@opentelemetry/resource-detector-gcp" "^0.29.12" + "@opentelemetry/resources" "^1.24.0" + "@opentelemetry/sdk-node" "^0.53.0" + +"@opentelemetry/context-async-hooks@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.26.0.tgz#fa92f722cf685685334bba95f258d3ef9fce60f6" + integrity sha512-HedpXXYzzbaoutw6DFLWLDket2FwLkLpil4hGCZ1xYEIMTcivdfwEOISgdbLEWyG3HW52gTq2V9mOVJrONgiwg== + +"@opentelemetry/context-async-hooks@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/context-async-hooks/-/context-async-hooks-1.28.0.tgz#287afda2b75cb226f70d433244c3ef6f6dd8abdd" + integrity sha512-igcl4Ve+F1N2063PJUkesk/GkYyuGIWinYkSyAFTnIj3gzrOgvOA4k747XNdL47HRRL1w/qh7UW8NDuxOLvKFA== + +"@opentelemetry/core@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.26.0.tgz#7d84265aaa850ed0ca5813f97d831155be42b328" + integrity sha512-1iKxXXE8415Cdv0yjG3G6hQnB5eVEsJce3QaawX8SjDn0mAS0ZM8fAbZZJD4ajvhC15cePvosSCut404KrIIvQ== + dependencies: + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/core@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.28.0.tgz#e97290a3e36c59480ffb2287fe2713c66749274c" + integrity sha512-ZLwRMV+fNDpVmF2WYUdBHlq0eOWtEaUJSusrzjGnBt7iSRvfjFE3RXYUZJrqou/wIDWV0DwQ5KIfYe9WXg9Xqw== + dependencies: + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/core@1.30.1", "@opentelemetry/core@^1.0.0", "@opentelemetry/core@^1.1.0", "@opentelemetry/core@^1.25.0", "@opentelemetry/core@^1.25.1", "@opentelemetry/core@^1.26.0", "@opentelemetry/core@^1.8.0": + version "1.30.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.30.1.tgz#a0b468bb396358df801881709ea38299fc30ab27" + integrity sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ== + dependencies: + "@opentelemetry/semantic-conventions" "1.28.0" + +"@opentelemetry/exporter-logs-otlp-grpc@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.53.0.tgz#cc2514acbff2a41fa428c8b8e81ca386027890e2" + integrity sha512-x5ygAQgWAQOI+UOhyV3z9eW7QU2dCfnfOuIBiyYmC2AWr74f6x/3JBnP27IAcEx6aihpqBYWKnpoUTztkVPAZw== + dependencies: + "@grpc/grpc-js" "^1.7.1" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.53.0" + "@opentelemetry/otlp-transformer" "0.53.0" + "@opentelemetry/sdk-logs" "0.53.0" + +"@opentelemetry/exporter-logs-otlp-grpc@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.55.0.tgz#192b41e6f1fd3db9ef834ddb9fa41993865467fe" + integrity sha512-ykqawCL0ILJWyCJlxCPSAlqQXZ6x2bQsxAVUu8S3z22XNqY5SMx0rl2d93XnvnrOwtcfm+sM9ZhbGh/i5AZ9xw== + dependencies: + "@grpc/grpc-js" "^1.7.1" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.55.0" + "@opentelemetry/otlp-transformer" "0.55.0" + "@opentelemetry/sdk-logs" "0.55.0" + +"@opentelemetry/exporter-logs-otlp-http@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.53.0.tgz#1b4a152ea427ec4581532880fd0d620cc559cb11" + integrity sha512-cSRKgD/n8rb+Yd+Cif6EnHEL/VZg1o8lEcEwFji1lwene6BdH51Zh3feAD9p2TyVoBKrl6Q9Zm2WltSp2k9gWQ== + dependencies: + "@opentelemetry/api-logs" "0.53.0" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-exporter-base" "0.53.0" + "@opentelemetry/otlp-transformer" "0.53.0" + "@opentelemetry/sdk-logs" "0.53.0" + +"@opentelemetry/exporter-logs-otlp-http@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.55.0.tgz#d9879d36cdf5a114fae662a7f83ef832bdee4cf0" + integrity sha512-fpFObWWq+DoLVrBU2dyMEaVkibByEkmKQZIUIjW/4j7lwIsTgW7aJCoD9RYFVB/tButcqov5Es2C0J2wTjM2tg== + dependencies: + "@opentelemetry/api-logs" "0.55.0" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-exporter-base" "0.55.0" + "@opentelemetry/otlp-transformer" "0.55.0" + "@opentelemetry/sdk-logs" "0.55.0" + +"@opentelemetry/exporter-logs-otlp-proto@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.53.0.tgz#5227efbd9ced9f8f5878dc3e60fc86707f42f5f5" + integrity sha512-jhEcVL1deeWNmTUP05UZMriZPSWUBcfg94ng7JuBb1q2NExgnADQFl1VQQ+xo62/JepK+MxQe4xAwlsDQFbISA== + dependencies: + "@opentelemetry/api-logs" "0.53.0" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-exporter-base" "0.53.0" + "@opentelemetry/otlp-transformer" "0.53.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/sdk-logs" "0.53.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + +"@opentelemetry/exporter-logs-otlp-proto@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.55.0.tgz#d49202382b8bff7d4ae7f471c75ab30a751ca38a" + integrity sha512-vjE+DxUr+cUpxikdKCPiLZM5Wx7g1bywjCG76TQocvsA7Tmbb9p0t1+8gPlu9AGH7VEzPwDxxpN4p1ajpOurzQ== + dependencies: + "@opentelemetry/api-logs" "0.55.0" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-exporter-base" "0.55.0" + "@opentelemetry/otlp-transformer" "0.55.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/sdk-logs" "0.55.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + +"@opentelemetry/exporter-trace-otlp-grpc@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.53.0.tgz#716429f58e71e101fc1fa79b3634083faf7f76da" + integrity sha512-m6KSh6OBDwfDjpzPVbuJbMgMbkoZfpxYH2r262KckgX9cMYvooWXEKzlJYsNDC6ADr28A1rtRoUVRwNfIN4tUg== + dependencies: + "@grpc/grpc-js" "^1.7.1" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.53.0" + "@opentelemetry/otlp-transformer" "0.53.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + +"@opentelemetry/exporter-trace-otlp-grpc@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.55.0.tgz#c1b142bae7144eb2be45332de60a2f48a782ed06" + integrity sha512-ohIkCLn2Wc3vhhFuf1bH8kOXHMEdcWiD847x7f3Qfygc+CGiatGLzQYscTcEYsWGMV22gVwB/kVcNcx5a3o8gA== + dependencies: + "@grpc/grpc-js" "^1.7.1" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-grpc-exporter-base" "0.55.0" + "@opentelemetry/otlp-transformer" "0.55.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + +"@opentelemetry/exporter-trace-otlp-http@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.53.0.tgz#48e46c4573a35d31c14e6bc44635923e32970b9a" + integrity sha512-m7F5ZTq+V9mKGWYpX8EnZ7NjoqAU7VemQ1E2HAG+W/u0wpY1x0OmbxAXfGKFHCspdJk8UKlwPGrpcB8nay3P8A== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-exporter-base" "0.53.0" + "@opentelemetry/otlp-transformer" "0.53.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + +"@opentelemetry/exporter-trace-otlp-http@0.55.0", "@opentelemetry/exporter-trace-otlp-http@^0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.55.0.tgz#275e458aa3bd33c52d77f4357706bcfa53d27f28" + integrity sha512-lMiNic63EVHpW+eChmLD2CieDmwQBFi72+LFbh8+5hY0ShrDGrsGP/zuT5MRh7M/vM/UZYO/2A/FYd7CMQGR7A== + dependencies: + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-exporter-base" "0.55.0" + "@opentelemetry/otlp-transformer" "0.55.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + +"@opentelemetry/exporter-trace-otlp-proto@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.53.0.tgz#a5cf9ddd02f71c1cff7f425f2c138f056cfb3683" + integrity sha512-T/bdXslwRKj23S96qbvGtaYOdfyew3TjPEKOk5mHjkCmkVl1O9C/YMdejwSsdLdOq2YW30KjR9kVi0YMxZushQ== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-exporter-base" "0.53.0" + "@opentelemetry/otlp-transformer" "0.53.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + +"@opentelemetry/exporter-trace-otlp-proto@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.55.0.tgz#8ef67c30258faa91cdcc4f5289970eb55d6481bb" + integrity sha512-qxiJFP+bBZW3+goHCGkE1ZdW9gJU0fR7eQ6OP+Rz5oGtEBbq4nkGodhb7C9FJlEFlE2siPtCxoeupV0gtYynag== + dependencies: + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-exporter-base" "0.55.0" + "@opentelemetry/otlp-transformer" "0.55.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + +"@opentelemetry/exporter-zipkin@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.26.0.tgz#7f7aa5f72f2048ff1316e006b14cce4182b408c3" + integrity sha512-PW5R34n3SJHO4t0UetyHKiXL6LixIqWN6lWncg3eRXhKuT30x+b7m5sDJS0kEWRfHeS+kG7uCw2vBzmB2lk3Dw== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/exporter-zipkin@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.28.0.tgz#6e5ca7f43f79d0e3240ca7029f8dbc43af64c1b7" + integrity sha512-AMwr3eGXaPEH7gk8yhcUcen31VXy1yU5VJETu0pCfGpggGCYmhm0FKgYBpL5/vlIgQJWU/sW2vIjCL7aSilpKg== + dependencies: + "@opentelemetry/core" "1.28.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/instrumentation-amqplib@^0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.42.0.tgz#b3cab5a7207736a30d769962eed3af3838f986c4" + integrity sha512-fiuU6OKsqHJiydHWgTRQ7MnIrJ2lEqsdgFtNIH4LbAUJl/5XmrIeoDzDnox+hfkgWK65jsleFuQDtYb5hW1koQ== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-aws-lambda@^0.45.0": + version "0.45.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.45.0.tgz#26d8c014c6fba662b748eb7c7443386f07db6f1f" + integrity sha512-22ZnmYftKjFoiqC1k3tu2AVKiXSZv+ohuHWk4V4MdJpPuNkadY624aDkv5BmwDeavDxVFgqE9nGgDM9s3Q94mg== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/propagator-aws-xray" "^1.3.1" + "@opentelemetry/resources" "^1.8.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@types/aws-lambda" "8.10.143" + +"@opentelemetry/instrumentation-aws-sdk@^0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.44.0.tgz#f1a2d8c186d37fae42954921bbdcc3555aac331c" + integrity sha512-HIWFg4TDQsayceiikOnruMmyQ0SZYW6WiR+wknWwWVLHC3lHTCpAnqzp5V42ckArOdlwHZu2Jvq2GMSM4Myx3w== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/propagation-utils" "^0.30.11" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-bunyan@^0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.41.0.tgz#102d0e93610f9174105a9a59fc8d47d86b684b8d" + integrity sha512-NoQS+gcwQ7pzb2PZFyra6bAxDAVXBMmpKxBblEuXJWirGrAksQllg9XTdmqhrwT/KxUYrbVca/lMams7e51ysg== + dependencies: + "@opentelemetry/api-logs" "^0.53.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@types/bunyan" "1.8.9" + +"@opentelemetry/instrumentation-cassandra-driver@^0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.41.0.tgz#4776c54b68ffbe8f86f9348fbe4953e04c87820a" + integrity sha512-hvTNcC8qjCQEHZTLAlTmDptjsEGqCKpN+90hHH8Nn/GwilGr5TMSwGrlfstdJuZWyw8HAnRUed6bcjvmHHk2Xw== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-connect@^0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.39.0.tgz#32bdbaac464cba061c95df6c850ee81efdd86f8b" + integrity sha512-pGBiKevLq7NNglMgqzmeKczF4XQMTOUOTkK8afRHMZMnrK3fcETyTH7lVaSozwiOM3Ws+SuEmXZT7DYrrhxGlg== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@types/connect" "3.4.36" + +"@opentelemetry/instrumentation-cucumber@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.9.0.tgz#4ff2415c63eab8bd053424ab9b782ced86bc8a7d" + integrity sha512-4PQNFnIqnA2WM3ZHpr0xhZpHSqJ5xJ6ppTIzZC7wPqe+ZBpj41vG8B6ieqiPfq+im4QdqbYnzLb3rj48GDEN9g== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-dataloader@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.12.0.tgz#de03a3948dec4f15fed80aa424d6bd5d6a8d10c7" + integrity sha512-pnPxatoFE0OXIZDQhL2okF//dmbiWFzcSc8pUg9TqofCLYZySSxDCgQc69CJBo5JnI3Gz1KP+mOjS4WAeRIH4g== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation-dns@^0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.39.0.tgz#4c572041a6a0877aacbb743131158899a3d636e0" + integrity sha512-+iPzvXqVdJa67QBuz2tuP0UI3LS1/cMMo6dS7360DDtOQX+sQzkiN+mo3Omn4T6ZRhkTDw6c7uwsHBcmL31+1g== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + semver "^7.5.4" + +"@opentelemetry/instrumentation-express@^0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-express/-/instrumentation-express-0.43.0.tgz#35ff5bcf40b816d9a9159d5f7814ed7e5d83f69b" + integrity sha512-bxTIlzn9qPXJgrhz8/Do5Q3jIlqfpoJrSUtVGqH+90eM1v2PkPHc+SdE+zSqe4q9Y1UQJosmZ4N4bm7Zj/++MA== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-fastify@^0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.40.0.tgz#0c57608ac202337d56b53338f1fc9369d224306b" + integrity sha512-74qj4nG3zPtU7g2x4sm2T4R3/pBMyrYstTsqSZwdlhQk1SD4l8OSY9sPRX1qkhfxOuW3U4KZQAV/Cymb3fB6hg== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-fs@^0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.15.0.tgz#41658507860f39fee5209bca961cea8d24ca2a83" + integrity sha512-JWVKdNLpu1skqZQA//jKOcKdJC66TWKqa2FUFq70rKohvaSq47pmXlnabNO+B/BvLfmidfiaN35XakT5RyMl2Q== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation-generic-pool@^0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.39.0.tgz#2b9af16ad82d5cbe67125c0125753cecd162a728" + integrity sha512-y4v8Y+tSfRB3NNBvHjbjrn7rX/7sdARG7FuK6zR8PGb28CTa0kHpEGCJqvL9L8xkTNvTXo+lM36ajFGUaK1aNw== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation-graphql@^0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.43.0.tgz#71bb94ea775c70dbd388c739b397ec1418f3f170" + integrity sha512-aI3YMmC2McGd8KW5du1a2gBA0iOMOGLqg4s9YjzwbjFwjlmMNFSK1P3AIg374GWg823RPUGfVTIgZ/juk9CVOA== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation-grpc@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.53.0.tgz#1b493bee7ca8d3d9b8b1a870eb391eeb9bb74900" + integrity sha512-Ss338T92yE1UCgr9zXSY3cPuaAy27uQw+wAC5IwsQKCXL5wwkiOgkd+2Ngksa9EGsgUEMwGeHi76bDdHFJ5Rrw== + dependencies: + "@opentelemetry/instrumentation" "0.53.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/instrumentation-hapi@^0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.41.0.tgz#de8711907256d8fae1b5faf71fc825cef4a7ddbb" + integrity sha512-jKDrxPNXDByPlYcMdZjNPYCvw0SQJjN+B1A+QH+sx+sAHsKSAf9hwFiJSrI6C4XdOls43V/f/fkp9ITkHhKFbQ== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-http@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-http/-/instrumentation-http-0.53.0.tgz#0d806adf1b3aba036bc46e16162e3c0dbb8a6b60" + integrity sha512-H74ErMeDuZfj7KgYCTOFGWF5W9AfaPnqLQQxeFq85+D29wwV2yqHbz2IKLYpkOh7EI6QwDEl7rZCIxjJLyc/CQ== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/instrumentation" "0.53.0" + "@opentelemetry/semantic-conventions" "1.27.0" + semver "^7.5.2" + +"@opentelemetry/instrumentation-ioredis@^0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.43.0.tgz#dbadabaeefc4cb47c406f878444f1bcac774fa89" + integrity sha512-i3Dke/LdhZbiUAEImmRG3i7Dimm/BD7t8pDDzwepSvIQ6s2X6FPia7561gw+64w+nx0+G9X14D7rEfaMEmmjig== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/redis-common" "^0.36.2" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-kafkajs@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.3.0.tgz#6687bce4dac8b90ef8ccbf1b662d5d1e95a34414" + integrity sha512-UnkZueYK1ise8FXQeKlpBd7YYUtC7mM8J0wzUSccEfc/G8UqHQqAzIyYCUOUPUKp8GsjLnWOOK/3hJc4owb7Jg== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-knex@^0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.40.0.tgz#6c667eb5e18cda68f348ab6b8f88f0f8843fcf98" + integrity sha512-6jka2jfX8+fqjEbCn6hKWHVWe++mHrIkLQtaJqUkBt3ZBs2xn1+y0khxiDS0v/mNb0bIKDJWwtpKFfsQDM1Geg== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-koa@^0.43.0": + version "0.43.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.43.0.tgz#963fd192a1b5f6cbae5dabf4ec82e3105cbb23b1" + integrity sha512-lDAhSnmoTIN6ELKmLJBplXzT/Jqs5jGZehuG22EdSMaTwgjMpxMDI1YtlKEhiWPWkrz5LUsd0aOO0ZRc9vn3AQ== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-lru-memoizer@^0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.40.0.tgz#dc60d7fdfd2a0c681cb23e7ed4f314d1506ccdc0" + integrity sha512-21xRwZsEdMPnROu/QsaOIODmzw59IYpGFmuC4aFWvMj6stA8+Ei1tX67nkarJttlNjoM94um0N4X26AD7ff54A== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation-memcached@^0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.39.0.tgz#645b61af927097a7195f48da8e5bcc63bd8f1520" + integrity sha512-WfwvKAZ9I1qILRP5EUd88HQjwAAL+trXpCpozjBi4U6a0A07gB3fZ5PFAxbXemSjF5tHk9KVoROnqHvQ+zzFSQ== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@types/memcached" "^2.2.6" + +"@opentelemetry/instrumentation-mongodb@^0.47.0": + version "0.47.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.47.0.tgz#f8107d878281433905e717f223fb4c0f10356a7b" + integrity sha512-yqyXRx2SulEURjgOQyJzhCECSh5i1uM49NUaq9TqLd6fA7g26OahyJfsr9NE38HFqGRHpi4loyrnfYGdrsoVjQ== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/sdk-metrics" "^1.9.1" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-mongoose@^0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.42.0.tgz#375afd21adfcd897a8f521c1ffd2d91e6a428705" + integrity sha512-AnWv+RaR86uG3qNEMwt3plKX1ueRM7AspfszJYVkvkehiicC3bHQA6vWdb6Zvy5HAE14RyFbu9+2hUUjR2NSyg== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-mysql2@^0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.41.0.tgz#6377b6e2d2487fd88e1d79aa03658db6c8d51651" + integrity sha512-REQB0x+IzVTpoNgVmy5b+UnH1/mDByrneimP6sbDHkp1j8QOl1HyWOrBH/6YWR0nrbU3l825Em5PlybjT3232g== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@opentelemetry/sql-common" "^0.40.1" + +"@opentelemetry/instrumentation-mysql@^0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.41.0.tgz#2d50691ead5219774bd36d66c35d5b4681485dd7" + integrity sha512-jnvrV6BsQWyHS2qb2fkfbfSb1R/lmYwqEZITwufuRl37apTopswu9izc0b1CYRp/34tUG/4k/V39PND6eyiNvw== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@types/mysql" "2.15.26" + +"@opentelemetry/instrumentation-nestjs-core@^0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.40.0.tgz#2c0e6405b56caaec32747d55c57ff9a034668ea8" + integrity sha512-WF1hCUed07vKmf5BzEkL0wSPinqJgH7kGzOjjMAiTGacofNXjb/y4KQ8loj2sNsh5C/NN7s1zxQuCgbWbVTGKg== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-net@^0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-net/-/instrumentation-net-0.39.0.tgz#74db7e3de602a2ce09e989bf9602da974fdd60f2" + integrity sha512-rixHoODfI/Cx1B0mH1BpxCT0bRSxktuBDrt9IvpT2KSEutK5hR0RsRdgdz/GKk+BQ4u+IG6godgMSGwNQCueEA== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-pg@^0.45.1": + version "0.45.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.45.1.tgz#fb705e9f489c8d46036085618faf4c2887611ab9" + integrity sha512-GHUvPv7CQEK3RKHH3YAj6mjgJ3nZb6wRQS+t0yaRgKZzX2ggGsLN6OhRT04+IjqmMg9aIRUy1CzqwzgqAxjYbw== + dependencies: + "@opentelemetry/core" "^1.26.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "1.27.0" + "@opentelemetry/sql-common" "^0.40.1" + "@types/pg" "8.6.1" + "@types/pg-pool" "2.0.6" + +"@opentelemetry/instrumentation-pino@^0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.42.0.tgz#1d91ad9ef48787380f778306bc54f6ab1811f474" + integrity sha512-SoX6FzucBfTuFNMZjdurJhcYWq2ve8/LkhmyVLUW31HpIB45RF1JNum0u4MkGisosDmXlK4njomcgUovShI+WA== + dependencies: + "@opentelemetry/api-logs" "^0.53.0" + "@opentelemetry/core" "^1.25.0" + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation-redis-4@^0.42.1": + version "0.42.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.42.1.tgz#3adf3bee5b4da0837eb31c0f032105dcd2b055d1" + integrity sha512-xm17LJhDfQzQo4wkM/zFwh6wk3SNN/FBFGkscI9Kj4efrb/o5p8Z3yE6ldBPNdIZ6RAwg2p3DL7fvE3DuUDJWA== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/redis-common" "^0.36.2" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-redis@^0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.42.0.tgz#407ab207c5a555b47f46689b345edcabfee89675" + integrity sha512-jZBoqve0rEC51q0HuhjtZVq1DtUvJHzEJ3YKGvzGar2MU1J4Yt5+pQAQYh1W4jSoDyKeaI4hyeUdWM5N0c2lqA== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/redis-common" "^0.36.2" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-restify@^0.41.0": + version "0.41.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.41.0.tgz#071d3a21814e3ce1c311d074ea7c76bbe93bc869" + integrity sha512-gKEo+X/wVKUBuD2WDDlF7SlDNBHMWjSQoLxFCsGqeKgHR0MGtwMel8uaDGg9LJ83nKqYy+7Vl/cDFxjba6H+/w== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-router@^0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-router/-/instrumentation-router-0.40.0.tgz#9c60b02bbfa63298dc73d5c2fcf305b95660e4cb" + integrity sha512-bRo4RaclGFiKtmv/N1D0MuzO7DuxbeqMkMCbPPng6mDwzpHAMpHz/K/IxJmF+H1Hi/NYXVjCKvHGClageLe9eA== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-socket.io@^0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.42.0.tgz#eb2d0eed17c05259d9bded09f02ce9f05846d64c" + integrity sha512-xB5tdsBzuZyicQTO3hDzJIpHQ7V1BYJ6vWPWgl19gWZDBdjEGc3HOupjkd3BUJyDoDhbMEHGk2nNlkUU99EfkA== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/instrumentation-tedious@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.14.0.tgz#15cd9268125cfc0fd2d939602c098dbf3bb4cc2f" + integrity sha512-ofq7pPhSqvRDvD2FVx3RIWPj76wj4QubfrbqJtEx0A+fWoaYxJOCIQ92tYJh28elAmjMmgF/XaYuJuBhBv5J3A== + dependencies: + "@opentelemetry/instrumentation" "^0.53.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + "@types/tedious" "^4.0.14" + +"@opentelemetry/instrumentation-undici@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.6.0.tgz#9436ee155c8dcb0b760b66947c0e0f347688a5ef" + integrity sha512-ABJBhm5OdhGmbh0S/fOTE4N69IZ00CsHC5ijMYfzbw3E5NwLgpQk5xsljaECrJ8wz1SfXbO03FiSuu5AyRAkvQ== + dependencies: + "@opentelemetry/core" "^1.8.0" + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation-winston@^0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.40.0.tgz#021194913c8dd337c097d204cee3fffb55dd0f5b" + integrity sha512-eMk2tKl86YJ8/yHvtDbyhrE35/R0InhO9zuHTflPx8T0+IvKVUhPV71MsJr32sImftqeOww92QHt4Jd+a5db4g== + dependencies: + "@opentelemetry/api-logs" "^0.53.0" + "@opentelemetry/instrumentation" "^0.53.0" + +"@opentelemetry/instrumentation@0.53.0", "@opentelemetry/instrumentation@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.53.0.tgz#e6369e4015eb5112468a4d45d38dcada7dad892d" + integrity sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A== + dependencies: + "@opentelemetry/api-logs" "0.53.0" + "@types/shimmer" "^1.2.0" + import-in-the-middle "^1.8.1" + require-in-the-middle "^7.1.1" + semver "^7.5.2" + shimmer "^1.2.1" + +"@opentelemetry/instrumentation@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation/-/instrumentation-0.55.0.tgz#ecac8afd8706f6e99b3bb6951b9e07c4c81533f0" + integrity sha512-YDCMlaQRZkziLL3t6TONRgmmGxDx6MyQDXRD0dknkkgUZtOK5+8MWft1OXzmNu6XfBOdT12MKN5rz+jHUkafKQ== + dependencies: + "@opentelemetry/api-logs" "0.55.0" + "@types/shimmer" "^1.2.0" + import-in-the-middle "^1.8.1" + require-in-the-middle "^7.1.1" + semver "^7.5.2" + shimmer "^1.2.1" + +"@opentelemetry/otlp-exporter-base@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.53.0.tgz#dfe51874b869c687c3cb463b70cddda7de282762" + integrity sha512-UCWPreGQEhD6FjBaeDuXhiMf6kkBODF0ZQzrk/tuQcaVDJ+dDQ/xhJp192H9yWnKxVpEjFrSSLnpqmX4VwX+eA== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-transformer" "0.53.0" + +"@opentelemetry/otlp-exporter-base@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.55.0.tgz#db17332497e4a97e4ca85d394fb91cbbcfd76d84" + integrity sha512-iHQI0Zzq3h1T6xUJTVFwmFl5Dt5y1es+fl4kM+k5T/3YvmVyeYkSiF+wHCg6oKrlUAJfk+t55kaAu3sYmt7ZYA== + dependencies: + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-transformer" "0.55.0" + +"@opentelemetry/otlp-grpc-exporter-base@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.53.0.tgz#6c5ba207352e23d45dc75473e157ef27a1a7f4c8" + integrity sha512-F7RCN8VN+lzSa4fGjewit8Z5fEUpY/lmMVy5EWn2ZpbAabg3EE3sCLuTNfOiooNGnmvzimUPruoeqeko/5/TzQ== + dependencies: + "@grpc/grpc-js" "^1.7.1" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/otlp-exporter-base" "0.53.0" + "@opentelemetry/otlp-transformer" "0.53.0" + +"@opentelemetry/otlp-grpc-exporter-base@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.55.0.tgz#33644b96eeaa6a53431f45cd4b8180c887a6a8d7" + integrity sha512-gebbjl9FiSp52igWXuGjcWQKfB6IBwFGt5z1VFwTcVZVeEZevB6bJIqoFrhH4A02m7OUlpJ7l4EfRi3UtkNANQ== + dependencies: + "@grpc/grpc-js" "^1.7.1" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/otlp-exporter-base" "0.55.0" + "@opentelemetry/otlp-transformer" "0.55.0" + +"@opentelemetry/otlp-transformer@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.53.0.tgz#55d435db5ed5cf56b99c010827294dd4921c45c2" + integrity sha512-rM0sDA9HD8dluwuBxLetUmoqGJKSAbWenwD65KY9iZhUxdBHRLrIdrABfNDP7aiTjcgK8XFyTn5fhDz7N+W6DA== + dependencies: + "@opentelemetry/api-logs" "0.53.0" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/sdk-logs" "0.53.0" + "@opentelemetry/sdk-metrics" "1.26.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + protobufjs "^7.3.0" + +"@opentelemetry/otlp-transformer@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.55.0.tgz#316b9325983e660cb4f18cb76fa84ce1c0cdad42" + integrity sha512-kVqEfxtp6mSN2Dhpy0REo1ghP4PYhC1kMHQJ2qVlO99Pc+aigELjZDfg7/YKmL71gR6wVGIeJfiql/eXL7sQPA== + dependencies: + "@opentelemetry/api-logs" "0.55.0" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/sdk-logs" "0.55.0" + "@opentelemetry/sdk-metrics" "1.28.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + protobufjs "^7.3.0" + +"@opentelemetry/propagation-utils@^0.30.11": + version "0.30.16" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagation-utils/-/propagation-utils-0.30.16.tgz#6715d0225b618ea66cf34cc3800fa3452a8475fa" + integrity sha512-ZVQ3Z/PQ+2GQlrBfbMMMT0U7MzvYZLCPP800+ooyaBqm4hMvuQHfP028gB9/db0mwkmyEAMad9houukUVxhwcw== + +"@opentelemetry/propagator-aws-xray@^1.3.1": + version "1.26.2" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-aws-xray/-/propagator-aws-xray-1.26.2.tgz#39e0ded430e23e99c68c380a77f5052444f13f88" + integrity sha512-k43wxTjKYvwfce9L4eT8fFYy/ATmCfPHZPZsyT/6ABimf2KE1HafoOsIcxLOtmNSZt6dCvBIYCrXaOWta20xJg== + +"@opentelemetry/propagator-b3@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-1.26.0.tgz#3ebbeff26a3fb81e8be011666ea6d07ff3e4fba7" + integrity sha512-vvVkQLQ/lGGyEy9GT8uFnI047pajSOVnZI2poJqVGD3nJ+B9sFGdlHNnQKophE3lHfnIH0pw2ubrCTjZCgIj+Q== + dependencies: + "@opentelemetry/core" "1.26.0" + +"@opentelemetry/propagator-b3@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-b3/-/propagator-b3-1.28.0.tgz#5e4c87c2097a18f88a5a4d19a57350f55517bb8a" + integrity sha512-Q7HVDIMwhN5RxL4bECMT4BdbyYSAKkC6U/RGn4NpO/cbqP6ZRg+BS7fPo/pGZi2w8AHfpIGQFXQmE8d2PC5xxQ== + dependencies: + "@opentelemetry/core" "1.28.0" + +"@opentelemetry/propagator-jaeger@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.26.0.tgz#096ac03d754204921cd5a886c77b5c9bd4677cd7" + integrity sha512-DelFGkCdaxA1C/QA0Xilszfr0t4YbGd3DjxiCDPh34lfnFr+VkkrjV9S8ZTJvAzfdKERXhfOxIKBoGPJwoSz7Q== + dependencies: + "@opentelemetry/core" "1.26.0" + +"@opentelemetry/propagator-jaeger@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.28.0.tgz#427158c3d0f8ea77c205c7b9cde09091c7f25ae3" + integrity sha512-wKJ94+s8467CnIRgoSRh0yXm/te0QMOwTq9J01PfG/RzYZvlvN8aRisN2oZ9SznB45dDGnMj3BhUlchSA9cEKA== + dependencies: + "@opentelemetry/core" "1.28.0" + +"@opentelemetry/redis-common@^0.36.2": + version "0.36.2" + resolved "https://registry.yarnpkg.com/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz#906ac8e4d804d4109f3ebd5c224ac988276fdc47" + integrity sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g== + +"@opentelemetry/resource-detector-alibaba-cloud@^0.29.3": + version "0.29.7" + resolved "https://registry.yarnpkg.com/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.29.7.tgz#ebeb5e3594495f9ed3e8e99e2a4b7a647efb03b0" + integrity sha512-PExUl/R+reSQI6Y/eNtgAsk6RHk1ElYSzOa8/FHfdc/nLmx9sqMasBEpLMkETkzDP7t27ORuXe4F9vwkV2uwwg== + dependencies: + "@opentelemetry/core" "^1.26.0" + "@opentelemetry/resources" "^1.10.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/resource-detector-aws@^1.6.2": + version "1.12.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.12.0.tgz#740edea01ce395a67885c02bbffcad74d3bad4e0" + integrity sha512-Cvi7ckOqiiuWlHBdA1IjS0ufr3sltex2Uws2RK6loVp4gzIJyOijsddAI6IZ5kiO8h/LgCWe8gxPmwkTKImd+Q== + dependencies: + "@opentelemetry/core" "^1.0.0" + "@opentelemetry/resources" "^1.10.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/resource-detector-azure@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@opentelemetry/resource-detector-azure/-/resource-detector-azure-0.2.12.tgz#090eaf81408af88d26354631c41df921deca3d7d" + integrity sha512-iIarQu6MiCjEEp8dOzmBvCSlRITPFTinFB2oNKAjU6xhx8d7eUcjNOKhBGQTvuCriZrxrEvDaEEY9NfrPQ6uYQ== + dependencies: + "@opentelemetry/core" "^1.25.1" + "@opentelemetry/resources" "^1.10.1" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/resource-detector-container@^0.4.3": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@opentelemetry/resource-detector-container/-/resource-detector-container-0.4.4.tgz#56f13ae43b5e84c6edb9f5ce91291944e778913b" + integrity sha512-ZEN2mq7lIjQWJ8NTt1umtr6oT/Kb89856BOmESLSvgSHbIwOFYs7cSfSRH5bfiVw6dXTQAVbZA/wLgCHKrebJA== + dependencies: + "@opentelemetry/core" "^1.26.0" + "@opentelemetry/resources" "^1.10.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + +"@opentelemetry/resource-detector-gcp@^0.29.12": + version "0.29.13" + resolved "https://registry.yarnpkg.com/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.29.13.tgz#d506f2f05d7c790c59203afdfda40a90c22264b0" + integrity sha512-vdotx+l3Q+89PeyXMgKEGnZ/CwzwMtuMi/ddgD9/5tKZ08DfDGB2Npz9m2oXPHRCjc4Ro6ifMqFlRyzIvgOjhg== + dependencies: + "@opentelemetry/core" "^1.0.0" + "@opentelemetry/resources" "^1.10.0" + "@opentelemetry/semantic-conventions" "^1.27.0" + gcp-metadata "^6.0.0" + +"@opentelemetry/resources@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.26.0.tgz#da4c7366018bd8add1f3aa9c91c6ac59fd503cef" + integrity sha512-CPNYchBE7MBecCSVy0HKpUISEeJOniWqcHaAHpmasZ3j9o6V3AyBzhRc90jdmemq0HOxDr6ylhUbDhBqqPpeNw== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/resources@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.28.0.tgz#c8c27ae7559c817f9d117f1bf96d76f893fb29f5" + integrity sha512-cIyXSVJjGeTICENN40YSvLDAq4Y2502hGK3iN7tfdynQLKWb3XWZQEkPc+eSx47kiy11YeFAlYkEfXwR1w8kfw== + dependencies: + "@opentelemetry/core" "1.28.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/resources@1.30.1", "@opentelemetry/resources@^1.10.0", "@opentelemetry/resources@^1.10.1", "@opentelemetry/resources@^1.24.0", "@opentelemetry/resources@^1.30.1", "@opentelemetry/resources@^1.8.0": + version "1.30.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.30.1.tgz#a4eae17ebd96947fdc7a64f931ca4b71e18ce964" + integrity sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA== + dependencies: + "@opentelemetry/core" "1.30.1" + "@opentelemetry/semantic-conventions" "1.28.0" + +"@opentelemetry/sdk-logs@0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.53.0.tgz#ec8b69278c4e683c13c58ed4285a47c27f5799c6" + integrity sha512-dhSisnEgIj/vJZXZV6f6KcTnyLDx/VuQ6l3ejuZpMpPlh9S1qMHiZU9NMmOkVkwwHkMy3G6mEBwdP23vUZVr4g== + dependencies: + "@opentelemetry/api-logs" "0.53.0" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + +"@opentelemetry/sdk-logs@0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.55.0.tgz#78844e502167723a258c75a6b4f3de3900c13ea3" + integrity sha512-TSx+Yg/d48uWW6HtjS1AD5x6WPfLhDWLl/WxC7I2fMevaiBuKCuraxTB8MDXieCNnBI24bw9ytyXrDCswFfWgA== + dependencies: + "@opentelemetry/api-logs" "0.55.0" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/resources" "1.28.0" + +"@opentelemetry/sdk-metrics@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.26.0.tgz#37bb0afb1d4447f50aab9cdd05db6f2d8b86103e" + integrity sha512-0SvDXmou/JjzSDOjUmetAAvcKQW6ZrvosU0rkbDGpXvvZN+pQF6JbK/Kd4hNdK4q/22yeruqvukXEJyySTzyTQ== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + +"@opentelemetry/sdk-metrics@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.28.0.tgz#257b5295bbe9de1ad31c5e8cb43a660c25911d20" + integrity sha512-43tqMK/0BcKTyOvm15/WQ3HLr0Vu/ucAl/D84NO7iSlv6O4eOprxSHa3sUtmYkaZWHqdDJV0AHVz/R6u4JALVQ== + dependencies: + "@opentelemetry/core" "1.28.0" + "@opentelemetry/resources" "1.28.0" + +"@opentelemetry/sdk-metrics@^1.9.1": + version "1.30.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.30.1.tgz#70e2bcd275b9df6e7e925e3fe53cfe71329b5fc8" + integrity sha512-q9zcZ0Okl8jRgmy7eNW3Ku1XSgg3sDLa5evHZpCwjspw7E8Is4K/haRPDJrBcX3YSn/Y7gUvFnByNYEKQNbNog== + dependencies: + "@opentelemetry/core" "1.30.1" + "@opentelemetry/resources" "1.30.1" + +"@opentelemetry/sdk-node@^0.53.0": + version "0.53.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-node/-/sdk-node-0.53.0.tgz#0d25a142009792f9a4d7d69ab243a225c229643b" + integrity sha512-0hsxfq3BKy05xGktwG8YdGdxV978++x40EAKyKr1CaHZRh8uqVlXnclnl7OMi9xLMJEcXUw7lGhiRlArFcovyg== + dependencies: + "@opentelemetry/api-logs" "0.53.0" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/exporter-logs-otlp-grpc" "0.53.0" + "@opentelemetry/exporter-logs-otlp-http" "0.53.0" + "@opentelemetry/exporter-logs-otlp-proto" "0.53.0" + "@opentelemetry/exporter-trace-otlp-grpc" "0.53.0" + "@opentelemetry/exporter-trace-otlp-http" "0.53.0" + "@opentelemetry/exporter-trace-otlp-proto" "0.53.0" + "@opentelemetry/exporter-zipkin" "1.26.0" + "@opentelemetry/instrumentation" "0.53.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/sdk-logs" "0.53.0" + "@opentelemetry/sdk-metrics" "1.26.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + "@opentelemetry/sdk-trace-node" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/sdk-node@^0.55.0": + version "0.55.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-node/-/sdk-node-0.55.0.tgz#a026846d3a0372211129397e073a4820191ddd8e" + integrity sha512-gSXQWV23+9vhbjsvAIeM0LxY3W8DTKI3MZlzFp61noIb1jSr46ET+qoUjHlfZ1Yymebv9KXWeZsqhft81HBXuQ== + dependencies: + "@opentelemetry/api-logs" "0.55.0" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/exporter-logs-otlp-grpc" "0.55.0" + "@opentelemetry/exporter-logs-otlp-http" "0.55.0" + "@opentelemetry/exporter-logs-otlp-proto" "0.55.0" + "@opentelemetry/exporter-trace-otlp-grpc" "0.55.0" + "@opentelemetry/exporter-trace-otlp-http" "0.55.0" + "@opentelemetry/exporter-trace-otlp-proto" "0.55.0" + "@opentelemetry/exporter-zipkin" "1.28.0" + "@opentelemetry/instrumentation" "0.55.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/sdk-logs" "0.55.0" + "@opentelemetry/sdk-metrics" "1.28.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + "@opentelemetry/sdk-trace-node" "1.28.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/sdk-trace-base@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.26.0.tgz#0c913bc6d2cfafd901de330e4540952269ae579c" + integrity sha512-olWQldtvbK4v22ymrKLbIcBi9L2SpMO84sCPY54IVsJhP9fRsxJT194C/AVaAuJzLE30EdhhM1VmvVYR7az+cw== + dependencies: + "@opentelemetry/core" "1.26.0" + "@opentelemetry/resources" "1.26.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/sdk-trace-base@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.28.0.tgz#6195dc8cd78bd74394cf54c67c5cbd8d1528516c" + integrity sha512-ceUVWuCpIao7Y5xE02Xs3nQi0tOGmMea17ecBdwtCvdo9ekmO+ijc9RFDgfifMl7XCBf41zne/1POM3LqSTZDA== + dependencies: + "@opentelemetry/core" "1.28.0" + "@opentelemetry/resources" "1.28.0" + "@opentelemetry/semantic-conventions" "1.27.0" + +"@opentelemetry/sdk-trace-base@^1.28.0": + version "1.30.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz#41a42234096dc98e8f454d24551fc80b816feb34" + integrity sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg== + dependencies: + "@opentelemetry/core" "1.30.1" + "@opentelemetry/resources" "1.30.1" + "@opentelemetry/semantic-conventions" "1.28.0" + +"@opentelemetry/sdk-trace-node@1.26.0": + version "1.26.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.26.0.tgz#169ef4fc058e82a12460da18cedaf6e4615fc617" + integrity sha512-Fj5IVKrj0yeUwlewCRwzOVcr5avTuNnMHWf7GPc1t6WaT78J6CJyF3saZ/0RkZfdeNO8IcBl/bNcWMVZBMRW8Q== + dependencies: + "@opentelemetry/context-async-hooks" "1.26.0" + "@opentelemetry/core" "1.26.0" + "@opentelemetry/propagator-b3" "1.26.0" + "@opentelemetry/propagator-jaeger" "1.26.0" + "@opentelemetry/sdk-trace-base" "1.26.0" + semver "^7.5.2" + +"@opentelemetry/sdk-trace-node@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.28.0.tgz#e3384802e12c689bb7a84809a732d091a2fbda09" + integrity sha512-N0sYfYXvHpP0FNIyc+UfhLnLSTOuZLytV0qQVrDWIlABeD/DWJIGttS7nYeR14gQLXch0M1DW8zm3VeN6Opwtg== + dependencies: + "@opentelemetry/context-async-hooks" "1.28.0" + "@opentelemetry/core" "1.28.0" + "@opentelemetry/propagator-b3" "1.28.0" + "@opentelemetry/propagator-jaeger" "1.28.0" + "@opentelemetry/sdk-trace-base" "1.28.0" + semver "^7.5.2" + +"@opentelemetry/semantic-conventions@1.27.0": + version "1.27.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz#1a857dcc95a5ab30122e04417148211e6f945e6c" + integrity sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg== + +"@opentelemetry/semantic-conventions@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz#337fb2bca0453d0726696e745f50064411f646d6" + integrity sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA== + +"@opentelemetry/semantic-conventions@^1.27.0": + version "1.40.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz#10b2944ca559386590683392022a897eefd011d3" + integrity sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw== + +"@opentelemetry/sql-common@^0.40.1": + version "0.40.1" + resolved "https://registry.yarnpkg.com/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz#93fbc48d8017449f5b3c3274f2268a08af2b83b6" + integrity sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg== + dependencies: + "@opentelemetry/core" "^1.1.0" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -5750,6 +6783,25 @@ resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.24.tgz#3a96351047575bbcf2340541b2d955a35339608f" integrity sha512-8iHVLHsCCOBKjCF2KwFe0p9Z3rfM9mL+sSP8btyR5vTjJRAqpBYD28/ZLgXPf0pjG1VxOvtCV/BgXkQbpSe8Hw== +"@types/aws-lambda@8.10.143": + version "8.10.143" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.143.tgz#383693fbaadc6994a71d64a7c09e8c244fad8dff" + integrity sha512-u5vzlcR14ge/4pMTTMDQr3MF0wEe38B2F9o84uC4F43vN5DGTy63npRrB6jQhyt+C0lGv4ZfiRcRkqJoZuPnmg== + +"@types/bunyan@1.8.9": + version "1.8.9" + resolved "https://registry.yarnpkg.com/@types/bunyan/-/bunyan-1.8.9.tgz#22d4517f3217b7c8f5a69bbc8c9f6df79779dcb5" + integrity sha512-ZqS9JGpBxVOvsawzmVt30sP++gSQMTejCkIAQ3VdadOcRE8izTyW66hufvwLeH+YEGP6Js2AW7Gz+RMyvrEbmw== + dependencies: + "@types/node" "*" + +"@types/connect@3.4.36": + version "3.4.36" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.36.tgz#e511558c15a39cb29bd5357eebb57bd1459cd1ab" + integrity sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w== + dependencies: + "@types/node" "*" + "@types/cors@^2.8.12": version "2.8.17" resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" @@ -5772,6 +6824,20 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/memcached@^2.2.6": + version "2.2.10" + resolved "https://registry.yarnpkg.com/@types/memcached/-/memcached-2.2.10.tgz#113f9e3a451d6b5e0a3822e06d9feb52e63e954a" + integrity sha512-AM9smvZN55Gzs2wRrqeMHVP7KE8KWgCJO/XL5yCly2xF6EKa4YlbpK+cLSAH4NG/Ah64HrlegmGqW8kYws7Vxg== + dependencies: + "@types/node" "*" + +"@types/mysql@2.15.26": + version "2.15.26" + resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.26.tgz#f0de1484b9e2354d587e7d2bd17a873cc8300836" + integrity sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ== + dependencies: + "@types/node" "*" + "@types/node@*", "@types/node@>=10.0.0": version "22.13.13" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.13.tgz#5e7d110fb509b0d4a43fbf48fa9d6e0f83e1b1e7" @@ -5779,6 +6845,41 @@ dependencies: undici-types "~6.20.0" +"@types/node@>=13.7.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.5.0.tgz#5c99f37c443d9ccc4985866913f1ed364217da31" + integrity sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw== + dependencies: + undici-types "~7.18.0" + +"@types/pg-pool@2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/pg-pool/-/pg-pool-2.0.6.tgz#1376d9dc5aec4bb2ec67ce28d7e9858227403c77" + integrity sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ== + dependencies: + "@types/pg" "*" + +"@types/pg@*", "@types/pg@8.6.1": + version "8.6.1" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.1.tgz#099450b8dc977e8197a44f5229cedef95c8747f9" + integrity sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^2.2.0" + +"@types/shimmer@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/shimmer/-/shimmer-1.2.0.tgz#9b706af96fa06416828842397a70dfbbf1c14ded" + integrity sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg== + +"@types/tedious@^4.0.14": + version "4.0.14" + resolved "https://registry.yarnpkg.com/@types/tedious/-/tedious-4.0.14.tgz#868118e7a67808258c05158e9cad89ca58a2aec1" + integrity sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw== + dependencies: + "@types/node" "*" + "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" @@ -5897,6 +6998,11 @@ accesscontrol@^2.2.1: dependencies: notation "^1.3.6" +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -6358,6 +7464,11 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bignumber.js@^9.0.0: + version "9.3.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.3.1.tgz#759c5aaddf2ffdc4f154f7b493e1c8770f88c4d7" + integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== + binary-extensions@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" @@ -6665,6 +7776,11 @@ chownr@^3.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== +cjs-module-lexer@^1.2.2: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -7987,6 +9103,17 @@ gaxios@^1.0.4: https-proxy-agent "^2.2.1" node-fetch "^2.3.0" +gaxios@^6.1.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-6.7.1.tgz#ebd9f7093ede3ba502685e73390248bb5b7f71fb" + integrity sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ== + dependencies: + extend "^3.0.2" + https-proxy-agent "^7.0.1" + is-stream "^2.0.0" + node-fetch "^2.6.9" + uuid "^9.0.1" + gcp-metadata@^0.6.1, gcp-metadata@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-0.6.3.tgz#4550c08859c528b370459bd77a7187ea0bdbc4ab" @@ -7996,6 +9123,15 @@ gcp-metadata@^0.6.1, gcp-metadata@^0.6.3: extend "^3.0.1" retry-axios "0.3.2" +gcp-metadata@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-6.1.1.tgz#f65aa69f546bc56e116061d137d3f5f90bdec494" + integrity sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A== + dependencies: + gaxios "^6.1.1" + google-logging-utils "^0.0.2" + json-bigint "^1.0.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -8156,6 +9292,11 @@ google-auto-auth@^0.10.1: google-auth-library "^1.3.1" request "^2.79.0" +google-logging-utils@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/google-logging-utils/-/google-logging-utils-0.0.2.tgz#5fd837e06fa334da450433b9e3e1870c1594466a" + integrity sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ== + google-p12-pem@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-1.0.5.tgz#0b4721cdfc818759d884f0c62803518decdaf0d0" @@ -8420,6 +9561,16 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-in-the-middle@^1.8.1: + version "1.15.0" + resolved "https://registry.yarnpkg.com/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz#9e20827a322bbadaeb5e3bac49ea8f6d4685fdd8" + integrity sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA== + dependencies: + acorn "^8.14.0" + acorn-import-attributes "^1.9.5" + cjs-module-lexer "^1.2.2" + module-details-from-path "^1.0.3" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -8613,7 +9764,7 @@ is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0: +is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0, is-core-module@^2.16.1: version "2.16.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== @@ -9090,6 +10241,13 @@ jsesc@^3.0.2: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== +json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -9389,6 +10547,11 @@ lodash-compat@^3.10.2: resolved "https://registry.yarnpkg.com/lodash-compat/-/lodash-compat-3.10.2.tgz#c6940128a9d30f8e902cd2cf99fd0cba4ecfc183" integrity sha512-k8SE/OwvWfYZqx3MA/Ry1SHBDWre8Z8tCs0Ba0bF5OqVNvymxgFZ/4VDtbTxzTvcoG11JpTMFsaeZp/yGYvFnA== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -9506,6 +10669,11 @@ long-timeout@0.1.1: resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514" integrity sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w== +long@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + looper@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" @@ -9842,6 +11010,11 @@ mocha@^11.7.5: yargs-parser "^21.1.1" yargs-unparser "^2.0.0" +module-details-from-path@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/module-details-from-path/-/module-details-from-path-1.0.4.tgz#b662fdcd93f6c83d3f25289da0ce81c8d9685b94" + integrity sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w== + moment@^2.30.1: version "2.30.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" @@ -9947,7 +11120,7 @@ node-addon-api@^8.3.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.3.1.tgz#53bc8a4f8dbde3de787b9828059da94ba9fd4eed" integrity sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA== -node-fetch@^2.3.0, node-fetch@^2.6.0: +node-fetch@^2.3.0, node-fetch@^2.6.0, node-fetch@^2.6.9: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -10419,6 +11592,27 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-protocol@*: + version "1.13.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.13.0.tgz#fdaf6d020bca590d58bb991b4b16fc448efe0511" + integrity sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w== + +pg-types@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + picocolors@^1.0.0, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" @@ -10482,6 +11676,28 @@ possible-typed-array-names@^1.0.0: resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.1.tgz#c40b3da0222c500ff1e51c5d7014b60b79697c7a" + integrity sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ== + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -10520,6 +11736,24 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" +protobufjs@^7.3.0, protobufjs@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a" + integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg== + 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" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -10786,6 +12020,15 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-in-the-middle@^7.1.1: + version "7.5.2" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz#dc25b148affad42e570cf0e41ba30dc00f1703ec" + integrity sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ== + dependencies: + debug "^4.3.5" + module-details-from-path "^1.0.3" + resolve "^1.22.8" + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -10815,6 +12058,15 @@ resolve@^1.10.0, resolve@^1.22.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.8: + version "1.22.11" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + retry-axios@0.3.2, retry-axios@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/retry-axios/-/retry-axios-0.3.2.tgz#5757c80f585b4cc4c4986aa2ffd47a60c6d35e13" @@ -10937,6 +12189,11 @@ semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== +semver@^7.5.2: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + semver@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" @@ -11048,6 +12305,11 @@ shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a" integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== +shimmer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" + integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== + side-channel-list@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" @@ -11811,6 +13073,11 @@ undici-types@~6.20.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== +undici-types@~7.18.0: + version "7.18.2" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.18.2.tgz#29357a89e7b7ca4aef3bf0fd3fd0cd73884229e9" + integrity sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w== + unique-filename@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-4.0.0.tgz#a06534d370e7c977a939cd1d11f7f0ab8f1fed13" @@ -11941,6 +13208,11 @@ uuid@^8.3.0, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + valid-url@~1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" @@ -12234,7 +13506,7 @@ xmlhttprequest-ssl@~2.1.1: resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz#e9e8023b3f29ef34b97a859f584c5e6c61418e23" integrity sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ== -xtend@^4.0.2, xtend@~4.0.0: +xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== From 9d17764ef4ecef22f65521b8d9b5fcc34741b07c Mon Sep 17 00:00:00 2001 From: Thomas Flament Date: Thu, 2 Apr 2026 16:59:25 +0200 Subject: [PATCH 2/7] feat: add Proxy-based instrumentation for core components Proxy-based auto-wrapping of vault, storage, metadata, api, and services with low-cardinality span names. Instruments both callback-based and promise-based methods transparently. Issue: CLDSRV-884 --- lib/instrumentation/simple.js | 486 ++++++++++++++++++++++++++++++++++ 1 file changed, 486 insertions(+) create mode 100644 lib/instrumentation/simple.js diff --git a/lib/instrumentation/simple.js b/lib/instrumentation/simple.js new file mode 100644 index 0000000000..0efa49e0fd --- /dev/null +++ b/lib/instrumentation/simple.js @@ -0,0 +1,486 @@ +'use strict'; + +const { trace, context, SpanStatusCode, SpanKind } = require('@opentelemetry/api'); + +const enableOtel = process.env.ENABLE_OTEL === 'true'; + +function createInstrumentedProxy(target, componentName, options = {}) { + if (!enableOtel) { + return target; + } + + if (!target || typeof target !== 'object') { + return target; + } + + const tracer = trace.getTracer(`cloudserver-${componentName}`, '1.0.0'); + const { + skipMethods = ['constructor', 'toString', 'valueOf', 'inspect'], + getSpanName = methodName => `${componentName}.${methodName}`, + } = options; + + return new Proxy(target, { + get(obj, prop) { + const originalValue = obj[prop]; + + if (typeof prop === 'symbol' || typeof originalValue !== 'function' || skipMethods.includes(prop)) { + return originalValue; + } + + return function (...args) { + const spanName = getSpanName(prop, args); + const span = tracer.startSpan(spanName, { + kind: SpanKind.INTERNAL, + attributes: { + 'cloudserver.component': componentName, + 'cloudserver.method': prop, + 'cloudserver.operation_type': getOperationType(componentName, prop), + 'cloudserver.method_name': prop, + }, + }); + + const callbackIndex = args.findLastIndex(arg => typeof arg === 'function'); + + if (callbackIndex === -1) { + return context.with(trace.setSpan(context.active(), span), () => { + try { + const result = originalValue.apply(this, args); + + if (result && typeof result.then === 'function') { + return result + .then(value => { + span.setStatus({ code: SpanStatusCode.OK }); + span.end(); + return value; + }) + .catch(error => { + span.recordException(error); + span.setStatus({ code: SpanStatusCode.ERROR }); + span.end(); + throw error; + }); + } + + span.setStatus({ code: SpanStatusCode.OK }); + span.end(); + return result; + } catch (error) { + span.recordException(error); + span.setStatus({ code: SpanStatusCode.ERROR }); + span.end(); + throw error; + } + }); + } + + const originalCallback = args[callbackIndex]; + const wrappedArgs = [...args]; + wrappedArgs[callbackIndex] = function (err, ...results) { + if (err) { + span.recordException(err); + span.setStatus({ code: SpanStatusCode.ERROR }); + } else { + span.setStatus({ code: SpanStatusCode.OK }); + } + span.end(); + return originalCallback.call(this, err, ...results); + }; + + try { + return context.with(trace.setSpan(context.active(), span), () => + originalValue.apply(this, wrappedArgs)); + } catch (error) { + span.recordException(error); + span.setStatus({ code: SpanStatusCode.ERROR }); + span.end(); + throw error; + } + }; + }, + }); +} + +function getOperationType(component, method) { + if (component === 'vault') { + if (method.includes('authenticate')) { return 'auth'; } + if (method.includes('Policy') || method.includes('policy')) { return 'policy'; } + return 'other'; + } + if (component === 'storage') { + if (['put', 'upload'].some(op => method.includes(op))) { return 'write'; } + if (['get', 'head', 'download'].some(op => method.includes(op))) { return 'read'; } + if (['delete', 'remove'].some(op => method.includes(op))) { return 'delete'; } + return 'other'; + } + if (component === 'metadata') { + if (method.includes('Object')) { + if (method.includes('put') || method.includes('create')) { return 'object_put'; } + if (method.includes('get') || method.includes('read')) { return 'object_get'; } + if (method.includes('delete') || method.includes('remove')) { return 'object_delete'; } + return 'object_op'; + } + if (method.includes('Bucket')) { + if (method.includes('create')) { return 'bucket_create'; } + if (method.includes('delete')) { return 'bucket_delete'; } + if (method.includes('get') || method.includes('Attributes')) { return 'bucket_get'; } + if (method.includes('put') || method.includes('update')) { return 'bucket_put'; } + return 'bucket_op'; + } + return 'other'; + } + if (component === 'api') { + if (method.includes('object')) { + if (method.includes('Put') || method.includes('put')) { return 'object_put'; } + if (method.includes('Get') || method.includes('get') || + method.includes('Head') || method.includes('head')) { return 'object_get'; } + if (method.includes('Delete') || method.includes('delete')) { return 'object_delete'; } + if (method.includes('Copy') || method.includes('copy')) { return 'object_copy'; } + return 'object_op'; + } + if (method.includes('bucket')) { + if (method.includes('Put') || method.includes('put')) { return 'bucket_put'; } + if (method.includes('Get') || method.includes('get') || + method.includes('Head') || method.includes('head')) { return 'bucket_get'; } + if (method.includes('Delete') || method.includes('delete')) { return 'bucket_delete'; } + return 'bucket_op'; + } + if (method.includes('multipart') || method.includes('Multipart')) { return 'multipart'; } + return 'other'; + } + if (component === 'services') { + if (method.includes('Object')) { + if (method.includes('Store') || method.includes('store')) { return 'object_store'; } + if (method.includes('Delete') || method.includes('delete')) { return 'object_delete'; } + if (method.includes('Get') || method.includes('get') || method.includes('Listing')) { return 'object_get'; } + return 'object_op'; + } + if (method.includes('Multipart') || method.includes('MPU')) { return 'multipart'; } + if (method.includes('Service')) { return 'service_listing'; } + return 'other'; + } + return 'unknown'; +} + +function instrumentVault(vault) { + return createInstrumentedProxy(vault, 'vault', { + getSpanName: methodName => { + if (methodName.includes('authenticate')) { + return 'vault.authenticate'; + } + if (methodName.includes('Policy') || methodName.includes('policy')) { + return 'vault.policy_check'; + } + return `vault.${methodName}`; + }, + }); +} + +function instrumentStorage(storage) { + return createInstrumentedProxy(storage, 'storage', { + getSpanName: methodName => { + if (methodName === 'put' || methodName.includes('upload')) { + return 'storage.put'; + } + if (methodName === 'get' || methodName.includes('download')) { + return 'storage.get'; + } + if (methodName === 'delete' || methodName.includes('remove')) { + return 'storage.delete'; + } + if (methodName === 'head') { + return 'storage.head'; + } + return `storage.${methodName}`; + }, + }); +} + +function instrumentMetadata(metadata) { + return createInstrumentedProxy(metadata, 'metadata', { + getSpanName: methodName => { + if (methodName.includes('Object')) { + if (methodName.includes('put') || methodName.includes('create')) { + return 'metadata.object_put'; + } + if (methodName.includes('get') || methodName.includes('read')) { + return 'metadata.object_get'; + } + if (methodName.includes('delete') || methodName.includes('remove')) { + return 'metadata.object_delete'; + } + return 'metadata.object_op'; + } + if (methodName.includes('Bucket')) { + if (methodName.includes('create')) { + return 'metadata.bucket_create'; + } + if (methodName.includes('delete')) { + return 'metadata.bucket_delete'; + } + if (methodName.includes('get') || methodName.includes('Attributes')) { + return 'metadata.bucket_get'; + } + if (methodName.includes('put') || methodName.includes('update')) { + return 'metadata.bucket_put'; + } + return 'metadata.bucket_op'; + } + return `metadata.${methodName}`; + }, + }); +} + +function instrumentApi(api) { + return createInstrumentedProxy(api, 'api', { + getSpanName: methodName => { + if (methodName === 'callApiMethod') { + return 'api.request_handler'; + } + if (methodName.startsWith('object')) { + if (methodName.includes('Put') || methodName === 'objectPut') { + return 'api.object_put'; + } + if (methodName.includes('Get') || methodName === 'objectGet') { + return 'api.object_get'; + } + if (methodName.includes('Head') || methodName === 'objectHead') { + return 'api.object_head'; + } + if (methodName.includes('Delete') || methodName === 'objectDelete') { + return 'api.object_delete'; + } + if (methodName.includes('Copy') || methodName === 'objectCopy') { + return 'api.object_copy'; + } + if (methodName.includes('ACL')) { + return 'api.object_acl'; + } + if (methodName.includes('Tag')) { + return 'api.object_tagging'; + } + return 'api.object_op'; + } + if (methodName.startsWith('bucket')) { + if (methodName.includes('Put') || methodName === 'bucketPut') { + return 'api.bucket_put'; + } + if (methodName.includes('Get') || methodName === 'bucketGet') { + return 'api.bucket_get'; + } + if (methodName.includes('Head') || methodName === 'bucketHead') { + return 'api.bucket_head'; + } + if (methodName.includes('Delete') || methodName === 'bucketDelete') { + return 'api.bucket_delete'; + } + if (methodName.includes('ACL')) { + return 'api.bucket_acl'; + } + if (methodName.includes('Policy')) { + return 'api.bucket_policy'; + } + if (methodName.includes('Cors')) { + return 'api.bucket_cors'; + } + if (methodName.includes('Lifecycle')) { + return 'api.bucket_lifecycle'; + } + if (methodName.includes('Versioning')) { + return 'api.bucket_versioning'; + } + if (methodName.includes('Tag')) { + return 'api.bucket_tagging'; + } + return 'api.bucket_op'; + } + if (methodName.includes('multipart') || methodName.includes('Multipart')) { + if (methodName.includes('initiate') || methodName.includes('Initiate')) { + return 'api.multipart_initiate'; + } + if (methodName.includes('complete') || methodName.includes('Complete')) { + return 'api.multipart_complete'; + } + if (methodName.includes('Part')) { + return 'api.multipart_upload_part'; + } + if (methodName.includes('list') || methodName.includes('List')) { + return 'api.multipart_list'; + } + return 'api.multipart_op'; + } + if (methodName.includes('service') || methodName.includes('Service')) { + return 'api.service_get'; + } + if (methodName.includes('website')) { + return 'api.website'; + } + if (methodName.includes('cors') || methodName.includes('Cors')) { + return 'api.cors_preflight'; + } + return `api.${methodName}`; + }, + }); +} + +function instrumentServices(services) { + return createInstrumentedProxy(services, 'services', { + getSpanName: methodName => { + if (methodName === 'metadataStoreObject') { + return 'services.store_object'; + } + if (methodName === 'deleteObject') { + return 'services.delete_object'; + } + if (methodName === 'getObjectListing') { + return 'services.list_objects'; + } + if (methodName === 'getLifecycleListing') { + return 'services.lifecycle_listing'; + } + if (methodName === 'getService') { + return 'services.list_buckets'; + } + if (methodName.includes('MPU') || methodName.includes('Multipart')) { + if (methodName.includes('Store')) { + return 'services.multipart_store'; + } + if (methodName.includes('Validate')) { + return 'services.multipart_validate'; + } + if (methodName.includes('Mark')) { + return 'services.multipart_mark_complete'; + } + if (methodName.includes('Listing')) { + return 'services.multipart_list'; + } + if (methodName.includes('Part')) { + return 'services.multipart_store_part'; + } + return 'services.multipart_op'; + } + if (methodName.includes('batchDelete')) { + return 'services.batch_delete'; + } + return `services.${methodName}`; + }, + }); +} + +function instrumentApiMethod(apiMethod, methodName) { + if (!enableOtel) { + return apiMethod; + } + + const tracer = trace.getTracer('cloudserver-api-detailed', '1.0.0'); + + return function (...args) { + const request = args.find(arg => arg && arg.method && arg.url); + const attributes = { + 'cloudserver.component': 'api', + 'cloudserver.operation_type': getOperationType('api', methodName), + 'cloudserver.method_name': methodName, + }; + + if (request) { + attributes['http.method'] = request.method; + attributes['cloudserver.api_operation'] = methodName; + } + + const span = tracer.startSpan(`api.${getGenericApiSpanName(methodName)}`, { + kind: SpanKind.INTERNAL, + attributes, + }); + + const callbackIndex = args.findLastIndex(arg => typeof arg === 'function'); + + if (callbackIndex === -1) { + return context.with(trace.setSpan(context.active(), span), () => { + try { + const result = apiMethod.apply(this, args); + + if (result && typeof result.then === 'function') { + return result + .then(value => { + span.setStatus({ code: SpanStatusCode.OK }); + span.end(); + return value; + }) + .catch(error => { + span.recordException(error); + span.setStatus({ code: SpanStatusCode.ERROR }); + span.end(); + throw error; + }); + } + + span.setStatus({ code: SpanStatusCode.OK }); + span.end(); + return result; + } catch (error) { + span.recordException(error); + span.setStatus({ code: SpanStatusCode.ERROR }); + span.end(); + throw error; + } + }); + } + + const originalCallback = args[callbackIndex]; + const wrappedArgs = [...args]; + wrappedArgs[callbackIndex] = function (err, ...results) { + if (err) { + span.recordException(err); + span.setStatus({ code: SpanStatusCode.ERROR }); + if (err.code) { + span.setAttributes({ 'cloudserver.error_code': err.code }); + } + } else { + span.setStatus({ code: SpanStatusCode.OK }); + } + span.end(); + return originalCallback.call(this, err, ...results); + }; + + try { + return context.with(trace.setSpan(context.active(), span), () => + apiMethod.apply(this, wrappedArgs)); + } catch (error) { + span.recordException(error); + span.setStatus({ code: SpanStatusCode.ERROR }); + span.end(); + throw error; + } + }; +} + +function getGenericApiSpanName(methodName) { + if (methodName.includes('object')) { + if (methodName.includes('Put')) { return 'object_put'; } + if (methodName.includes('Get')) { return 'object_get'; } + if (methodName.includes('Head')) { return 'object_head'; } + if (methodName.includes('Delete')) { return 'object_delete'; } + if (methodName.includes('Copy')) { return 'object_copy'; } + return 'object_op'; + } + if (methodName.includes('bucket')) { + if (methodName.includes('Put')) { return 'bucket_put'; } + if (methodName.includes('Get')) { return 'bucket_get'; } + if (methodName.includes('Head')) { return 'bucket_head'; } + if (methodName.includes('Delete')) { return 'bucket_delete'; } + return 'bucket_op'; + } + if (methodName.includes('multipart') || methodName.includes('Multipart')) { + return 'multipart_op'; + } + return methodName.toLowerCase(); +} + +module.exports = { + createInstrumentedProxy, + instrumentVault, + instrumentStorage, + instrumentMetadata, + instrumentApi, + instrumentServices, + instrumentApiMethod, +}; From fb960df6e74a0684f55e10db3ec3eca04597277e Mon Sep 17 00:00:00 2001 From: Thomas Flament Date: Thu, 2 Apr 2026 16:59:51 +0200 Subject: [PATCH 3/7] feat: extract inbound W3C trace context in HTTP server When an inbound request carries traceparent/tracestate headers, extract them via propagation.extract() and scope the entire request processing under that context. This connects cloudserver spans to upstream callers (e.g. NGINX, Beyla) as a single distributed trace. Issue: CLDSRV-884 --- lib/server.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/server.js b/lib/server.js index a5bb364b61..a3584352e3 100644 --- a/lib/server.js +++ b/lib/server.js @@ -7,6 +7,9 @@ const { setServerHeader } = arsenal.s3routes.routesUtils; const { RedisClient, StatsClient } = arsenal.metrics; const monitoringClient = require('./utilities/monitoringHandler'); +const enableOtel = process.env.ENABLE_OTEL === 'true'; +const otelApi = enableOtel ? require('@opentelemetry/api') : null; + const logger = require('./utilities/logger'); const { internalHandlers } = require('./utilities/internalHandlers'); const { clientCheck, healthcheckHandler } = require('./utilities/healthcheckHandler'); @@ -206,7 +209,23 @@ class S3Server { vault, }, }; - arsenal.s3routes.routes(req, res, params, logger, this.config); + + // Extract inbound W3C trace context (traceparent/tracestate) and + // run the entire request within it so that spans created downstream + // are children of the caller's trace. + if (enableOtel && req.headers.traceparent) { + const traceHeaders = { traceparent: req.headers.traceparent }; + if (req.headers.tracestate) { + traceHeaders.tracestate = req.headers.tracestate; + } + const remoteContext = otelApi.propagation.extract( + otelApi.context.active(), traceHeaders); + return otelApi.context.with(remoteContext, () => { + arsenal.s3routes.routes(req, res, params, logger, this.config); + }); + } + + return arsenal.s3routes.routes(req, res, params, logger, this.config); } /** From 207b785544d6949a0e26a3ae33df5948d520e003 Mon Sep 17 00:00:00 2001 From: Thomas Flament Date: Thu, 2 Apr 2026 17:01:56 +0200 Subject: [PATCH 4/7] feat: instrument all S3 API handlers with OTEL spans Wrap all 70+ S3 API handler methods with instrumentApiMethod() from the Proxy-based instrumentation module. Each handler gets a dedicated span with low-cardinality name and operation type attributes when ENABLE_OTEL=true; zero overhead when disabled. Issue: CLDSRV-884 --- lib/api/api.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/lib/api/api.js b/lib/api/api.js index 058e63c2e6..96d9107be7 100644 --- a/lib/api/api.js +++ b/lib/api/api.js @@ -80,6 +80,7 @@ const parseCopySource = require('./apiUtils/object/parseCopySource'); const { tagConditionKeyAuth } = require('./apiUtils/authorization/tagConditionKeys'); const { isRequesterASessionUser } = require('./apiUtils/authorization/permissionChecks'); const checkHttpHeadersSize = require('./apiUtils/object/checkHttpHeadersSize'); +const { instrumentApiMethod } = require('../instrumentation/simple'); const constants = require('../../constants'); const { config } = require('../Config.js'); const { validateMethodChecksumNoChunking } = require('./apiUtils/integrity/validateChecksums'); @@ -493,4 +494,77 @@ const api = { handleAuthorizationResults, }; +// Wrap all S3 API handlers with OTEL instrumentation spans +api.bucketDelete = instrumentApiMethod(bucketDelete, 'bucketDelete'); +api.bucketDeleteCors = instrumentApiMethod(bucketDeleteCors, 'bucketDeleteCors'); +api.bucketDeleteEncryption = instrumentApiMethod(bucketDeleteEncryption, 'bucketDeleteEncryption'); +api.bucketDeleteWebsite = instrumentApiMethod(bucketDeleteWebsite, 'bucketDeleteWebsite'); +api.bucketDeleteLifecycle = instrumentApiMethod(bucketDeleteLifecycle, 'bucketDeleteLifecycle'); +api.bucketDeletePolicy = instrumentApiMethod(bucketDeletePolicy, 'bucketDeletePolicy'); +api.bucketDeleteQuota = instrumentApiMethod(bucketDeleteQuota, 'bucketDeleteQuota'); +api.bucketDeleteRateLimit = instrumentApiMethod(bucketDeleteRateLimit, 'bucketDeleteRateLimit'); +api.bucketGet = instrumentApiMethod(bucketGet, 'bucketGet'); +api.bucketGetACL = instrumentApiMethod(bucketGetACL, 'bucketGetACL'); +api.bucketGetCors = instrumentApiMethod(bucketGetCors, 'bucketGetCors'); +api.bucketGetVersioning = instrumentApiMethod(bucketGetVersioning, 'bucketGetVersioning'); +api.bucketGetWebsite = instrumentApiMethod(bucketGetWebsite, 'bucketGetWebsite'); +api.bucketGetLocation = instrumentApiMethod(bucketGetLocation, 'bucketGetLocation'); +api.bucketGetLifecycle = instrumentApiMethod(bucketGetLifecycle, 'bucketGetLifecycle'); +api.bucketGetNotification = instrumentApiMethod(bucketGetNotification, 'bucketGetNotification'); +api.bucketGetObjectLock = instrumentApiMethod(bucketGetObjectLock, 'bucketGetObjectLock'); +api.bucketGetPolicy = instrumentApiMethod(bucketGetPolicy, 'bucketGetPolicy'); +api.bucketGetQuota = instrumentApiMethod(bucketGetQuota, 'bucketGetQuota'); +api.bucketGetEncryption = instrumentApiMethod(bucketGetEncryption, 'bucketGetEncryption'); +api.bucketGetRateLimit = instrumentApiMethod(bucketGetRateLimit, 'bucketGetRateLimit'); +api.bucketHead = instrumentApiMethod(bucketHead, 'bucketHead'); +api.bucketPut = instrumentApiMethod(bucketPut, 'bucketPut'); +api.bucketPutACL = instrumentApiMethod(bucketPutACL, 'bucketPutACL'); +api.bucketPutCors = instrumentApiMethod(bucketPutCors, 'bucketPutCors'); +api.bucketPutVersioning = instrumentApiMethod(bucketPutVersioning, 'bucketPutVersioning'); +api.bucketPutTagging = instrumentApiMethod(bucketPutTagging, 'bucketPutTagging'); +api.bucketDeleteTagging = instrumentApiMethod(bucketDeleteTagging, 'bucketDeleteTagging'); +api.bucketGetTagging = instrumentApiMethod(bucketGetTagging, 'bucketGetTagging'); +api.bucketPutWebsite = instrumentApiMethod(bucketPutWebsite, 'bucketPutWebsite'); +api.bucketPutReplication = instrumentApiMethod(bucketPutReplication, 'bucketPutReplication'); +api.bucketPutLifecycle = instrumentApiMethod(bucketPutLifecycle, 'bucketPutLifecycle'); +api.bucketPutNotification = instrumentApiMethod(bucketPutNotification, 'bucketPutNotification'); +api.bucketPutEncryption = instrumentApiMethod(bucketPutEncryption, 'bucketPutEncryption'); +api.bucketPutPolicy = instrumentApiMethod(bucketPutPolicy, 'bucketPutPolicy'); +api.bucketPutObjectLock = instrumentApiMethod(bucketPutObjectLock, 'bucketPutObjectLock'); +api.bucketUpdateQuota = instrumentApiMethod(bucketUpdateQuota, 'bucketUpdateQuota'); +api.bucketPutRateLimit = instrumentApiMethod(bucketPutRateLimit, 'bucketPutRateLimit'); +api.bucketGetReplication = instrumentApiMethod(bucketGetReplication, 'bucketGetReplication'); +api.bucketDeleteReplication = instrumentApiMethod(bucketDeleteReplication, 'bucketDeleteReplication'); +api.bucketGetLogging = instrumentApiMethod(bucketGetLogging, 'bucketGetLogging'); +api.bucketPutLogging = instrumentApiMethod(bucketPutLogging, 'bucketPutLogging'); +api.corsPreflight = instrumentApiMethod(corsPreflight, 'corsPreflight'); +api.completeMultipartUpload = instrumentApiMethod(completeMultipartUpload, 'completeMultipartUpload'); +api.initiateMultipartUpload = instrumentApiMethod(initiateMultipartUpload, 'initiateMultipartUpload'); +api.listMultipartUploads = instrumentApiMethod(listMultipartUploads, 'listMultipartUploads'); +api.listParts = instrumentApiMethod(listParts, 'listParts'); +api.metadataSearch = instrumentApiMethod(metadataSearch, 'metadataSearch'); +api.multiObjectDelete = instrumentApiMethod(multiObjectDelete, 'multiObjectDelete'); +api.multipartDelete = instrumentApiMethod(multipartDelete, 'multipartDelete'); +api.objectCopy = instrumentApiMethod(objectCopy, 'objectCopy'); +api.objectDelete = instrumentApiMethod(objectDelete, 'objectDelete'); +api.objectDeleteTagging = instrumentApiMethod(objectDeleteTagging, 'objectDeleteTagging'); +api.objectGet = instrumentApiMethod(objectGet, 'objectGet'); +api.objectGetACL = instrumentApiMethod(objectGetACL, 'objectGetACL'); +api.objectGetAttributes = instrumentApiMethod(objectGetAttributes, 'objectGetAttributes'); +api.objectGetLegalHold = instrumentApiMethod(objectGetLegalHold, 'objectGetLegalHold'); +api.objectGetRetention = instrumentApiMethod(objectGetRetention, 'objectGetRetention'); +api.objectGetTagging = instrumentApiMethod(objectGetTagging, 'objectGetTagging'); +api.objectHead = instrumentApiMethod(objectHead, 'objectHead'); +api.objectPut = instrumentApiMethod(objectPut, 'objectPut'); +api.objectPutACL = instrumentApiMethod(objectPutACL, 'objectPutACL'); +api.objectPutLegalHold = instrumentApiMethod(objectPutLegalHold, 'objectPutLegalHold'); +api.objectPutTagging = instrumentApiMethod(objectPutTagging, 'objectPutTagging'); +api.objectPutPart = instrumentApiMethod(objectPutPart, 'objectPutPart'); +api.objectPutCopyPart = instrumentApiMethod(objectPutCopyPart, 'objectPutCopyPart'); +api.objectPutRetention = instrumentApiMethod(objectPutRetention, 'objectPutRetention'); +api.objectRestore = instrumentApiMethod(objectRestore, 'objectRestore'); +api.serviceGet = instrumentApiMethod(serviceGet, 'serviceGet'); +api.websiteGet = instrumentApiMethod(website, 'websiteGet'); +api.websiteHead = instrumentApiMethod(website, 'websiteHead'); + module.exports = api; From 48e3a6ac748f4aa34f5326b48746c5ef3d293cf6 Mon Sep 17 00:00:00 2001 From: Thomas Flament Date: Mon, 13 Apr 2026 17:51:50 +0200 Subject: [PATCH 5/7] chore: bump arsenal to ARSN-572 PoC branch for e2e trace context testing Temporarily point the arsenal dep at scality/Arsenal#improvement/ARSN-572/trace-context (commit 01693cde) so we can validate end-to-end trace context propagation from cloudserver HTTP spans through to the MongoDB oplog on a test cluster. ARSN-572 adds traceContext plumbing on metadata writes; cloudserver needs no code change thanks to OTEL async context hooks. Revert to a clean #8.3.x release tag before this PR merges, once ARSN-572 ships. Issue: CLDSRV-884 --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index d4f028beba..55ea80aa2d 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@opentelemetry/sdk-node": "^0.55.0", "@opentelemetry/sdk-trace-base": "^1.28.0", "@smithy/node-http-handler": "^3.0.0", - "arsenal": "git+https://github.com/scality/Arsenal#8.3.9", + "arsenal": "git+https://github.com/scality/Arsenal#improvement/ARSN-572/trace-context", "async": "2.6.4", "bucketclient": "scality/bucketclient#8.2.7", "bufferutil": "^4.0.8", diff --git a/yarn.lock b/yarn.lock index 6d9697cc79..7eafdf3fe5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7287,9 +7287,9 @@ arraybuffer.prototype.slice@^1.0.4: optionalDependencies: ioctl "^2.0.2" -"arsenal@git+https://github.com/scality/Arsenal#8.3.9": - version "8.3.9" - resolved "git+https://github.com/scality/Arsenal#51e5b761f7f0612a722c828fa3d43b438c50ab7c" +"arsenal@git+https://github.com/scality/Arsenal#improvement/ARSN-572/trace-context": + version "8.3.10" + resolved "git+https://github.com/scality/Arsenal#39233c826f16f19d867d83f74f0bbc3ba4d2244b" dependencies: "@aws-sdk/client-kms" "^3.975.0" "@aws-sdk/client-s3" "^3.975.0" @@ -7298,6 +7298,7 @@ arraybuffer.prototype.slice@^1.0.4: "@azure/identity" "^4.13.0" "@azure/storage-blob" "^12.31.0" "@js-sdsl/ordered-set" "^4.4.2" + "@opentelemetry/api" "^1.9.0" "@scality/hdclient" "^1.3.1" "@smithy/node-http-handler" "^4.3.0" "@smithy/protocol-http" "^5.3.5" From 99d0979fa29ba8053acf6344b5e0b2e53c47967c Mon Sep 17 00:00:00 2001 From: Thomas Flament Date: Wed, 15 Apr 2026 16:59:47 +0200 Subject: [PATCH 6/7] feat: harden OTEL trust boundaries and honor upstream sampling Three changes to make OTEL tracing safe to enable on public ingress: 1. Skip probe/scrape noise. lib/tracing/healthPaths.js exports an isHealthPath() predicate backed by an explicit Set of k8s probe and Prometheus scrape endpoints. Wired into HttpInstrumentation as ignoreIncomingRequestHook so /live /ready /_/healthcheck /_/healthcheck/deep /metrics and OPTIONS preflight requests produce no spans at all. 2. Don't leak trace context to untrusted destinations. buildTrustedHosts() derives an allowlist of hostnames from the cloudserver Config (vaultd, dataClient, metadataClient, bucketd bootstrap, kmip transports, kms, scuba, utapi, mongo replica set, management push/endpoint, local aliases). HttpInstrumentation.requestHook fires after propagation injection but before the request hits the wire: outbound requests to any host not in the allowlist have their traceparent/tracestate headers stripped and the client span is annotated with scality.trace.suppressed=true. The span is kept (observability preserved), only the header leak is prevented. 3. Honor upstream sampling. Switch from TraceIdRatioBasedSampler to ParentBasedSampler({ root: TraceIdRatioBasedSampler(ratio) }) so an inbound traceparent with sampled=1 from NGINX/Beyla gets respected end to end. Previously a 1% sampler at cloudserver multiplied with a 1% sampler at vault giving 0.01% effective coverage and gap-ridden traces. Unit tests cover extractHost URL/host:port parsing, every Config host shape resolved by buildTrustedHosts (acts as a tripwire when new backends are added without updating the allowlist), and all isHealthPath matching rules. All code is behind the ENABLE_OTEL gate; @opentelemetry/* packages are not required when the flag is unset. Issue: CLDSRV-884 --- lib/otel.js | 160 ++++++++++++++++++++++++++++++- lib/tracing/healthPaths.js | 33 +++++++ tests/unit/lib/otel.spec.js | 184 ++++++++++++++++++++++++++++++++++++ 3 files changed, 373 insertions(+), 4 deletions(-) create mode 100644 lib/tracing/healthPaths.js create mode 100644 tests/unit/lib/otel.spec.js diff --git a/lib/otel.js b/lib/otel.js index 9823333eed..84a12338e0 100644 --- a/lib/otel.js +++ b/lib/otel.js @@ -2,6 +2,113 @@ const enableOtel = process.env.ENABLE_OTEL === 'true'; +/** + * Extract a bare hostname from a `host[:port]` string or a URL. + * Returns undefined when the input is not a non-empty string. + */ +function extractHost(s) { + if (typeof s !== 'string' || s.length === 0) { + return undefined; + } + // Try to parse as URL first (handles http://, https://, ws://, wss://). + if (s.includes('://')) { + try { + return new URL(s).hostname.toLowerCase(); + } catch { + // fall through to plain host:port parsing + } + } + // Plain "host:port" or bare "host". + // IPv6 literals are bracketed; strip brackets after splitting on final ':'. + const hostPart = s.includes(':') && !s.startsWith('[') + ? s.split(':')[0] + : s.replace(/^\[|\]$/g, ''); + return hostPart.toLowerCase(); +} + +/** + * Build the set of hosts we consider "trusted" for outbound trace context + * propagation. Any HTTP egress to a host not in this set will have its + * `traceparent`/`tracestate` headers stripped — the request still gets a + * client span (we still want to observe the call), but the trace ID is + * not leaked to an external destination. + * + * The set is derived from cloudserver's own Config.js, so it stays honest + * automatically as new backends are added. A unit test asserts this. + * + * @param {object} config - the cloudserver Config instance + * @returns {Set} + */ +function buildTrustedHosts(config) { + const hosts = new Set(['localhost', '127.0.0.1', '::1']); + + const add = v => { + const h = extractHost(v); + if (h) { + hosts.add(h); + } + }; + + if (!config) { + return hosts; + } + + // Core daemons + add(config.vaultd && config.vaultd.host); + add(config.dataClient && config.dataClient.host); + add(config.metadataClient && config.metadataClient.host); + add(config.pfsClient && config.pfsClient.host); + add(config.cdmi && config.cdmi.host); + + // bucketd bootstrap: array of "host:port" + if (config.bucketd && Array.isArray(config.bucketd.bootstrap)) { + config.bucketd.bootstrap.forEach(add); + } + + // KMIP: transport is either a single object or an array of objects, + // each with tls.host + if (config.kmip && config.kmip.transport) { + const transports = Array.isArray(config.kmip.transport) + ? config.kmip.transport + : [config.kmip.transport]; + transports.forEach(t => add(t && t.tls && t.tls.host)); + } + + // KMS AWS + if (config.kmsAWS && config.kmsAWS.endpoint) { + add(config.kmsAWS.endpoint); + } + + // Scuba (quotas) + add(config.scuba && config.scuba.host); + + // Utapi + add(config.utapi && config.utapi.host); + + // Local cache (Redis) + add(config.localCache && config.localCache.host); + + // Management agent (local websocket client target) + add(config.managementAgent && config.managementAgent.host); + + // MongoDB replica set: "host:port,host:port,..." + if (config.mongodb && typeof config.mongodb.replicaSetHosts === 'string') { + config.mongodb.replicaSetHosts.split(',').forEach(add); + } + + // Management push/management endpoints (set via env vars consumed by + // lib/management/index.js — we read them directly here since Config.js + // does not carry them). + if (process.env.PUSH_ENDPOINT) { + add(process.env.PUSH_ENDPOINT); + } + if (process.env.MANAGEMENT_ENDPOINT) { + add(process.env.MANAGEMENT_ENDPOINT); + } + + return hosts; +} + let sdk = null; if (enableOtel) { @@ -9,8 +116,13 @@ if (enableOtel) { const { Resource } = require('@opentelemetry/resources'); const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); - const { TraceIdRatioBasedSampler } = require('@opentelemetry/sdk-trace-base'); + const { + ParentBasedSampler, + TraceIdRatioBasedSampler, + } = require('@opentelemetry/sdk-trace-base'); const { version } = require('../package.json'); + const { config } = require('./Config'); + const { isHealthPath } = require('./tracing/healthPaths'); const exportUrl = process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || 'http://otel-collector.default.svc.cluster.local:4318/v1/traces'; @@ -22,6 +134,37 @@ if (enableOtel) { const parsedRatio = parseFloat(process.env.OTEL_SAMPLING_RATIO); const samplingRatio = Number.isFinite(parsedRatio) ? parsedRatio : 0.01; + const TRUSTED_HOSTS = buildTrustedHosts(config); + + // Filter for incoming requests: drop spans on probe/scrape paths and + // CORS preflight requests entirely — they're high-volume and + // zero-value for tracing. + const ignoreIncomingRequestHook = req => { + if (req.method === 'OPTIONS') { + return true; + } + return isHealthPath(req.url); + }; + + // Hook that fires after propagation has injected traceparent/tracestate + // on outbound requests but before the request is flushed on the wire. + // We keep the client span (still useful observability) but strip the + // trace context headers when the destination is not in our trusted + // allowlist, so trace IDs don't leak to external services. + const requestHook = (span, request) => { + const hostHeader = (request.getHeader && request.getHeader('host')) || ''; + const host = hostHeader.toString().toLowerCase().split(':')[0]; + if (!TRUSTED_HOSTS.has(host)) { + if (typeof request.removeHeader === 'function') { + request.removeHeader('traceparent'); + request.removeHeader('tracestate'); + } + if (span && typeof span.setAttribute === 'function') { + span.setAttribute('scality.trace.suppressed', true); + } + } + }; + sdk = new NodeSDK({ resource: new Resource({ 'service.name': process.env.OTEL_SERVICE_NAME || 'cloudserver', @@ -29,7 +172,12 @@ if (enableOtel) { 'service.namespace': process.env.OTEL_SERVICE_NAMESPACE || 'scality', }), traceExporter, - sampler: new TraceIdRatioBasedSampler(samplingRatio), + // Honor upstream sampling decisions when a parent context is present + // (e.g. traceparent extracted from NGINX/Beyla). Fall back to the + // ratio-based sampler for root spans originating in cloudserver. + sampler: new ParentBasedSampler({ + root: new TraceIdRatioBasedSampler(samplingRatio), + }), instrumentations: [ getNodeAutoInstrumentations({ '@opentelemetry/instrumentation-fs': { enabled: false }, @@ -39,7 +187,11 @@ if (enableOtel) { enabled: true, requireParentSpan: true, }, - '@opentelemetry/instrumentation-http': { enabled: true }, + '@opentelemetry/instrumentation-http': { + enabled: true, + ignoreIncomingRequestHook, + requestHook, + }, '@opentelemetry/instrumentation-express': { enabled: true }, '@opentelemetry/instrumentation-mongodb': { enabled: true, @@ -59,4 +211,4 @@ if (enableOtel) { process.on('SIGINT', shutdown); } -module.exports = { sdk }; +module.exports = { sdk, buildTrustedHosts, extractHost }; diff --git a/lib/tracing/healthPaths.js b/lib/tracing/healthPaths.js new file mode 100644 index 0000000000..0cbd6ab418 --- /dev/null +++ b/lib/tracing/healthPaths.js @@ -0,0 +1,33 @@ +'use strict'; + +/** + * Explicit set of HTTP paths that should never produce an OTEL span or + * be treated as request entries for tracing purposes. These are k8s probe + * endpoints and the Prometheus scrape path — high-frequency, zero-value + * noise that would otherwise dominate the trace stream. + */ +const HEALTH_PATHS = new Set([ + '/live', + '/ready', + '/_/healthcheck', + '/_/healthcheck/deep', + '/metrics', +]); + +/** + * Returns true when the given URL path (with any query string) corresponds + * to a probe/scrape endpoint that should bypass tracing. + * + * @param {string|undefined} url - the request URL or path, e.g. `/live?x=1` + * @returns {boolean} + */ +function isHealthPath(url) { + if (typeof url !== 'string' || url.length === 0) { + return false; + } + const qIdx = url.indexOf('?'); + const path = qIdx === -1 ? url : url.slice(0, qIdx); + return HEALTH_PATHS.has(path); +} + +module.exports = { HEALTH_PATHS, isHealthPath }; diff --git a/tests/unit/lib/otel.spec.js b/tests/unit/lib/otel.spec.js new file mode 100644 index 0000000000..36a0c164ab --- /dev/null +++ b/tests/unit/lib/otel.spec.js @@ -0,0 +1,184 @@ +'use strict'; + +const assert = require('assert'); + +const { buildTrustedHosts, extractHost } = require('../../../lib/otel'); +const { isHealthPath } = require('../../../lib/tracing/healthPaths'); + +describe('otel.extractHost', () => { + it('extracts hostname from a plain host string', () => { + assert.strictEqual(extractHost('example.com'), 'example.com'); + }); + + it('extracts hostname from a host:port string', () => { + assert.strictEqual(extractHost('example.com:8500'), 'example.com'); + }); + + it('lower-cases the extracted hostname', () => { + assert.strictEqual(extractHost('Example.COM:8500'), 'example.com'); + }); + + it('extracts hostname from an http URL', () => { + assert.strictEqual( + extractHost('http://mongo.example.internal:27017/db'), + 'mongo.example.internal', + ); + }); + + it('extracts hostname from an https URL', () => { + assert.strictEqual( + extractHost('https://push.api.zenko.io/api/v1/instance'), + 'push.api.zenko.io', + ); + }); + + it('returns undefined for empty / non-string input', () => { + assert.strictEqual(extractHost(undefined), undefined); + assert.strictEqual(extractHost(''), undefined); + assert.strictEqual(extractHost(42), undefined); + }); +}); + +describe('otel.buildTrustedHosts', () => { + it('always contains loopback aliases', () => { + const hosts = buildTrustedHosts({}); + assert.ok(hosts.has('localhost')); + assert.ok(hosts.has('127.0.0.1')); + assert.ok(hosts.has('::1')); + }); + + it('handles a missing config gracefully', () => { + const hosts = buildTrustedHosts(); + assert.ok(hosts.has('localhost')); + assert.strictEqual(hosts.size, 3); + }); + + it('includes every host referenced in a full config', () => { + // Snapshot of every host-bearing config key that cloudserver + // consults. If a new config key is added without updating + // buildTrustedHosts, this test must fail — keep the derivation + // honest. + const config = { + vaultd: { host: 'vaultd.zenko.svc.cluster.local' }, + dataClient: { host: 'data.zenko.svc.cluster.local' }, + metadataClient: { host: 'bucketd.zenko.svc.cluster.local' }, + pfsClient: { host: 'pfs.zenko.svc.cluster.local' }, + cdmi: { host: 'cdmi.zenko.svc.cluster.local' }, + bucketd: { + bootstrap: [ + 'bucketd-a.zenko.svc.cluster.local:9000', + 'bucketd-b.zenko.svc.cluster.local:9000', + ], + }, + kmip: { + transport: [ + { tls: { host: 'kmip-a.zenko.svc.cluster.local' } }, + { tls: { host: 'kmip-b.zenko.svc.cluster.local' } }, + ], + }, + kmsAWS: { endpoint: 'https://aws-kms.example.com' }, + scuba: { host: 'scuba.zenko.svc.cluster.local' }, + utapi: { host: 'utapi.zenko.svc.cluster.local' }, + localCache: { host: 'redis.zenko.svc.cluster.local' }, + managementAgent: { host: 'localhost' }, + mongodb: { + replicaSetHosts: + 'mongo-0.zenko.svc.cluster.local:27017,' + + 'mongo-1.zenko.svc.cluster.local:27017,' + + 'mongo-2.zenko.svc.cluster.local:27017', + }, + }; + + const saved = { + PUSH_ENDPOINT: process.env.PUSH_ENDPOINT, + MANAGEMENT_ENDPOINT: process.env.MANAGEMENT_ENDPOINT, + }; + process.env.PUSH_ENDPOINT = 'https://push.api.zenko.io'; + process.env.MANAGEMENT_ENDPOINT = 'https://api.zenko.io'; + try { + const hosts = buildTrustedHosts(config); + const expected = [ + 'vaultd.zenko.svc.cluster.local', + 'data.zenko.svc.cluster.local', + 'bucketd.zenko.svc.cluster.local', + 'pfs.zenko.svc.cluster.local', + 'cdmi.zenko.svc.cluster.local', + 'bucketd-a.zenko.svc.cluster.local', + 'bucketd-b.zenko.svc.cluster.local', + 'kmip-a.zenko.svc.cluster.local', + 'kmip-b.zenko.svc.cluster.local', + 'aws-kms.example.com', + 'scuba.zenko.svc.cluster.local', + 'utapi.zenko.svc.cluster.local', + 'redis.zenko.svc.cluster.local', + 'mongo-0.zenko.svc.cluster.local', + 'mongo-1.zenko.svc.cluster.local', + 'mongo-2.zenko.svc.cluster.local', + 'push.api.zenko.io', + 'api.zenko.io', + ]; + for (const h of expected) { + assert.ok(hosts.has(h), `expected trusted host ${h}`); + } + } finally { + if (saved.PUSH_ENDPOINT === undefined) { + delete process.env.PUSH_ENDPOINT; + } else { + process.env.PUSH_ENDPOINT = saved.PUSH_ENDPOINT; + } + if (saved.MANAGEMENT_ENDPOINT === undefined) { + delete process.env.MANAGEMENT_ENDPOINT; + } else { + process.env.MANAGEMENT_ENDPOINT = saved.MANAGEMENT_ENDPOINT; + } + } + }); + + it('tolerates a single-transport KMIP config object', () => { + const hosts = buildTrustedHosts({ + kmip: { transport: { tls: { host: 'kmip-single.example.com' } } }, + }); + assert.ok(hosts.has('kmip-single.example.com')); + }); + + it('ignores undefined host values', () => { + const hosts = buildTrustedHosts({ + vaultd: {}, + dataClient: {}, + metadataClient: {}, + }); + assert.strictEqual(hosts.size, 3); // only the loopback aliases + }); +}); + +describe('tracing.healthPaths', () => { + it('matches the canonical probe and scrape paths', () => { + [ + '/live', + '/ready', + '/_/healthcheck', + '/_/healthcheck/deep', + '/metrics', + ].forEach(p => assert.strictEqual(isHealthPath(p), true, p)); + }); + + it('matches when a query string is present', () => { + assert.strictEqual(isHealthPath('/live?token=x'), true); + assert.strictEqual(isHealthPath('/metrics?format=prom'), true); + }); + + it('does not match unrelated paths', () => { + [ + '/bucket/key', + '/_/backbeat/data/bucket/key', + '/livez', + '/metrics/custom', + ].forEach(p => assert.strictEqual(isHealthPath(p), false, p)); + }); + + it('returns false for non-string / empty input', () => { + assert.strictEqual(isHealthPath(undefined), false); + assert.strictEqual(isHealthPath(''), false); + assert.strictEqual(isHealthPath(42), false); + }); +}); From 7ac398a3ab02d6b08cf393492071246632287ddf Mon Sep 17 00:00:00 2001 From: Thomas Flament Date: Wed, 15 Apr 2026 17:40:56 +0200 Subject: [PATCH 7/7] fix(otel): trust storage connectors and skip inbound requestHook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two post-deploy fixes found during cluster verification on the OTEL branch: 1. buildTrustedHosts() now also walks Config.locationConstraints and adds hosts from the two direct Scality-owned storage connector shapes: - details.connector.hdclient.bootstrap[*] (hdproxy) - details.connector.sproxyd.bootstrap[*] (sproxyd) Without this, the requestHook stripped traceparent on every data-path call to hdproxy, breaking the trace at cloudserver → hdproxy → hyperiod / hdcontroller boundary (no child spans in Jaeger even though the storage side is OTEL-instrumented). Every other locationType (aws-s3, azure, gcp, wasabi, do-spaces, ceph-radosgw, scality-ring-s3, *-archive, dmf, file, nfs-mount, mem) stays off the allowlist — they're separate clusters, external clouds, or non-HTTP backends, and we don't want trace IDs leaking across cluster boundaries. 2. Extracted the requestHook body into makeRequestHook(trustedHosts) and added an early-return when `typeof request.getHeader !== 'function'`. The hook fires on both inbound IncomingMessage and outbound ClientRequest; only outbound has getHeader. Previously every inbound server span was wrongly tagged scality.trace.suppressed=true — cosmetic but misleading in Jaeger. Matches the guard shape vault2 uses. Unit tests extended: four-shape locationConfig asserts only hdclient and sproxyd hosts are trusted (aws-s3 + scality-ring-s3 excluded); requestHook tests cover inbound-skipped, undefined-request, trusted passthrough, untrusted header strip, and missing-host-header treated as untrusted. Issue: CLDSRV-884 --- lib/otel.js | 81 ++++++++++++++++----- tests/unit/lib/otel.spec.js | 136 +++++++++++++++++++++++++++++++++++- 2 files changed, 197 insertions(+), 20 deletions(-) diff --git a/lib/otel.js b/lib/otel.js index 84a12338e0..14f1c1d000 100644 --- a/lib/otel.js +++ b/lib/otel.js @@ -26,6 +26,42 @@ function extractHost(s) { return hostPart.toLowerCase(); } +/** + * Factory for the OTEL HTTP instrumentation requestHook. Fires after + * propagation has injected trace headers on an outbound request but before + * the request is flushed on the wire. On outbound requests to hosts outside + * `trustedHosts`, strips `traceparent`/`tracestate` and annotates the + * client span with `scality.trace.suppressed=true` (span is preserved so + * we still observe the call — we only suppress the header leak). + * + * The hook receives both inbound server spans (`IncomingMessage`, which + * has no `getHeader` / `removeHeader`) and outbound client spans + * (`ClientRequest`). We short-circuit on inbound to avoid falsely + * tagging server spans as suppressed. + */ +function makeRequestHook(trustedHosts) { + return function requestHook(span, request) { + // Skip inbound server spans: IncomingMessage doesn't expose + // getHeader/removeHeader, and there's no outbound header to + // strip anyway. vault2 uses the same guard shape. + if (!request || typeof request.getHeader !== 'function') { + return; + } + const hostHeader = request.getHeader('host') || ''; + const host = hostHeader.toString().toLowerCase().split(':')[0]; + if (trustedHosts.has(host)) { + return; + } + if (typeof request.removeHeader === 'function') { + request.removeHeader('traceparent'); + request.removeHeader('tracestate'); + } + if (span && typeof span.setAttribute === 'function') { + span.setAttribute('scality.trace.suppressed', true); + } + }; +} + /** * Build the set of hosts we consider "trusted" for outbound trace context * propagation. Any HTTP egress to a host not in this set will have its @@ -106,6 +142,30 @@ function buildTrustedHosts(config) { add(process.env.MANAGEMENT_ENDPOINT); } + // Storage connectors from locationConfig. We only trust the two direct + // Scality-owned connector shapes. Every other locationType (aws-s3, + // azure, gcp, wasabi, do-spaces, ceph-radosgw, scality-ring-s3, + // *-archive, dmf, file, nfs-mount, mem) is either a separate cluster, + // an external cloud, or doesn't talk HTTP — those stay untrusted so + // trace context does not leak across cluster boundaries. + if (config.locationConstraints + && typeof config.locationConstraints === 'object') { + for (const loc of Object.values(config.locationConstraints)) { + const connector = loc && loc.details && loc.details.connector; + if (!connector) { + continue; + } + if (connector.hdclient + && Array.isArray(connector.hdclient.bootstrap)) { + connector.hdclient.bootstrap.forEach(add); + } + if (connector.sproxyd + && Array.isArray(connector.sproxyd.bootstrap)) { + connector.sproxyd.bootstrap.forEach(add); + } + } + } + return hosts; } @@ -146,24 +206,7 @@ if (enableOtel) { return isHealthPath(req.url); }; - // Hook that fires after propagation has injected traceparent/tracestate - // on outbound requests but before the request is flushed on the wire. - // We keep the client span (still useful observability) but strip the - // trace context headers when the destination is not in our trusted - // allowlist, so trace IDs don't leak to external services. - const requestHook = (span, request) => { - const hostHeader = (request.getHeader && request.getHeader('host')) || ''; - const host = hostHeader.toString().toLowerCase().split(':')[0]; - if (!TRUSTED_HOSTS.has(host)) { - if (typeof request.removeHeader === 'function') { - request.removeHeader('traceparent'); - request.removeHeader('tracestate'); - } - if (span && typeof span.setAttribute === 'function') { - span.setAttribute('scality.trace.suppressed', true); - } - } - }; + const requestHook = makeRequestHook(TRUSTED_HOSTS); sdk = new NodeSDK({ resource: new Resource({ @@ -211,4 +254,4 @@ if (enableOtel) { process.on('SIGINT', shutdown); } -module.exports = { sdk, buildTrustedHosts, extractHost }; +module.exports = { sdk, buildTrustedHosts, extractHost, makeRequestHook }; diff --git a/tests/unit/lib/otel.spec.js b/tests/unit/lib/otel.spec.js index 36a0c164ab..eede9712f6 100644 --- a/tests/unit/lib/otel.spec.js +++ b/tests/unit/lib/otel.spec.js @@ -2,7 +2,11 @@ const assert = require('assert'); -const { buildTrustedHosts, extractHost } = require('../../../lib/otel'); +const { + buildTrustedHosts, + extractHost, + makeRequestHook, +} = require('../../../lib/otel'); const { isHealthPath } = require('../../../lib/tracing/healthPaths'); describe('otel.extractHost', () => { @@ -149,6 +153,136 @@ describe('otel.buildTrustedHosts', () => { }); assert.strictEqual(hosts.size, 3); // only the loopback aliases }); + + it('includes hdclient and sproxyd connector hosts from locationConstraints, and only those', () => { + // Four shapes: hdclient (trusted), sproxyd (trusted), + // aws-s3 (untrusted), scality-ring-s3 (untrusted — separate + // cluster, its tracing stack does not cross-reference ours). + const hosts = buildTrustedHosts({ + locationConstraints: { + 'us-east-1': { + type: 'scality', + details: { + connector: { + hdclient: { + bootstrap: [ + 'hdproxy-a.xcore.svc:18888', + 'hdproxy-b.xcore.svc:18888', + ], + }, + }, + }, + }, + 'us-east-2': { + type: 'scality', + details: { + connector: { + sproxyd: { + bootstrap: [ + 'sproxyd-a.ring.svc:81', + 'sproxyd-b.ring.svc:81', + ], + }, + }, + }, + }, + 'aws-bucket': { + type: 'aws_s3', + details: { + awsEndpoint: 's3.us-west-2.amazonaws.com', + bucketName: 'external', + }, + }, + 'ring-remote': { + type: 'scality-ring-s3', + details: { + awsEndpoint: 's3.remote-ring.example.com', + bucketName: 'remote', + }, + }, + }, + }); + // Hdclient + sproxyd hosts are in the set. + assert.ok(hosts.has('hdproxy-a.xcore.svc')); + assert.ok(hosts.has('hdproxy-b.xcore.svc')); + assert.ok(hosts.has('sproxyd-a.ring.svc')); + assert.ok(hosts.has('sproxyd-b.ring.svc')); + // External / remote-cluster endpoints are NOT in the set. + assert.ok(!hosts.has('s3.us-west-2.amazonaws.com')); + assert.ok(!hosts.has('s3.remote-ring.example.com')); + }); + + it('tolerates locationConstraints entries without a connector', () => { + // file, mem, aws_s3 etc. — no connector at all must not throw. + assert.doesNotThrow(() => buildTrustedHosts({ + locationConstraints: { + local: { type: 'file', details: {} }, + mem: { type: 'mem', details: {} }, + }, + })); + }); +}); + +describe('otel.makeRequestHook', () => { + const trusted = new Set(['trusted.example.com', 'localhost']); + const hook = makeRequestHook(trusted); + + function fakeClientRequest(host) { + const removed = []; + return { + _removed: removed, + getHeader(name) { + return name.toLowerCase() === 'host' ? host : undefined; + }, + removeHeader(name) { removed.push(name); }, + }; + } + + function fakeSpan() { + const attrs = {}; + return { + _attrs: attrs, + setAttribute(k, v) { attrs[k] = v; }, + }; + } + + it('is a no-op on inbound IncomingMessage (no getHeader method)', () => { + const span = fakeSpan(); + // IncomingMessage shape: has .headers object, but no getHeader(). + const inbound = { headers: { host: 'untrusted.example.com' } }; + assert.doesNotThrow(() => hook(span, inbound)); + assert.strictEqual(span._attrs['scality.trace.suppressed'], undefined); + }); + + it('is a no-op on undefined request', () => { + const span = fakeSpan(); + assert.doesNotThrow(() => hook(span, undefined)); + assert.strictEqual(span._attrs['scality.trace.suppressed'], undefined); + }); + + it('leaves trusted outbound requests untouched', () => { + const span = fakeSpan(); + const req = fakeClientRequest('trusted.example.com:8500'); + hook(span, req); + assert.deepStrictEqual(req._removed, []); + assert.strictEqual(span._attrs['scality.trace.suppressed'], undefined); + }); + + it('strips trace headers and tags span on untrusted outbound requests', () => { + const span = fakeSpan(); + const req = fakeClientRequest('external.example.com'); + hook(span, req); + assert.deepStrictEqual(req._removed.sort(), ['traceparent', 'tracestate']); + assert.strictEqual(span._attrs['scality.trace.suppressed'], true); + }); + + it('handles missing host header by treating as untrusted', () => { + const span = fakeSpan(); + const req = fakeClientRequest(undefined); + hook(span, req); + assert.deepStrictEqual(req._removed.sort(), ['traceparent', 'tracestate']); + assert.strictEqual(span._attrs['scality.trace.suppressed'], true); + }); }); describe('tracing.healthPaths', () => {