dd-trace 6.7.0 → 6.9.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/ci/diagnose.js +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +14 -8
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +47 -37
- package/ci/test-optimization-validation/generated-test-contract.js +9 -7
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/offline-output.js +6 -6
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +41 -21
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +377 -84
- package/index.d.ts +175 -14
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +12 -4
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +17 -2
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
- package/packages/datadog-instrumentations/src/cucumber.js +131 -51
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +986 -246
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
- package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/pg.js +180 -6
- package/packages/datadog-instrumentations/src/playwright.js +176 -81
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
- package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
- package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
- package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +3 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +3 -21
- package/packages/datadog-plugin-jest/src/util.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +342 -6
- package/packages/datadog-plugin-next/src/index.js +57 -9
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-pg/src/index.js +65 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +179 -18
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/datadog-webpack/index.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +31 -5
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +13 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +152 -78
- package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
- package/packages/dd-trace/src/llmobs/tagger.js +1 -2
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -6
- package/packages/dd-trace/src/plugins/util/git.js +7 -5
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +356 -86
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +24 -2
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +10 -20
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const getConfig = require('../../config')
|
|
4
4
|
const id = require('../../id')
|
|
5
5
|
const log = require('../../log')
|
|
6
|
+
const { EARLY_FLAKE_DETECTION_RETRY_BUCKETS, createEfdRetryPolicy } = require('../efd-retry-policy')
|
|
6
7
|
const {
|
|
7
8
|
incrementCountMetric,
|
|
8
9
|
distributionMetric,
|
|
@@ -15,21 +16,20 @@ const { writeSettingsToCache } = require('../test-optimization-cache')
|
|
|
15
16
|
const { MAX_RETRIES, validateSettingsResponse } = require('../test-optimization-http-cache-schema')
|
|
16
17
|
const request = require('./request')
|
|
17
18
|
|
|
18
|
-
const DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES = 2
|
|
19
19
|
const DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES = Object.freeze({
|
|
20
20
|
'5s': 10,
|
|
21
21
|
'10s': 5,
|
|
22
22
|
'30s': 3,
|
|
23
23
|
'5m': 2,
|
|
24
24
|
})
|
|
25
|
+
const DEFAULT_EARLY_FLAKE_DETECTION_RETRY_POLICY =
|
|
26
|
+
createEfdRetryPolicy(DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES)
|
|
25
27
|
const DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD = 30
|
|
26
|
-
const EARLY_FLAKE_DETECTION_RETRY_BUCKETS = Object.keys(DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES)
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* @typedef {object} EarlyFlakeDetectionSettings
|
|
30
31
|
* @property {boolean} enabled
|
|
31
|
-
* @property {
|
|
32
|
-
* @property {Readonly<Record<string, number>>} slowTestRetries
|
|
32
|
+
* @property {import('../efd-retry-policy').EfdRetryPolicy} retryPolicy
|
|
33
33
|
* @property {number} faultyThreshold
|
|
34
34
|
*/
|
|
35
35
|
|
|
@@ -90,20 +90,17 @@ function parseEarlyFlakeDetectionSettings (value, isKnownTestsEnabled) {
|
|
|
90
90
|
if (!isRecord(value) || value.enabled !== true) {
|
|
91
91
|
return {
|
|
92
92
|
enabled: false,
|
|
93
|
-
|
|
94
|
-
slowTestRetries: DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES,
|
|
93
|
+
retryPolicy: DEFAULT_EARLY_FLAKE_DETECTION_RETRY_POLICY,
|
|
95
94
|
faultyThreshold: DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
let isValid = true
|
|
100
|
-
let
|
|
101
|
-
let slowTestRetries = DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES
|
|
99
|
+
let retryPolicy = DEFAULT_EARLY_FLAKE_DETECTION_RETRY_POLICY
|
|
102
100
|
if (Object.hasOwn(value, 'slow_test_retries')) {
|
|
103
101
|
const parsedSlowTestRetries = parseSlowTestRetries(value.slow_test_retries)
|
|
104
102
|
if (parsedSlowTestRetries) {
|
|
105
|
-
|
|
106
|
-
numRetries = parsedSlowTestRetries['5s'] ?? DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES
|
|
103
|
+
retryPolicy = createEfdRetryPolicy(parsedSlowTestRetries)
|
|
107
104
|
} else {
|
|
108
105
|
isValid = false
|
|
109
106
|
}
|
|
@@ -120,8 +117,7 @@ function parseEarlyFlakeDetectionSettings (value, isKnownTestsEnabled) {
|
|
|
120
117
|
|
|
121
118
|
return {
|
|
122
119
|
enabled: isKnownTestsEnabled && isValid,
|
|
123
|
-
|
|
124
|
-
slowTestRetries,
|
|
120
|
+
retryPolicy,
|
|
125
121
|
faultyThreshold,
|
|
126
122
|
}
|
|
127
123
|
}
|
|
@@ -180,8 +176,7 @@ function parseLibraryConfigurationResponse (rawJson, config = getConfig(), optio
|
|
|
180
176
|
isItrEnabled: attributes.itr_enabled === true,
|
|
181
177
|
requireGit: attributes.require_git === true,
|
|
182
178
|
isEarlyFlakeDetectionEnabled: earlyFlakeDetection.enabled,
|
|
183
|
-
|
|
184
|
-
earlyFlakeDetectionSlowTestRetries: earlyFlakeDetection.slowTestRetries,
|
|
179
|
+
earlyFlakeDetectionRetryPolicy: earlyFlakeDetection.retryPolicy,
|
|
185
180
|
earlyFlakeDetectionFaultyThreshold: earlyFlakeDetection.faultyThreshold,
|
|
186
181
|
isFlakyTestRetriesEnabled,
|
|
187
182
|
isDiEnabled: attributes.di_enabled === true && isFlakyTestRetriesEnabled,
|
|
@@ -42,7 +42,7 @@ function request (data, options, callback) {
|
|
|
42
42
|
if (url.protocol === 'unix:') {
|
|
43
43
|
opts.socketPath = url.pathname
|
|
44
44
|
} else {
|
|
45
|
-
opts.path
|
|
45
|
+
opts.path ??= url.path
|
|
46
46
|
opts.protocol = url.protocol
|
|
47
47
|
opts.hostname = url.hostname
|
|
48
48
|
opts.port = url.port
|
|
@@ -100,9 +100,9 @@ function request (data, options, callback) {
|
|
|
100
100
|
if (res.statusCode === 429 && !hasRetried) {
|
|
101
101
|
const resetHeader = res.headers['x-ratelimit-reset']
|
|
102
102
|
const resetTs = (resetHeader === null || resetHeader === undefined)
|
|
103
|
-
?
|
|
103
|
+
? NaN
|
|
104
104
|
: Number.parseInt(resetHeader, 10)
|
|
105
|
-
const waitMs = Number.isFinite(resetTs) ? Math.max(0, resetTs * 1000 - Date.now()) :
|
|
105
|
+
const waitMs = Number.isFinite(resetTs) ? Math.max(0, resetTs * 1000 - Date.now()) : NaN
|
|
106
106
|
|
|
107
107
|
if (Number.isFinite(waitMs) && waitMs <= RATE_LIMIT_MAX_WAIT_MS) {
|
|
108
108
|
hasRetried = true
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { readFileSync } = require('node:fs')
|
|
3
|
+
const { closeSync, constants, fstatSync, openSync, readFileSync } = require('node:fs')
|
|
4
4
|
const { gzipSync } = require('node:zlib')
|
|
5
5
|
|
|
6
6
|
const getConfig = require('../../config')
|
|
@@ -17,12 +17,18 @@ const {
|
|
|
17
17
|
} = require('../telemetry')
|
|
18
18
|
|
|
19
19
|
const UPLOAD_TIMEOUT_MS = 30_000
|
|
20
|
+
const COVERAGE_FILE_OPEN_FLAGS = constants.O_RDONLY |
|
|
21
|
+
(constants.O_NOFOLLOW || 0) |
|
|
22
|
+
constants.O_NONBLOCK
|
|
23
|
+
const BIGINT_STAT_OPTIONS = { bigint: true }
|
|
20
24
|
|
|
21
25
|
/**
|
|
22
26
|
* Uploads a single coverage report to the Datadog CI intake.
|
|
23
27
|
* One file per request with field names 'coverage' and 'event'.
|
|
24
28
|
* @param {object} options - Upload options
|
|
25
29
|
* @param {string} options.filePath - Path to the coverage report file
|
|
30
|
+
* @param {bigint} options.fileDevice - Device containing the discovered report
|
|
31
|
+
* @param {bigint} options.fileInode - Inode of the discovered report
|
|
26
32
|
* @param {string} options.format - Format of the coverage report (e.g., 'lcov', 'cobertura')
|
|
27
33
|
* @param {string[]} [options.flags] - Optional coverage report grouping flags
|
|
28
34
|
* @param {object} options.testEnvironmentMetadata - Test environment metadata containing git/CI tags
|
|
@@ -32,7 +38,7 @@ const UPLOAD_TIMEOUT_MS = 30_000
|
|
|
32
38
|
* @param {(error: Error|null) => void} callback - Callback function
|
|
33
39
|
*/
|
|
34
40
|
function uploadCoverageReport (
|
|
35
|
-
{ filePath, format, flags, testEnvironmentMetadata, url, isEvpProxy, evpProxyPrefix },
|
|
41
|
+
{ filePath, fileDevice, fileInode, format, flags, testEnvironmentMetadata, url, isEvpProxy, evpProxyPrefix },
|
|
36
42
|
callback
|
|
37
43
|
) {
|
|
38
44
|
const { DD_API_KEY } = getConfig()
|
|
@@ -43,10 +49,20 @@ function uploadCoverageReport (
|
|
|
43
49
|
|
|
44
50
|
let compressedCoverage
|
|
45
51
|
try {
|
|
46
|
-
const
|
|
52
|
+
const fileDescriptor = openSync(filePath, COVERAGE_FILE_OPEN_FLAGS)
|
|
53
|
+
let coverageContent
|
|
54
|
+
try {
|
|
55
|
+
const fileStats = fstatSync(fileDescriptor, BIGINT_STAT_OPTIONS)
|
|
56
|
+
if (!fileStats.isFile() || fileStats.dev !== fileDevice || fileStats.ino !== fileInode) {
|
|
57
|
+
throw new Error('Coverage report changed after discovery')
|
|
58
|
+
}
|
|
59
|
+
coverageContent = readFileSync(fileDescriptor)
|
|
60
|
+
} finally {
|
|
61
|
+
closeSync(fileDescriptor)
|
|
62
|
+
}
|
|
47
63
|
compressedCoverage = gzipSync(coverageContent)
|
|
48
|
-
} catch (
|
|
49
|
-
return callback(new Error(`Failed to read coverage report at ${filePath}: ${
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return callback(new Error(`Failed to read coverage report at ${filePath}: ${error.message}`))
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
// Build the event payload with format, type, and all tags from test environment metadata
|
|
@@ -26,7 +26,7 @@ const SETTINGS_BOOLEAN_KEYS = [
|
|
|
26
26
|
]
|
|
27
27
|
const EARLY_FLAKE_DETECTION_KEYS = ['enabled', 'faulty_session_threshold', 'slow_test_retries']
|
|
28
28
|
const TEST_MANAGEMENT_KEYS = ['attempt_to_fix_retries', 'enabled']
|
|
29
|
-
const RETRY_THRESHOLD_PATTERN = /^\d+(?:ms|
|
|
29
|
+
const RETRY_THRESHOLD_PATTERN = /^\d+(?:ms|[smh])$/
|
|
30
30
|
const MAX_VALIDATION_MODULES = 1000
|
|
31
31
|
const MAX_VALIDATION_SUITES = 10_000
|
|
32
32
|
const MAX_VALIDATION_TESTS = 100_000
|
|
@@ -137,7 +137,7 @@ function validateSkippableTestsResponse (response, options = {}) {
|
|
|
137
137
|
if (response.meta !== undefined) {
|
|
138
138
|
assertObject(response.meta, 'Invalid skippable tests response: meta must be an object')
|
|
139
139
|
}
|
|
140
|
-
if (response.meta?.coverage !== undefined) {
|
|
140
|
+
if (response.meta?.coverage !== undefined && response.meta.coverage !== null) {
|
|
141
141
|
assertObject(response.meta.coverage, 'Invalid skippable tests response: meta.coverage must be an object')
|
|
142
142
|
}
|
|
143
143
|
if (response.meta?.correlation_id !== undefined && typeof response.meta.correlation_id !== 'string') {
|
|
@@ -145,7 +145,11 @@ class TestOptimizationHttpCache {
|
|
|
145
145
|
validationMode: Boolean(this._validationManifestPath),
|
|
146
146
|
})
|
|
147
147
|
const testLevel = options.testLevel || 'suite'
|
|
148
|
-
logSkippableSuitesResponse(
|
|
148
|
+
logSkippableSuitesResponse(
|
|
149
|
+
result,
|
|
150
|
+
testLevel,
|
|
151
|
+
options.isCoverageReportUploadEnabled && options.isLineCoverageSupported !== false
|
|
152
|
+
)
|
|
149
153
|
const skippableItems = parsedResponse.data.filter(({ type }) => type === testLevel)
|
|
150
154
|
incrementCountMetric(
|
|
151
155
|
testLevel === 'test'
|
|
@@ -32,18 +32,26 @@ const parseErrors = new Map()
|
|
|
32
32
|
* @param {string} source - The source of the value.
|
|
33
33
|
* @param {string} baseMessage - The base message to use for the warning.
|
|
34
34
|
* @param {Error} [error] - An error that was thrown while parsing the value.
|
|
35
|
+
* @param {string} [outcome] - The outcome after the invalid value is rejected.
|
|
35
36
|
*/
|
|
36
|
-
function warnInvalidValue (value, optionName, source, baseMessage, error) {
|
|
37
|
-
const canonicalName =
|
|
37
|
+
function warnInvalidValue (value, optionName, source, baseMessage, error, outcome = 'picked default') {
|
|
38
|
+
const canonicalName = optionsTable[optionName]?.canonicalName ?? optionName
|
|
39
|
+
const telemetryKey = canonicalName + source
|
|
40
|
+
const telemetryEntry = configWithOrigin.get(telemetryKey)
|
|
38
41
|
// Lazy load log module to avoid circular dependency
|
|
39
|
-
if (!parseErrors.has(
|
|
40
|
-
// TODO:
|
|
41
|
-
let message = `${baseMessage}: ${util.inspect(value)} for ${optionName} (source: ${source})
|
|
42
|
+
if (!parseErrors.has(telemetryKey) && !telemetryEntry?.error) {
|
|
43
|
+
// TODO: Report the prior source when an invalid value does not use the default.
|
|
44
|
+
let message = `${baseMessage}: ${util.inspect(value)} for ${optionName} (source: ${source})`
|
|
45
|
+
if (outcome) message += `, ${outcome}`
|
|
42
46
|
if (error) {
|
|
43
47
|
error.stack = error.toString()
|
|
44
48
|
message += `\n\n${util.inspect(error)}`
|
|
45
49
|
}
|
|
46
|
-
|
|
50
|
+
if (telemetryEntry) {
|
|
51
|
+
telemetryEntry.error = { message }
|
|
52
|
+
} else {
|
|
53
|
+
parseErrors.set(telemetryKey, { message })
|
|
54
|
+
}
|
|
47
55
|
log ??= require('../log')
|
|
48
56
|
const logLevel = error ? 'error' : 'warn'
|
|
49
57
|
log[logLevel](message)
|
|
@@ -434,7 +434,7 @@ export interface GeneratedConfig {
|
|
|
434
434
|
};
|
|
435
435
|
};
|
|
436
436
|
featureFlags: {
|
|
437
|
-
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE:
|
|
437
|
+
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: string;
|
|
438
438
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL: string | undefined;
|
|
439
439
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS: number;
|
|
440
440
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS: number;
|
|
@@ -579,6 +579,7 @@ export interface GeneratedConfig {
|
|
|
579
579
|
DD_TEST_LOCAL_CONFIG_PATH: string | undefined;
|
|
580
580
|
DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES: number;
|
|
581
581
|
DD_TEST_MANAGEMENT_ENABLED: boolean;
|
|
582
|
+
DD_TEST_MANAGEMENT_REPORT_ENABLED: boolean | undefined;
|
|
582
583
|
};
|
|
583
584
|
traceId128BitGenerationEnabled: boolean;
|
|
584
585
|
traceId128BitLoggingEnabled: boolean;
|
|
@@ -700,7 +701,7 @@ export interface GeneratedEnvVarConfig {
|
|
|
700
701
|
DD_EXPERIMENTAL_TEST_OPT_VITEST_NO_WORKER_INIT: boolean | undefined;
|
|
701
702
|
DD_EXPERIMENTAL_TEST_REQUESTS_FS_CACHE: boolean;
|
|
702
703
|
DD_EXTERNAL_ENV: string | undefined;
|
|
703
|
-
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE:
|
|
704
|
+
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: string;
|
|
704
705
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL: string | undefined;
|
|
705
706
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS: number;
|
|
706
707
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS: number;
|
|
@@ -821,6 +822,7 @@ export interface GeneratedEnvVarConfig {
|
|
|
821
822
|
DD_TEST_LOCAL_CONFIG_PATH: string | undefined;
|
|
822
823
|
DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES: number;
|
|
823
824
|
DD_TEST_MANAGEMENT_ENABLED: boolean;
|
|
825
|
+
DD_TEST_MANAGEMENT_REPORT_ENABLED: boolean | undefined;
|
|
824
826
|
DD_TEST_SESSION_NAME: string | undefined;
|
|
825
827
|
DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED: boolean;
|
|
826
828
|
DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED: boolean;
|
|
@@ -307,6 +307,8 @@ module.exports = {
|
|
|
307
307
|
*
|
|
308
308
|
* This should only be called once in config.js to avoid copying the object frequently.
|
|
309
309
|
*
|
|
310
|
+
* @param {typeof process.env} [source] The environment to read from
|
|
311
|
+
* @param {boolean} [internalOnly] Only return configurations marked as internal
|
|
310
312
|
* @returns {TracerEnv} The environment variables
|
|
311
313
|
*/
|
|
312
314
|
getEnvironmentVariables (source = process.env, internalOnly = false) {
|
|
@@ -4,6 +4,7 @@ const fs = require('node:fs')
|
|
|
4
4
|
const os = require('node:os')
|
|
5
5
|
const { URL, format } = require('node:url')
|
|
6
6
|
|
|
7
|
+
const exporters = require('../../../../ext/exporters')
|
|
7
8
|
const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
|
|
8
9
|
const uuid = require('../../../../vendor/dist/crypto-randomuuid') // we need to keep the old uuid dep because of cypress
|
|
9
10
|
const set = require('../../../datadog-core/src/utils/src/set')
|
|
@@ -41,6 +42,13 @@ const { normalizeService } = require('./normalize-service')
|
|
|
41
42
|
const { programmaticTypeCoercions, transformers } = require('./parsers')
|
|
42
43
|
|
|
43
44
|
const RUNTIME_ID = uuid()
|
|
45
|
+
const TEST_OPTIMIZATION_WORKER_EXPORTERS = new Set([
|
|
46
|
+
exporters.CUCUMBER_WORKER,
|
|
47
|
+
exporters.JEST_WORKER,
|
|
48
|
+
exporters.MOCHA_WORKER,
|
|
49
|
+
exporters.PLAYWRIGHT_WORKER,
|
|
50
|
+
exporters.VITEST_WORKER,
|
|
51
|
+
])
|
|
44
52
|
|
|
45
53
|
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
46
54
|
|
|
@@ -194,8 +202,11 @@ class Config extends ConfigBase {
|
|
|
194
202
|
this.debug = log.configure(options)
|
|
195
203
|
|
|
196
204
|
// Process stable config warnings, if any
|
|
197
|
-
|
|
198
|
-
|
|
205
|
+
const stableConfigWarnings = this.stableConfig?.warnings
|
|
206
|
+
if (stableConfigWarnings) {
|
|
207
|
+
for (const warning of stableConfigWarnings) {
|
|
208
|
+
log.warn(warning)
|
|
209
|
+
}
|
|
199
210
|
}
|
|
200
211
|
|
|
201
212
|
this.#applyDefaults()
|
|
@@ -343,6 +354,21 @@ class Config extends ConfigBase {
|
|
|
343
354
|
}
|
|
344
355
|
}
|
|
345
356
|
|
|
357
|
+
const configurationSource = this.featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE
|
|
358
|
+
if (this.featureFlags.DD_FEATURE_FLAGS_ENABLED &&
|
|
359
|
+
configurationSource !== 'agentless' &&
|
|
360
|
+
configurationSource !== 'remote_config') {
|
|
361
|
+
warnInvalidValue(
|
|
362
|
+
configurationSource,
|
|
363
|
+
'DD_FEATURE_FLAGS_CONFIGURATION_SOURCE',
|
|
364
|
+
this.getOrigin('featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE'),
|
|
365
|
+
'Unsupported Feature Flagging configuration source',
|
|
366
|
+
undefined,
|
|
367
|
+
'provider disabled'
|
|
368
|
+
)
|
|
369
|
+
setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_ENABLED', false)
|
|
370
|
+
}
|
|
371
|
+
|
|
346
372
|
if (this.url ||
|
|
347
373
|
os.type() !== 'Windows_NT' &&
|
|
348
374
|
!trackedConfigOrigins.has('hostname') &&
|
|
@@ -578,9 +604,9 @@ class Config extends ConfigBase {
|
|
|
578
604
|
setAndTrack(this, 'remoteConfig.DD_REMOTE_CONFIGURATION_ENABLED', false)
|
|
579
605
|
}
|
|
580
606
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
607
|
+
const isTestOptimizationWorker = this.isCiVisibility &&
|
|
608
|
+
TEST_OPTIMIZATION_WORKER_EXPORTERS.has(this.experimental.exporter)
|
|
609
|
+
if (isTestOptimizationWorker) {
|
|
584
610
|
setAndTrack(this, 'telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED', false)
|
|
585
611
|
}
|
|
586
612
|
|
|
@@ -58,6 +58,17 @@ const transformers = {
|
|
|
58
58
|
toLowerCase (value) {
|
|
59
59
|
return toCase(value, 'toLowerCase')
|
|
60
60
|
},
|
|
61
|
+
/**
|
|
62
|
+
* Normalizes a Feature Flagging configuration source.
|
|
63
|
+
* A blank value is treated as unset so legacy configuration can still apply.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} value
|
|
66
|
+
* @returns {string | undefined}
|
|
67
|
+
*/
|
|
68
|
+
configurationSource (value) {
|
|
69
|
+
const normalized = value.trim().toLowerCase()
|
|
70
|
+
return normalized || undefined
|
|
71
|
+
},
|
|
61
72
|
toUpperCase (value) {
|
|
62
73
|
return toCase(value, 'toUpperCase')
|
|
63
74
|
},
|
|
@@ -161,7 +172,14 @@ const transformers = {
|
|
|
161
172
|
return transformers.stripColonWhitespace(item)
|
|
162
173
|
})
|
|
163
174
|
}
|
|
164
|
-
|
|
175
|
+
// Only whitespace adjacent to a colon is removed; the outer whitespace of the first and
|
|
176
|
+
// last segment stays.
|
|
177
|
+
const parts = value.split(':')
|
|
178
|
+
for (let i = 0; i < parts.length; i++) {
|
|
179
|
+
if (i !== 0) parts[i] = parts[i].trimStart()
|
|
180
|
+
if (i !== parts.length - 1) parts[i] = parts[i].trimEnd()
|
|
181
|
+
}
|
|
182
|
+
return parts.join(':')
|
|
165
183
|
},
|
|
166
184
|
/**
|
|
167
185
|
* @param {string} value
|
|
@@ -236,7 +236,7 @@ const optionLookupTable = {
|
|
|
236
236
|
|
|
237
237
|
const transformers = {
|
|
238
238
|
tracing_sampling_rules (samplingRules) {
|
|
239
|
-
for (const rule of
|
|
239
|
+
for (const rule of samplingRules) {
|
|
240
240
|
if (rule.tags) {
|
|
241
241
|
const reformattedTags = {}
|
|
242
242
|
for (const tag of rule.tags) {
|
|
@@ -849,10 +849,9 @@
|
|
|
849
849
|
"implementation": "A",
|
|
850
850
|
"type": "string",
|
|
851
851
|
"default": "agentless",
|
|
852
|
-
"
|
|
853
|
-
"description": "Experimental: Select where Feature Flagging loads Universal Flag Configuration. Supported values are agentless and remote_config.",
|
|
852
|
+
"description": "Select where Feature Flagging loads Universal Flag Configuration. Supported values are agentless and remote_config; offline is reserved and currently unsupported.",
|
|
854
853
|
"namespace": "featureFlags",
|
|
855
|
-
"transform": "
|
|
854
|
+
"transform": "configurationSource"
|
|
856
855
|
}
|
|
857
856
|
],
|
|
858
857
|
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL": [
|
|
@@ -860,7 +859,7 @@
|
|
|
860
859
|
"implementation": "A",
|
|
861
860
|
"type": "string",
|
|
862
861
|
"default": null,
|
|
863
|
-
"description": "
|
|
862
|
+
"description": "Override the agentless Feature Flagging UFC endpoint or base URL.",
|
|
864
863
|
"namespace": "featureFlags",
|
|
865
864
|
"sensitive": true
|
|
866
865
|
}
|
|
@@ -870,7 +869,7 @@
|
|
|
870
869
|
"implementation": "A",
|
|
871
870
|
"type": "int",
|
|
872
871
|
"default": "30",
|
|
873
|
-
"description": "
|
|
872
|
+
"description": "Set the agentless Feature Flagging UFC polling interval in seconds, capped at one hour.",
|
|
874
873
|
"allowed": "[1-9]\\d*",
|
|
875
874
|
"namespace": "featureFlags"
|
|
876
875
|
}
|
|
@@ -880,7 +879,7 @@
|
|
|
880
879
|
"implementation": "A",
|
|
881
880
|
"type": "int",
|
|
882
881
|
"default": "5",
|
|
883
|
-
"description": "
|
|
882
|
+
"description": "Set the agentless Feature Flagging UFC request timeout in seconds.",
|
|
884
883
|
"allowed": "[1-9]\\d*",
|
|
885
884
|
"namespace": "featureFlags"
|
|
886
885
|
}
|
|
@@ -1942,6 +1941,14 @@
|
|
|
1942
1941
|
"namespace": "testOptimization"
|
|
1943
1942
|
}
|
|
1944
1943
|
],
|
|
1944
|
+
"DD_TEST_MANAGEMENT_REPORT_ENABLED": [
|
|
1945
|
+
{
|
|
1946
|
+
"implementation": "A",
|
|
1947
|
+
"type": "boolean",
|
|
1948
|
+
"default": null,
|
|
1949
|
+
"namespace": "testOptimization"
|
|
1950
|
+
}
|
|
1951
|
+
],
|
|
1945
1952
|
"DD_TEST_SESSION_NAME": [
|
|
1946
1953
|
{
|
|
1947
1954
|
"implementation": "A",
|
|
@@ -40,7 +40,7 @@ function encodeVarintInto (target, offset, value) {
|
|
|
40
40
|
let i = offset
|
|
41
41
|
const limit = offset + maxVarLen64 - 1
|
|
42
42
|
// if first byte is 1, the number is negative in javascript, but we want to interpret it as positive
|
|
43
|
-
while ((high !== 0 || low < 0 || low >
|
|
43
|
+
while ((high !== 0 || low < 0 || low > 0x7F) && i < limit) {
|
|
44
44
|
target[i] = (low & 0x7F) | 0x80
|
|
45
45
|
low >>>= 7
|
|
46
46
|
low |= (high & 0x7F) << 25
|
|
@@ -88,7 +88,7 @@ function decodeUvarint64 (
|
|
|
88
88
|
low |= n << s
|
|
89
89
|
}
|
|
90
90
|
if (s > 0) {
|
|
91
|
-
high |= s
|
|
91
|
+
high |= s > 32 ? n << (s - 32) : n >> (32 - s)
|
|
92
92
|
}
|
|
93
93
|
return [low, high, bytes]
|
|
94
94
|
}
|
|
@@ -96,8 +96,7 @@ function decodeUvarint64 (
|
|
|
96
96
|
low |= (n & 0x7F) << s
|
|
97
97
|
}
|
|
98
98
|
if (s > 0) {
|
|
99
|
-
high |=
|
|
100
|
-
s - 32 > 0 ? (n & 0x7F) << (s - 32) : (n & 0x7F) >> (32 - s)
|
|
99
|
+
high |= s > 32 ? (n & 0x7F) << (s - 32) : (n & 0x7F) >> (32 - s)
|
|
101
100
|
}
|
|
102
101
|
s += 7
|
|
103
102
|
}
|
|
@@ -20,11 +20,12 @@ const on = (level, ...args) => {
|
|
|
20
20
|
const off = () => {}
|
|
21
21
|
|
|
22
22
|
const threshold = LEVELS.indexOf(logLevel)
|
|
23
|
+
const isEnabled = debug && typeof logPort?.postMessage === 'function'
|
|
23
24
|
|
|
24
25
|
/** @type {Logger} */
|
|
25
26
|
module.exports = Object.fromEntries(
|
|
26
27
|
LEVELS.map(level => [
|
|
27
28
|
level,
|
|
28
|
-
|
|
29
|
+
isEnabled && threshold >= LEVELS.indexOf(level) ? on.bind(null, level) : off,
|
|
29
30
|
])
|
|
30
31
|
)
|
|
@@ -36,10 +36,7 @@ function getRemoveProbeExpression (id) {
|
|
|
36
36
|
* @returns {string}
|
|
37
37
|
*/
|
|
38
38
|
function compileBreakpointCondition (probes) {
|
|
39
|
-
const probeConditions =
|
|
40
|
-
for (const probe of probes) {
|
|
41
|
-
probeConditions.push(compileProbeCondition(probe))
|
|
42
|
-
}
|
|
39
|
+
const probeConditions = probes.map(compileProbeCondition)
|
|
43
40
|
|
|
44
41
|
// NOTE: $dd_sampler is read from the realm-local `globalThis` where it was installed (the main
|
|
45
42
|
// realm). A probe whose code runs in a different V8 realm (e.g. a `vm.createContext` script with a
|
|
@@ -67,14 +67,13 @@ function send (message, logger, dd, snapshot, processTags) {
|
|
|
67
67
|
|
|
68
68
|
if (pruned) {
|
|
69
69
|
json = pruned
|
|
70
|
-
size = Buffer.byteLength(json)
|
|
71
70
|
} else {
|
|
72
71
|
// Fallback if pruning fails
|
|
73
72
|
const line = Object.keys(snapshot.captures.lines)[0]
|
|
74
73
|
snapshot.captures.lines[line] = { pruned: true }
|
|
75
74
|
json = JSON.stringify(payload)
|
|
76
|
-
size = Buffer.byteLength(json)
|
|
77
75
|
}
|
|
76
|
+
size = Buffer.byteLength(json)
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
jsonBuffer.write(json, size)
|
|
@@ -61,7 +61,7 @@ async function getLocalStateForCallFrame (callFrame, limits, deadlineNs = BIGINT
|
|
|
61
61
|
// Delay calling `processRawState` so caller can resume the main thread before processing `rawState`
|
|
62
62
|
return {
|
|
63
63
|
processLocalState () {
|
|
64
|
-
processedState
|
|
64
|
+
processedState ??= processRawState(rawState, maxLength)
|
|
65
65
|
return processedState
|
|
66
66
|
},
|
|
67
67
|
fatalErrors: ctx.fatalErrors,
|
|
@@ -155,7 +155,7 @@ async function evaluateCaptureExpressions (callFrame, expressions, deadlineNs =
|
|
|
155
155
|
fatalErrors.push(...ctx.fatalErrors)
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
if (ctx.deadlineReached
|
|
158
|
+
if (ctx.deadlineReached) {
|
|
159
159
|
// Add the current expression (properties may be incomplete due to timeout)
|
|
160
160
|
rawResults.push({ name, remoteObject: result, maxLength })
|
|
161
161
|
// Add stub entries for remaining uncaptured expressions
|
|
@@ -97,10 +97,24 @@ const REDACTED_IDENTIFIERS = new Set(
|
|
|
97
97
|
'XSRF-TOKEN',
|
|
98
98
|
...config.dynamicInstrumentation.redactedIdentifiers,
|
|
99
99
|
]
|
|
100
|
-
.map(
|
|
101
|
-
.filter(
|
|
100
|
+
.map(normalizeIdentifier)
|
|
101
|
+
.filter(isIncludedIdentifier)
|
|
102
102
|
)
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* @param {string} name
|
|
106
|
+
*/
|
|
107
|
+
function normalizeIdentifier (name) {
|
|
108
|
+
return normalizeName(name)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @param {string} name
|
|
113
|
+
*/
|
|
114
|
+
function isIncludedIdentifier (name) {
|
|
115
|
+
return !excludedIdentifiers.has(name)
|
|
116
|
+
}
|
|
117
|
+
|
|
104
118
|
function normalizeName (name, isSymbol) {
|
|
105
119
|
if (isSymbol) name = name.slice(7, -1) // Remove `Symbol(` and `)`
|
|
106
120
|
return name.toLowerCase().replaceAll(/[-_@$.]/g, '')
|
|
@@ -32,7 +32,7 @@ const STATUSES = {
|
|
|
32
32
|
INSTALLED: 'INSTALLED',
|
|
33
33
|
EMITTING: 'EMITTING',
|
|
34
34
|
ERROR: 'ERROR',
|
|
35
|
-
|
|
35
|
+
// TODO: Add BLOCKED once support for allow list, deny list or max probe limit has been added
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function ackReceived ({ id: probeId, version }) {
|
|
@@ -110,7 +110,6 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
|
110
110
|
_encodePayloadStart (bytes) {
|
|
111
111
|
const payload = {
|
|
112
112
|
version: COVERAGE_PAYLOAD_VERSION,
|
|
113
|
-
coverages: [],
|
|
114
113
|
}
|
|
115
114
|
bytes.writeMapPrefix(COVERAGE_KEYS_LENGTH)
|
|
116
115
|
this._encodeString(bytes, 'version')
|
|
@@ -60,11 +60,11 @@ function eventTimeNano (event) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function normalizeSpan (span) {
|
|
63
|
-
span.service
|
|
63
|
+
span.service ||= DEFAULT_SERVICE_NAME
|
|
64
64
|
if (span.service.length > MAX_SERVICE_LENGTH) {
|
|
65
65
|
span.service = span.service.slice(0, MAX_SERVICE_LENGTH)
|
|
66
66
|
}
|
|
67
|
-
span.name
|
|
67
|
+
span.name ||= DEFAULT_SPAN_NAME
|
|
68
68
|
if (span.name.length > MAX_NAME_LENGTH) {
|
|
69
69
|
span.name = span.name.slice(0, MAX_NAME_LENGTH)
|
|
70
70
|
}
|
|
@@ -32,11 +32,9 @@ function parseUrl (urlObjOrString) {
|
|
|
32
32
|
// `urlToHttpOptions` returns `pathname` at runtime, but @types/node narrows it
|
|
33
33
|
// to `ClientRequestArgs`, which omits it; cast so the named-pipe fold below can
|
|
34
34
|
// read and rewrite it.
|
|
35
|
-
const url = /** @type {import('node:http').ClientRequestArgs & { pathname: string }} */ (
|
|
36
|
-
urlObjOrString !== null && typeof urlObjOrString === 'object'
|
|
37
|
-
|
|
38
|
-
: urlToHttpOptions(new URL(urlObjOrString))
|
|
39
|
-
)
|
|
35
|
+
const url = /** @type {import('node:http').ClientRequestArgs & { pathname: string }} */ (urlToHttpOptions(
|
|
36
|
+
urlObjOrString !== null && typeof urlObjOrString === 'object' ? urlObjOrString : new URL(urlObjOrString)
|
|
37
|
+
))
|
|
40
38
|
|
|
41
39
|
if (url.protocol === 'unix:' && url.hostname === '.') {
|
|
42
40
|
url.path = url.pathname = `//.${url.pathname}`
|
|
@@ -16,6 +16,8 @@ class ElectronExporter {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export (spans) {
|
|
19
|
+
if (!traceChannel.hasSubscribers) return
|
|
20
|
+
|
|
19
21
|
this.#traces.push(spans)
|
|
20
22
|
|
|
21
23
|
const { flushInterval } = this._config
|
|
@@ -35,7 +37,8 @@ class ElectronExporter {
|
|
|
35
37
|
clearTimeout(this.#timer)
|
|
36
38
|
this.#timer = undefined
|
|
37
39
|
|
|
38
|
-
const traces = this.#traces
|
|
40
|
+
const traces = this.#traces
|
|
41
|
+
this.#traces = []
|
|
39
42
|
|
|
40
43
|
if (traces.length > 0 && traceChannel.hasSubscribers) {
|
|
41
44
|
const formattedTraces = traces.map(spans => spans.map(span => normalizeSpan(truncateSpan(span))))
|
|
@@ -78,7 +78,6 @@ class ExternalLogger {
|
|
|
78
78
|
|
|
79
79
|
// Flushes logs with optional callback for when the call is complete
|
|
80
80
|
flush (cb = () => {}) {
|
|
81
|
-
let logs
|
|
82
81
|
let numLogs
|
|
83
82
|
let encodedLogs
|
|
84
83
|
|
|
@@ -88,7 +87,7 @@ class ExternalLogger {
|
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
try {
|
|
91
|
-
logs = this.queue
|
|
90
|
+
const logs = this.queue
|
|
92
91
|
this.queue = []
|
|
93
92
|
|
|
94
93
|
numLogs = logs.length
|
|
@@ -39,8 +39,8 @@ const flare = {
|
|
|
39
39
|
logChannel?.unsubscribe(logger)
|
|
40
40
|
logChannel = new LogChannel(logLevel)
|
|
41
41
|
logChannel.subscribe(logger)
|
|
42
|
-
tracerLogs
|
|
43
|
-
timer
|
|
42
|
+
tracerLogs ||= new FlareFile()
|
|
43
|
+
timer ||= setTimeout(flare.cleanup, TIMEOUT)
|
|
44
44
|
},
|
|
45
45
|
|
|
46
46
|
send (task) {
|