dd-trace 6.12.0 → 6.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +3 -1
- package/ci/init.js +8 -3
- package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
- package/ci/test-optimization-validation/ci-remediation.js +6 -6
- package/ci/test-optimization-validation/command-blocker.js +7 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
- package/ci/test-optimization-validation/framework-adapters/cypress.js +9 -11
- package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
- package/ci/test-optimization-validation/package-check.js +1 -1
- package/ci/test-optimization-validation/report-writer.js +7 -5
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +5 -4
- package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
- package/ci/vitest-no-worker-init-setup.mjs +13 -13
- package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
- package/index.d.ts +127 -26
- package/package.json +22 -19
- package/packages/datadog-esbuild/index.js +3 -1
- package/packages/datadog-instrumentations/src/bunyan.js +4 -2
- package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
- package/packages/datadog-instrumentations/src/fs.js +24 -20
- package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +16 -16
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +266 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +279 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +12 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
- package/packages/datadog-instrumentations/src/jest.js +165 -38
- package/packages/datadog-instrumentations/src/knex.js +76 -0
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +1597 -0
- package/packages/datadog-instrumentations/src/mariadb.js +13 -0
- package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
- package/packages/datadog-instrumentations/src/net.js +14 -17
- package/packages/datadog-instrumentations/src/next.js +212 -62
- package/packages/datadog-instrumentations/src/openai.js +42 -40
- package/packages/datadog-instrumentations/src/pg.js +15 -0
- package/packages/datadog-instrumentations/src/pino.js +15 -4
- package/packages/datadog-instrumentations/src/playwright.js +137 -27
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
- package/packages/datadog-instrumentations/src/sequelize.js +94 -2
- package/packages/datadog-instrumentations/src/undici.js +53 -4
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +44 -7
- package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
- package/packages/datadog-instrumentations/src/vitest-worker.js +82 -14
- package/packages/datadog-instrumentations/src/webdriverio.js +986 -1
- package/packages/datadog-instrumentations/src/winston.js +6 -3
- package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/util.js +2 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
- package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
- package/packages/datadog-plugin-cucumber/src/index.js +0 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
- package/packages/datadog-plugin-cypress/src/support.js +1 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
- package/packages/datadog-plugin-graphql/src/execute.js +998 -196
- package/packages/datadog-plugin-graphql/src/index.js +27 -7
- package/packages/datadog-plugin-graphql/src/jit.js +136 -0
- package/packages/datadog-plugin-graphql/src/request.js +18 -27
- package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
- package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
- package/packages/datadog-plugin-graphql/src/utils.js +208 -120
- package/packages/datadog-plugin-graphql/src/validate.js +10 -23
- package/packages/datadog-plugin-http/src/client.js +2 -15
- package/packages/datadog-plugin-http2/src/client.js +2 -15
- package/packages/datadog-plugin-jest/src/index.js +0 -6
- package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
- package/packages/datadog-plugin-mocha/src/index.js +403 -75
- package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
- package/packages/datadog-plugin-mysql/src/index.js +41 -15
- package/packages/datadog-plugin-net/src/tcp.js +3 -1
- package/packages/datadog-plugin-next/src/index.js +63 -29
- package/packages/datadog-plugin-openai-agents/src/integration.js +15 -11
- package/packages/datadog-plugin-playwright/src/index.js +176 -28
- package/packages/datadog-plugin-undici/src/index.js +29 -56
- package/packages/datadog-plugin-vitest/src/index.js +6 -12
- package/packages/dd-trace/src/aiguard/evaluation.js +96 -21
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -3
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +29 -10
- package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
- package/packages/dd-trace/src/aiguard/noop.js +9 -1
- package/packages/dd-trace/src/aiguard/redaction.js +183 -0
- package/packages/dd-trace/src/aiguard/sdk.js +7 -2
- package/packages/dd-trace/src/aiguard/tags.js +2 -0
- package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
- package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
- package/packages/dd-trace/src/appsec/graphql.js +6 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +10 -9
- package/packages/dd-trace/src/appsec/lambda.js +44 -26
- package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
- package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +7 -150
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +397 -234
- package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
- package/packages/dd-trace/src/ci-visibility/final-flush.js +21 -0
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
- package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
- package/packages/dd-trace/src/config/index.js +75 -14
- package/packages/dd-trace/src/config/parsers.js +11 -1
- package/packages/dd-trace/src/config/stable.js +3 -3
- package/packages/dd-trace/src/config/supported-configurations.json +47 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
- package/packages/dd-trace/src/debugger/config.js +12 -1
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -39
- package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
- package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
- package/packages/dd-trace/src/debugger/index.js +23 -3
- package/packages/dd-trace/src/dogstatsd.js +532 -71
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
- package/packages/dd-trace/src/encode/0.4.js +5 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
- package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
- package/packages/dd-trace/src/exporters/agent/index.js +24 -3
- package/packages/dd-trace/src/exporters/agent/writer.js +28 -11
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
- package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
- package/packages/dd-trace/src/exporters/common/agents.js +28 -6
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
- package/packages/dd-trace/src/exporters/common/request.js +31 -11
- package/packages/dd-trace/src/exporters/common/url.js +40 -1
- package/packages/dd-trace/src/exporters/common/writer.js +31 -7
- package/packages/dd-trace/src/exporters/span-stats/index.js +23 -4
- package/packages/dd-trace/src/external-logger/src/index.js +4 -3
- package/packages/dd-trace/src/flush.js +105 -0
- package/packages/dd-trace/src/id.js +14 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +52 -2
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +420 -105
- package/packages/dd-trace/src/llmobs/experiments/index.js +54 -42
- package/packages/dd-trace/src/llmobs/experiments/noop.js +39 -8
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +21 -0
- package/packages/dd-trace/src/llmobs/index.js +111 -48
- package/packages/dd-trace/src/llmobs/noop.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +8 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +6 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +13 -6
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +5 -7
- package/packages/dd-trace/src/llmobs/util.js +0 -33
- package/packages/dd-trace/src/llmobs/writers/base.js +106 -53
- package/packages/dd-trace/src/log/index.js +7 -1
- package/packages/dd-trace/src/log-submission/log-submission-plugin.js +249 -0
- package/packages/dd-trace/src/noop/span.js +5 -0
- package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
- package/packages/dd-trace/src/openfeature/writers/exposures.js +8 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +45 -3
- package/packages/dd-trace/src/opentelemetry/logs/index.js +9 -25
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +7 -4
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +18 -23
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +8 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +18 -6
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +14 -2
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +25 -5
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +61 -25
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
- package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
- package/packages/dd-trace/src/opentelemetry/tracer.js +26 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +494 -351
- package/packages/dd-trace/src/opentracing/span.js +28 -0
- package/packages/dd-trace/src/otel-thread-ctx.js +23 -5
- package/packages/dd-trace/src/payload-tagging/index.js +2 -1
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
- package/packages/dd-trace/src/plugins/tracing.js +12 -10
- package/packages/dd-trace/src/plugins/util/ci.js +3 -1
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
- package/packages/dd-trace/src/plugins/util/status-validator.js +98 -0
- package/packages/dd-trace/src/plugins/util/test.js +157 -41
- package/packages/dd-trace/src/plugins/util/url.js +2 -2
- package/packages/dd-trace/src/plugins/util/web.js +6 -74
- package/packages/dd-trace/src/profiling/config.js +1 -0
- package/packages/dd-trace/src/profiling/oom.js +11 -5
- package/packages/dd-trace/src/profiling/profiler.js +30 -13
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
- package/packages/dd-trace/src/profiling/profilers/wall.js +14 -14
- package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
- package/packages/dd-trace/src/proxy.js +108 -10
- package/packages/dd-trace/src/remote_config/index.js +319 -101
- package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
- package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
- package/packages/dd-trace/src/runtime_metrics/index.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +10 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +22 -7
- package/packages/dd-trace/src/sampling_rule.js +36 -9
- package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +51 -0
- package/packages/dd-trace/src/serverless/vercel.js +155 -0
- package/packages/dd-trace/src/serverless.js +45 -21
- package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
- package/packages/dd-trace/src/span_stats.js +64 -31
- package/packages/dd-trace/src/startup-log.js +3 -2
- package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
- package/packages/dd-trace/src/telemetry/send-data.js +18 -16
- package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
- package/packages/dd-trace/src/tracer.js +26 -5
- package/packages/dd-trace/src/tracer_metadata.js +11 -3
- package/packages/dd-trace/src/web-tags-cache.js +67 -13
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +0 -53
- package/packages/dd-trace/src/encode/agentless-json.js +0 -209
|
@@ -108,7 +108,7 @@ function stringifyWithRanges (obj, objRanges, loadSensitiveRanges = false) {
|
|
|
108
108
|
value = JSON.stringify(cloneObj, null, 2)
|
|
109
109
|
|
|
110
110
|
if (counter > 0) {
|
|
111
|
-
|
|
111
|
+
let formattedValue = ''
|
|
112
112
|
let outputLength = 0
|
|
113
113
|
let pos = 0
|
|
114
114
|
let rangeKeyIndex = value.indexOf(STRINGIFY_RANGE_KEY)
|
|
@@ -133,13 +133,14 @@ function stringifyWithRanges (obj, objRanges, loadSensitiveRanges = false) {
|
|
|
133
133
|
start,
|
|
134
134
|
end: start + originalValue.length,
|
|
135
135
|
})
|
|
136
|
-
|
|
136
|
+
formattedValue += value.slice(pos, rangeKeyIndex)
|
|
137
|
+
formattedValue += originalValue
|
|
137
138
|
outputLength += cleanLength + originalValue.length
|
|
138
139
|
pos = rangeKeyIndex + matchValue.length
|
|
139
140
|
} else {
|
|
140
141
|
// can't happen, the only way to this to happen is
|
|
141
142
|
// if the JSON has a value starting with the value of STRINGIFY_SENSITIVE_NOT_STRING_KEY
|
|
142
|
-
|
|
143
|
+
formattedValue += value.slice(pos, rangeKeyIndex + STRINGIFY_SENSITIVE_NOT_STRING_KEY.length + 1)
|
|
143
144
|
outputLength += cleanLength + STRINGIFY_SENSITIVE_NOT_STRING_KEY.length + 1
|
|
144
145
|
pos = rangeKeyIndex + STRINGIFY_SENSITIVE_NOT_STRING_KEY.length + 1
|
|
145
146
|
}
|
|
@@ -152,13 +153,13 @@ function stringifyWithRanges (obj, objRanges, loadSensitiveRanges = false) {
|
|
|
152
153
|
start,
|
|
153
154
|
end: start + Number.parseInt(regexRes[1], 10),
|
|
154
155
|
})
|
|
155
|
-
|
|
156
|
+
formattedValue += value.slice(pos, rangeKeyIndex)
|
|
156
157
|
outputLength += cleanLength
|
|
157
158
|
pos = rangeKeyIndex + regexRes[0].length
|
|
158
159
|
} else {
|
|
159
160
|
// can't happen, the only way to this to happen is
|
|
160
161
|
// if the JSON has a value starting with the value of STRINGIFY_SENSITIVE_KEY
|
|
161
|
-
|
|
162
|
+
formattedValue += value.slice(pos, rangeKeyIndex + STRINGIFY_SENSITIVE_KEY.length)
|
|
162
163
|
outputLength += cleanLength + STRINGIFY_SENSITIVE_KEY.length
|
|
163
164
|
pos = rangeKeyIndex + STRINGIFY_SENSITIVE_KEY.length
|
|
164
165
|
}
|
|
@@ -175,13 +176,13 @@ function stringifyWithRanges (obj, objRanges, loadSensitiveRanges = false) {
|
|
|
175
176
|
}))
|
|
176
177
|
ranges.push(...updatedRanges)
|
|
177
178
|
|
|
178
|
-
|
|
179
|
+
formattedValue += value.slice(pos, rangeKeyIndex)
|
|
179
180
|
outputLength += cleanLength
|
|
180
181
|
pos = rangeKeyIndex + regexRes[0].length
|
|
181
182
|
} else {
|
|
182
183
|
// can't happen, the only way to this to happen is
|
|
183
184
|
// if the JSON has a value starting with the value of STRINGIFY_RANGE_KEY
|
|
184
|
-
|
|
185
|
+
formattedValue += value.slice(pos, rangeKeyIndex + STRINGIFY_RANGE_KEY.length)
|
|
185
186
|
outputLength += cleanLength + STRINGIFY_RANGE_KEY.length
|
|
186
187
|
pos = rangeKeyIndex + STRINGIFY_RANGE_KEY.length
|
|
187
188
|
}
|
|
@@ -190,8 +191,8 @@ function stringifyWithRanges (obj, objRanges, loadSensitiveRanges = false) {
|
|
|
190
191
|
rangeKeyIndex = value.indexOf(STRINGIFY_RANGE_KEY, pos)
|
|
191
192
|
}
|
|
192
193
|
|
|
193
|
-
|
|
194
|
-
value =
|
|
194
|
+
formattedValue += value.slice(pos)
|
|
195
|
+
value = formattedValue
|
|
195
196
|
}
|
|
196
197
|
} else {
|
|
197
198
|
value = JSON.stringify(obj, null, 2)
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
const { HTTP_CLIENT_IP } = require('../../../../ext/tags')
|
|
4
4
|
|
|
5
5
|
const log = require('../log')
|
|
6
|
+
const { isEmpty } = require('../util')
|
|
6
7
|
const addresses = require('./addresses')
|
|
8
|
+
const apiSecurity = require('./api_security')
|
|
7
9
|
const Reporter = require('./reporter')
|
|
8
10
|
const waf = require('./waf')
|
|
9
11
|
|
|
@@ -22,7 +24,7 @@ const activeInvocations = new WeakMap()
|
|
|
22
24
|
*/
|
|
23
25
|
function onLambdaStartInvocation (data) {
|
|
24
26
|
try {
|
|
25
|
-
const { span, headers, method, path, query, body, clientIp, pathParams, cookies } = data
|
|
27
|
+
const { span, headers, method, path, query, body, clientIp, pathParams, cookies, route } = data
|
|
26
28
|
|
|
27
29
|
if (!span) {
|
|
28
30
|
log.warn('[ASM] No span provided in Lambda start invocation')
|
|
@@ -30,7 +32,7 @@ function onLambdaStartInvocation (data) {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const req = { headers: headers ?? {} }
|
|
33
|
-
activeInvocations.set(span, req)
|
|
35
|
+
activeInvocations.set(span, { req, method, route })
|
|
34
36
|
|
|
35
37
|
span.addTags({
|
|
36
38
|
'_dd.appsec.enabled': 1,
|
|
@@ -80,8 +82,8 @@ function onLambdaStartInvocation (data) {
|
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
/**
|
|
83
|
-
* Maps response data to WAF addresses, runs a final
|
|
84
|
-
* disposes the WAF context, and finishes the request report.
|
|
85
|
+
* Maps response data to WAF addresses, takes the API Security sampling decision, runs a final
|
|
86
|
+
* WAF pass, disposes the WAF context, and finishes the request report.
|
|
85
87
|
*
|
|
86
88
|
* @param {{ span: object, statusCode: string | undefined,
|
|
87
89
|
* responseHeaders: Record<string, string> | undefined }} data
|
|
@@ -99,31 +101,47 @@ function onLambdaEndInvocation (data) {
|
|
|
99
101
|
return
|
|
100
102
|
}
|
|
101
103
|
|
|
102
|
-
const req = activeInvocations.get(span)
|
|
104
|
+
const { req, method, route } = activeInvocations.get(span)
|
|
103
105
|
activeInvocations.delete(span)
|
|
104
106
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
107
|
+
try {
|
|
108
|
+
const persistent = {}
|
|
109
|
+
|
|
110
|
+
if (statusCode) {
|
|
111
|
+
persistent[addresses.HTTP_INCOMING_RESPONSE_CODE] = String(statusCode)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (responseHeaders) {
|
|
115
|
+
const filteredHeaders = { ...responseHeaders }
|
|
116
|
+
delete filteredHeaders['set-cookie']
|
|
117
|
+
persistent[addresses.HTTP_INCOMING_RESPONSE_HEADERS] = filteredHeaders
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const samplingDecision = apiSecurity.sampleRootSpanRequest(span, {
|
|
121
|
+
method,
|
|
122
|
+
statusCode,
|
|
123
|
+
route,
|
|
124
|
+
// The tracer does not block in Lambda yet, so a response is never a blocked one.
|
|
125
|
+
blocked: false,
|
|
126
|
+
}, true)
|
|
127
|
+
|
|
128
|
+
if (samplingDecision === apiSecurity.SamplingDecision.SAMPLE) {
|
|
129
|
+
persistent[addresses.WAF_CONTEXT_PROCESSOR] = { 'extract-schema': true }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let wafResult
|
|
133
|
+
if (!isEmpty(persistent)) {
|
|
134
|
+
wafResult = waf.run({ persistent }, req, undefined, span)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
apiSecurity.reportRootSpanRequest(span, samplingDecision, wafResult)
|
|
138
|
+
} finally {
|
|
139
|
+
// The execution environment outlives the invocation, so the native WAF context and the
|
|
140
|
+
// module-level metrics queue must be released even if the work above threw.
|
|
141
|
+
waf.disposeContext(req)
|
|
142
|
+
|
|
143
|
+
Reporter.finishRequest(req, null, {}, undefined, span)
|
|
118
144
|
}
|
|
119
|
-
|
|
120
|
-
if (hasPersistentData) {
|
|
121
|
-
waf.run({ persistent }, req, undefined, span)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
waf.disposeContext(req)
|
|
125
|
-
|
|
126
|
-
Reporter.finishRequest(req, null, {}, undefined, span)
|
|
127
145
|
} catch (err) {
|
|
128
146
|
log.error('[ASM] Error in Lambda end-invocation handler', err)
|
|
129
147
|
}
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
class JSONEncoder {
|
|
4
|
-
|
|
4
|
+
#bytes = 2
|
|
5
|
+
#maxBytes
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {number} [maxBytes]
|
|
9
|
+
*/
|
|
10
|
+
constructor (maxBytes) {
|
|
11
|
+
this.#maxBytes = maxBytes
|
|
5
12
|
this.payloads = []
|
|
6
13
|
}
|
|
7
14
|
|
|
8
15
|
encode (payload) {
|
|
16
|
+
if (this.#maxBytes !== undefined) {
|
|
17
|
+
const serializedPayload = JSON.stringify(payload) ?? 'null'
|
|
18
|
+
const payloadBytes = Buffer.byteLength(serializedPayload)
|
|
19
|
+
const separatorBytes = this.payloads.length === 0 ? 0 : 1
|
|
20
|
+
if (payloadBytes + separatorBytes > this.#maxBytes - this.#bytes) return false
|
|
21
|
+
this.#bytes += payloadBytes + separatorBytes
|
|
22
|
+
this.payloads.push(serializedPayload)
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
9
25
|
this.payloads.push(payload)
|
|
26
|
+
return true
|
|
10
27
|
}
|
|
11
28
|
|
|
12
29
|
count () {
|
|
@@ -14,11 +31,24 @@ class JSONEncoder {
|
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
reset () {
|
|
34
|
+
this.#bytes = 2
|
|
17
35
|
this.payloads = []
|
|
18
36
|
}
|
|
19
37
|
|
|
20
38
|
makePayload () {
|
|
21
|
-
|
|
39
|
+
let data
|
|
40
|
+
if (this.#maxBytes === undefined) {
|
|
41
|
+
data = JSON.stringify(this.payloads)
|
|
42
|
+
} else if (this.payloads.length === 0) {
|
|
43
|
+
data = ['[', ']']
|
|
44
|
+
} else {
|
|
45
|
+
data = new Array(this.payloads.length * 2 + 1)
|
|
46
|
+
data[0] = '['
|
|
47
|
+
for (let index = 0; index < this.payloads.length; index++) {
|
|
48
|
+
data[index * 2 + 1] = this.payloads[index]
|
|
49
|
+
data[index * 2 + 2] = index === this.payloads.length - 1 ? ']' : ','
|
|
50
|
+
}
|
|
51
|
+
}
|
|
22
52
|
this.reset()
|
|
23
53
|
return data
|
|
24
54
|
}
|
|
@@ -10,6 +10,7 @@ const { DEBUGGER_INPUT_V1 } = require('../../../debugger/constants')
|
|
|
10
10
|
|
|
11
11
|
// Product-specific discovery: newest advertised version, skip v3 (citestcycle), gzip if >= v4.
|
|
12
12
|
// Shared `evp_proxy` discovery is an explicit path allowlist and does not cover this contract.
|
|
13
|
+
const AGENT_INFO_TIMEOUT_MS = 5000
|
|
13
14
|
const AGENT_EVP_PROXY_PATH_PREFIX = '/evp_proxy/v'
|
|
14
15
|
const AGENT_EVP_PROXY_PATH_REGEX = /\/evp_proxy\/v(\d+)\/?/
|
|
15
16
|
|
|
@@ -47,14 +48,19 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
|
|
|
47
48
|
} = config
|
|
48
49
|
|
|
49
50
|
const initializationController = new AbortController()
|
|
50
|
-
const initializationOptions = {
|
|
51
|
+
const initializationOptions = {
|
|
52
|
+
deadline: Date.now() + AGENT_INFO_TIMEOUT_MS,
|
|
53
|
+
signal: initializationController.signal,
|
|
54
|
+
// Test runners await agent discovery before starting. A detached retry can let Node exit
|
|
55
|
+
// while that promise is still pending because promises alone do not keep the event loop alive.
|
|
56
|
+
keepProcessAlive: true,
|
|
57
|
+
}
|
|
51
58
|
this._initializationRequest = {
|
|
52
59
|
controller: initializationController,
|
|
53
60
|
options: initializationOptions,
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
fetchAgentInfo(this._url, (err, agentInfo) => {
|
|
57
|
-
const initializationFinalFlush = this._initializationRequest?.finalFlush
|
|
58
64
|
this._initializationRequest = undefined
|
|
59
65
|
const initializationAborted = initializationController.signal.aborted
|
|
60
66
|
const agentInfoError = err || (initializationAborted ? initializationController.signal.reason : undefined)
|
|
@@ -112,14 +118,8 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
|
|
|
112
118
|
this._resolveCanUseCiVisProtocol(isEvpCompatible)
|
|
113
119
|
if (initializationAborted) {
|
|
114
120
|
this.resetUncodedTraces()
|
|
115
|
-
this.resetDeferredTestSuiteSpans()
|
|
116
121
|
return
|
|
117
122
|
}
|
|
118
|
-
if (isEvpCompatible) {
|
|
119
|
-
if (initializationFinalFlush) this.exportDeferredTestSuiteSpans()
|
|
120
|
-
} else {
|
|
121
|
-
this.resetDeferredTestSuiteSpans()
|
|
122
|
-
}
|
|
123
123
|
this.exportUncodedTraces()
|
|
124
124
|
this.exportUncodedCoverages()
|
|
125
125
|
}, initializationOptions, request)
|
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
} = require('../../../ci-visibility/telemetry')
|
|
17
17
|
const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
|
|
18
18
|
const BaseWriter = require('../../../exporters/common/writer')
|
|
19
|
+
const { getAgent } = require('../agents')
|
|
19
20
|
const request = require('../request')
|
|
20
21
|
const TestOptimizationRequestTracker = require('./request-tracker')
|
|
21
22
|
|
|
@@ -23,7 +24,7 @@ class Writer extends BaseWriter {
|
|
|
23
24
|
#requestTracker
|
|
24
25
|
|
|
25
26
|
constructor ({ url, evpProxyPrefix = '' }) {
|
|
26
|
-
super(...arguments)
|
|
27
|
+
super({ ...arguments[0], retainOnBackpressure: true })
|
|
27
28
|
this.#requestTracker = new TestOptimizationRequestTracker(this)
|
|
28
29
|
this._url = url
|
|
29
30
|
this._encoder = new CoverageCIVisibilityEncoder(this)
|
|
@@ -51,6 +52,7 @@ class Writer extends BaseWriter {
|
|
|
51
52
|
},
|
|
52
53
|
timeout: 15_000,
|
|
53
54
|
url: this._url,
|
|
55
|
+
agent: getAgent(this._url),
|
|
54
56
|
deadline: flushOptions?.deadline,
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -61,7 +63,7 @@ class Writer extends BaseWriter {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
64
|
-
log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
|
|
66
|
+
log.debug(() => `Request to the intake: ${safeJSONStringify({ ...options, agent: undefined })}`)
|
|
65
67
|
|
|
66
68
|
const startRequestTime = Date.now()
|
|
67
69
|
|
|
@@ -77,11 +79,11 @@ class Writer extends BaseWriter {
|
|
|
77
79
|
if (err) {
|
|
78
80
|
incrementCountMetric(
|
|
79
81
|
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
|
|
80
|
-
{ endpoint: 'code_coverage', statusCode }
|
|
82
|
+
{ endpoint: 'code_coverage', statusCode, errorType: statusCode ? undefined : err.code }
|
|
81
83
|
)
|
|
82
84
|
incrementCountMetric(
|
|
83
85
|
TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
|
|
84
|
-
{ endpoint: 'code_coverage' }
|
|
86
|
+
{ endpoint: 'code_coverage', statusCode, errorType: statusCode ? undefined : err.code }
|
|
85
87
|
)
|
|
86
88
|
log.error('Error sending CI coverage payload', err)
|
|
87
89
|
done(err)
|
|
@@ -5,7 +5,14 @@ const { safeJSONStringify } = require('../../../exporters/common/util')
|
|
|
5
5
|
const { JSONEncoder } = require('../../encode/json-encoder')
|
|
6
6
|
const { DEBUGGER_INPUT_V1 } = require('../../../debugger/constants')
|
|
7
7
|
const BaseWriter = require('../../../exporters/common/writer')
|
|
8
|
+
const {
|
|
9
|
+
incrementCountMetric,
|
|
10
|
+
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
|
|
11
|
+
TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
|
|
12
|
+
} = require('../../../ci-visibility/telemetry')
|
|
8
13
|
|
|
14
|
+
const { getAgent } = require('../agents')
|
|
15
|
+
const { MAX_DI_LOG_BUFFERED_BYTES } = require('../limits')
|
|
9
16
|
const request = require('../request')
|
|
10
17
|
const TestOptimizationRequestTracker = require('./request-tracker')
|
|
11
18
|
|
|
@@ -17,10 +24,10 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
|
|
|
17
24
|
|
|
18
25
|
// TODO: what's a good value for timeout for the logs intake?
|
|
19
26
|
constructor ({ url, timeout = 15_000, isAgentProxy = false }) {
|
|
20
|
-
super(...arguments)
|
|
27
|
+
super({ ...arguments[0], retainOnBackpressure: true })
|
|
21
28
|
this.#requestTracker = new TestOptimizationRequestTracker(this)
|
|
22
29
|
this._url = url
|
|
23
|
-
this._encoder = new JSONEncoder()
|
|
30
|
+
this._encoder = new JSONEncoder(MAX_DI_LOG_BUFFERED_BYTES)
|
|
24
31
|
this._isAgentProxy = isAgentProxy
|
|
25
32
|
this.timeout = timeout
|
|
26
33
|
}
|
|
@@ -46,6 +53,7 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
|
|
|
46
53
|
},
|
|
47
54
|
timeout: this.timeout,
|
|
48
55
|
url: this._url,
|
|
56
|
+
agent: getAgent(this._url),
|
|
49
57
|
deadline: flushOptions?.deadline,
|
|
50
58
|
}
|
|
51
59
|
|
|
@@ -55,10 +63,18 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
|
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
58
|
-
log.debug(() => `Request to the logs intake: ${safeJSONStringify(options)}`)
|
|
66
|
+
log.debug(() => `Request to the logs intake: ${safeJSONStringify({ ...options, agent: undefined })}`)
|
|
59
67
|
|
|
60
|
-
this.#requestTracker.send(request, data, options, (err, res) => {
|
|
68
|
+
this.#requestTracker.send(request, data, options, (err, res, statusCode) => {
|
|
61
69
|
if (err) {
|
|
70
|
+
incrementCountMetric(
|
|
71
|
+
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
|
|
72
|
+
{ endpoint: 'di_logs', statusCode, errorType: statusCode ? undefined : err.code }
|
|
73
|
+
)
|
|
74
|
+
incrementCountMetric(
|
|
75
|
+
TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
|
|
76
|
+
{ endpoint: 'di_logs', statusCode, errorType: statusCode ? undefined : err.code }
|
|
77
|
+
)
|
|
62
78
|
log.error('Error sending DI logs payload', err)
|
|
63
79
|
done(err)
|
|
64
80
|
return
|
|
@@ -1,163 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const BaseWriter = require('../../../exporters/common/writer')
|
|
4
|
+
const FinalFlushRequestTracker = require('../../../exporters/common/final-flush-request-tracker')
|
|
5
|
+
const { createFinalFlushTimeoutError } = require('../../final-flush')
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class TestOptimizationRequestTracker {
|
|
8
|
-
#writer
|
|
9
|
-
#pendingRequests = new Set()
|
|
10
|
-
#finalFlushes = new Set()
|
|
11
|
-
#activeFinalFlush
|
|
12
|
-
|
|
7
|
+
class TestOptimizationRequestTracker extends FinalFlushRequestTracker {
|
|
13
8
|
/**
|
|
14
9
|
* Creates request tracking for a Test Optimization writer.
|
|
15
10
|
*
|
|
16
11
|
* @param {BaseWriter} writer
|
|
17
12
|
*/
|
|
18
13
|
constructor (writer) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* Flushes queued payloads and, for a final flush, waits for requests that were
|
|
24
|
-
* already in flight. The absolute deadline prevents Test Optimization from
|
|
25
|
-
* keeping the test process alive indefinitely.
|
|
26
|
-
*
|
|
27
|
-
* @param {(error?: Error) => void} [done]
|
|
28
|
-
* @param {{ deadline?: number }} [options]
|
|
29
|
-
* @returns {void}
|
|
30
|
-
*/
|
|
31
|
-
flush (done, options) {
|
|
32
|
-
if (options?.deadline === undefined) {
|
|
33
|
-
BaseWriter.prototype.flush.call(this.#writer, done, options)
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const finalFlush = {
|
|
38
|
-
deadline: options.deadline,
|
|
39
|
-
done: done || (() => {}),
|
|
40
|
-
error: undefined,
|
|
41
|
-
requests: new Set(),
|
|
42
|
-
timeoutId: undefined,
|
|
43
|
-
writerDone: false,
|
|
44
|
-
}
|
|
45
|
-
this.#finalFlushes.add(finalFlush)
|
|
46
|
-
|
|
47
|
-
for (const pendingRequest of this.#pendingRequests) {
|
|
48
|
-
this.#attachRequest(finalFlush, pendingRequest)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const remaining = Math.max(0, options.deadline - Date.now())
|
|
52
|
-
finalFlush.timeoutId = setTimeout(() => {
|
|
53
|
-
const error = new Error('Timed out flushing Test Optimization data')
|
|
54
|
-
error.code = FINAL_FLUSH_TIMEOUT_CODE
|
|
55
|
-
|
|
56
|
-
finalFlush.error ||= error
|
|
57
|
-
finalFlush.writerDone = true
|
|
58
|
-
|
|
59
|
-
for (const pendingRequest of finalFlush.requests) {
|
|
60
|
-
pendingRequest.finalFlushes.delete(finalFlush)
|
|
61
|
-
if (pendingRequest.finalFlushes.size === 0) {
|
|
62
|
-
pendingRequest.controller.abort(error)
|
|
63
|
-
this.#pendingRequests.delete(pendingRequest)
|
|
64
|
-
} else {
|
|
65
|
-
this.#updateRequestDeadline(pendingRequest)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
finalFlush.requests.clear()
|
|
69
|
-
this.#finishFinalFlush(finalFlush)
|
|
70
|
-
}, remaining)
|
|
71
|
-
|
|
72
|
-
const previousFinalFlush = this.#activeFinalFlush
|
|
73
|
-
this.#activeFinalFlush = finalFlush
|
|
74
|
-
try {
|
|
75
|
-
BaseWriter.prototype.flush.call(this.#writer, (error) => {
|
|
76
|
-
finalFlush.error ||= error
|
|
77
|
-
finalFlush.writerDone = true
|
|
78
|
-
this.#finishFinalFlush(finalFlush)
|
|
79
|
-
}, options)
|
|
80
|
-
} finally {
|
|
81
|
-
this.#activeFinalFlush = previousFinalFlush
|
|
82
|
-
}
|
|
83
|
-
this.#finishFinalFlush(finalFlush)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Sends and tracks a request so a later final flush can wait for or abort it.
|
|
88
|
-
*
|
|
89
|
-
* @param {Function} request
|
|
90
|
-
* @param {Buffer|string|object} data
|
|
91
|
-
* @param {object} options
|
|
92
|
-
* @param {(error: Error|null, result?: string|null, statusCode?: number,
|
|
93
|
-
* headers?: import('node:http').IncomingHttpHeaders) => void} callback
|
|
94
|
-
* @returns {void}
|
|
95
|
-
*/
|
|
96
|
-
send (request, data, options, callback) {
|
|
97
|
-
const controller = new AbortController()
|
|
98
|
-
const requestOptions = { ...options, signal: controller.signal }
|
|
99
|
-
const pendingRequest = { controller, finalFlushes: new Set(), options: requestOptions }
|
|
100
|
-
this.#pendingRequests.add(pendingRequest)
|
|
101
|
-
if (this.#activeFinalFlush) this.#attachRequest(this.#activeFinalFlush, pendingRequest)
|
|
102
|
-
|
|
103
|
-
request(data, requestOptions, (error, result, statusCode, headers) => {
|
|
104
|
-
if (error) {
|
|
105
|
-
for (const finalFlush of pendingRequest.finalFlushes) finalFlush.error ||= error
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
callback(error, result, statusCode, headers)
|
|
110
|
-
} finally {
|
|
111
|
-
this.#pendingRequests.delete(pendingRequest)
|
|
112
|
-
for (const finalFlush of pendingRequest.finalFlushes) {
|
|
113
|
-
finalFlush.requests.delete(pendingRequest)
|
|
114
|
-
this.#finishFinalFlush(finalFlush)
|
|
115
|
-
}
|
|
116
|
-
pendingRequest.finalFlushes.clear()
|
|
117
|
-
}
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Associates a request with the final flush boundary that must wait for it.
|
|
123
|
-
*
|
|
124
|
-
* @param {object} finalFlush
|
|
125
|
-
* @param {object} pendingRequest
|
|
126
|
-
* @returns {void}
|
|
127
|
-
*/
|
|
128
|
-
#attachRequest (finalFlush, pendingRequest) {
|
|
129
|
-
finalFlush.requests.add(pendingRequest)
|
|
130
|
-
pendingRequest.finalFlushes.add(finalFlush)
|
|
131
|
-
this.#updateRequestDeadline(pendingRequest)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Gives a shared request the latest deadline of the flushes waiting for it.
|
|
136
|
-
*
|
|
137
|
-
* @param {object} pendingRequest
|
|
138
|
-
* @returns {void}
|
|
139
|
-
*/
|
|
140
|
-
#updateRequestDeadline (pendingRequest) {
|
|
141
|
-
let deadline = 0
|
|
142
|
-
for (const finalFlush of pendingRequest.finalFlushes) {
|
|
143
|
-
deadline = Math.max(deadline, finalFlush.deadline)
|
|
144
|
-
}
|
|
145
|
-
pendingRequest.options.deadline = deadline
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Completes a final flush callback once its writer and associated requests
|
|
150
|
-
* have settled.
|
|
151
|
-
*
|
|
152
|
-
* @param {object} finalFlush
|
|
153
|
-
* @returns {void}
|
|
154
|
-
*/
|
|
155
|
-
#finishFinalFlush (finalFlush) {
|
|
156
|
-
if (!this.#finalFlushes.has(finalFlush) || !finalFlush.writerDone || finalFlush.requests.size !== 0) return
|
|
157
|
-
|
|
158
|
-
this.#finalFlushes.delete(finalFlush)
|
|
159
|
-
clearTimeout(finalFlush.timeoutId)
|
|
160
|
-
finalFlush.done(finalFlush.error)
|
|
14
|
+
super(
|
|
15
|
+
(done, options) => BaseWriter.prototype.flushDirect.call(writer, done, options),
|
|
16
|
+
createFinalFlushTimeoutError
|
|
17
|
+
)
|
|
161
18
|
}
|
|
162
19
|
}
|
|
163
20
|
|
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
} = require('../../../ci-visibility/telemetry')
|
|
17
17
|
const { AgentlessCiVisibilityEncoder } = require('../../../encode/agentless-ci-visibility')
|
|
18
18
|
const BaseWriter = require('../../../exporters/common/writer')
|
|
19
|
+
const { getAgent } = require('../agents')
|
|
19
20
|
const request = require('../request')
|
|
20
21
|
const TestOptimizationRequestTracker = require('./request-tracker')
|
|
21
22
|
|
|
@@ -23,11 +24,10 @@ class Writer extends BaseWriter {
|
|
|
23
24
|
#requestTracker
|
|
24
25
|
|
|
25
26
|
constructor ({ url, tags, evpProxyPrefix = '' }) {
|
|
26
|
-
super(...arguments)
|
|
27
|
+
super({ ...arguments[0], retainOnBackpressure: true })
|
|
27
28
|
this.#requestTracker = new TestOptimizationRequestTracker(this)
|
|
28
|
-
const { 'runtime-id': runtimeId, env, service } = tags
|
|
29
29
|
this._url = url
|
|
30
|
-
this._encoder = new AgentlessCiVisibilityEncoder(this, {
|
|
30
|
+
this._encoder = new AgentlessCiVisibilityEncoder(this, { tags })
|
|
31
31
|
this._evpProxyPrefix = evpProxyPrefix
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -52,6 +52,7 @@ class Writer extends BaseWriter {
|
|
|
52
52
|
},
|
|
53
53
|
timeout: 15_000,
|
|
54
54
|
url: this._url,
|
|
55
|
+
agent: getAgent(this._url),
|
|
55
56
|
deadline: flushOptions?.deadline,
|
|
56
57
|
}
|
|
57
58
|
|
|
@@ -62,7 +63,7 @@ class Writer extends BaseWriter {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
65
|
-
log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
|
|
66
|
+
log.debug(() => `Request to the intake: ${safeJSONStringify({ ...options, agent: undefined })}`)
|
|
66
67
|
|
|
67
68
|
const startRequestTime = Date.now()
|
|
68
69
|
|
|
@@ -78,11 +79,11 @@ class Writer extends BaseWriter {
|
|
|
78
79
|
if (err) {
|
|
79
80
|
incrementCountMetric(
|
|
80
81
|
TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
|
|
81
|
-
{ endpoint: 'test_cycle', statusCode }
|
|
82
|
+
{ endpoint: 'test_cycle', statusCode, errorType: statusCode ? undefined : err.code }
|
|
82
83
|
)
|
|
83
84
|
incrementCountMetric(
|
|
84
85
|
TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
|
|
85
|
-
{ endpoint: 'test_cycle' }
|
|
86
|
+
{ endpoint: 'test_cycle', statusCode, errorType: statusCode ? undefined : err.code }
|
|
86
87
|
)
|
|
87
88
|
log.error('Error sending CI agentless payload', err)
|
|
88
89
|
done(err)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const http = require('http')
|
|
4
|
+
const https = require('https')
|
|
5
|
+
|
|
6
|
+
const { createAgents } = require('../../exporters/common/agents')
|
|
7
|
+
|
|
8
|
+
// Finalization can flush several Test Optimization payload types together. Keep media on a separate
|
|
9
|
+
// bounded pool so long uploads cannot consume the sockets needed by trace, coverage, and log writers.
|
|
10
|
+
const maxSockets = 16
|
|
11
|
+
|
|
12
|
+
const payloadAgents = createAgents(maxSockets)
|
|
13
|
+
const mediaAgents = createAgents(maxSockets)
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Selects an agent by intake URL protocol.
|
|
17
|
+
*
|
|
18
|
+
* @param {string|URL|object} url
|
|
19
|
+
* @param {{httpAgent: http.Agent, httpsAgent: https.Agent}} agents
|
|
20
|
+
* @returns {http.Agent|https.Agent}
|
|
21
|
+
*/
|
|
22
|
+
function selectAgent (url, { httpAgent, httpsAgent }) {
|
|
23
|
+
const protocol = url?.protocol
|
|
24
|
+
if (protocol === 'https:' || protocol === 'https') return httpsAgent
|
|
25
|
+
if (protocol === 'http:' || protocol === 'http') return httpAgent
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
return new URL(url).protocol === 'https:' ? httpsAgent : httpAgent
|
|
29
|
+
} catch {
|
|
30
|
+
return String(url).startsWith('https:') ? httpsAgent : httpAgent
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Selects the dedicated Test Optimization payload agent for an intake URL.
|
|
36
|
+
*
|
|
37
|
+
* @param {string|URL|object} url
|
|
38
|
+
* @returns {http.Agent|https.Agent}
|
|
39
|
+
*/
|
|
40
|
+
function getAgent (url) {
|
|
41
|
+
return selectAgent(url, payloadAgents)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Selects the isolated Test Optimization media agent for an intake URL.
|
|
46
|
+
*
|
|
47
|
+
* @param {string|URL|object} url
|
|
48
|
+
* @returns {http.Agent|https.Agent}
|
|
49
|
+
*/
|
|
50
|
+
function getMediaAgent (url) {
|
|
51
|
+
return selectAgent(url, mediaAgents)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = { getAgent, getMediaAgent }
|
|
@@ -11,9 +11,8 @@ class CiValidationWriter {
|
|
|
11
11
|
* @param {object} options.tags tracer tags
|
|
12
12
|
*/
|
|
13
13
|
constructor ({ sink, tags }) {
|
|
14
|
-
const { 'runtime-id': runtimeId, env, service } = tags
|
|
15
14
|
this._sink = sink
|
|
16
|
-
this._encoder = new AgentlessCiVisibilityEncoder(this, {
|
|
15
|
+
this._encoder = new AgentlessCiVisibilityEncoder(this, { tags })
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
/**
|