dd-trace 6.15.0 → 6.17.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/README.md +15 -0
- package/ci/diagnose.js +0 -23
- package/ci/test-optimization-validation/approval-artifacts.js +0 -3
- package/ci/test-optimization-validation/approval.js +0 -6
- package/ci/test-optimization-validation/artifact-id.js +0 -1
- package/ci/test-optimization-validation/bounded-json.js +0 -1
- package/ci/test-optimization-validation/cli.js +0 -12
- package/ci/test-optimization-validation/command-output-policy.js +0 -1
- package/ci/test-optimization-validation/command-runner.js +0 -3
- package/ci/test-optimization-validation/environment.js +0 -4
- package/ci/test-optimization-validation/executable-approval.js +0 -1
- package/ci/test-optimization-validation/executable.js +0 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +4 -8
- package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
- package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
- package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
- package/ci/test-optimization-validation/generated-test-contract.js +0 -5
- package/ci/test-optimization-validation/generated-verifier.js +0 -1
- package/ci/test-optimization-validation/literal-environment.js +0 -1
- package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
- package/ci/test-optimization-validation/manifest-schema.js +0 -21
- package/ci/test-optimization-validation/offline-fixtures.js +0 -4
- package/ci/test-optimization-validation/package-check.js +4 -1
- package/ci/test-optimization-validation/plan-writer.js +0 -11
- package/ci/test-optimization-validation/preflight-runner.js +0 -1
- package/ci/test-optimization-validation/redaction.js +0 -4
- package/ci/test-optimization-validation/report-writer.js +0 -16
- package/ci/test-optimization-validation/runner-command.js +0 -3
- package/ci/test-optimization-validation/runner-contract.js +0 -4
- package/ci/test-optimization-validation/safe-files.js +0 -1
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +1 -2
- package/ci/test-optimization-validation/source-text.js +0 -3
- package/ci/vitest-no-worker-init-setup.mjs +41 -16
- package/index.d.ts +169 -0
- package/next.d.ts +27 -0
- package/next.js +3 -0
- package/package.json +28 -23
- package/packages/datadog-esbuild/index.js +14 -1
- package/packages/datadog-esbuild/src/resolver.js +284 -0
- package/packages/datadog-esbuild/src/utils.js +162 -120
- package/packages/datadog-instrumentations/src/aerospike.js +28 -6
- package/packages/datadog-instrumentations/src/ai.js +39 -97
- package/packages/datadog-instrumentations/src/anthropic.js +76 -134
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +1 -3
- package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
- package/packages/datadog-instrumentations/src/azure-cosmos.js +1 -1
- package/packages/datadog-instrumentations/src/azure-durable-functions.js +23 -9
- package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
- package/packages/datadog-instrumentations/src/bullmq.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -3
- package/packages/datadog-instrumentations/src/console.js +97 -0
- package/packages/datadog-instrumentations/src/cucumber.js +72 -12
- package/packages/datadog-instrumentations/src/cypress-config.js +0 -23
- package/packages/datadog-instrumentations/src/dd-trace-api.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +39 -14
- package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +25 -8
- package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +69 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
- package/packages/datadog-instrumentations/src/helpers/register.js +13 -64
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +109 -29
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-durable-functions.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -16
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +12 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +6 -7
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +99 -75
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
- package/packages/datadog-instrumentations/src/jest.js +141 -51
- package/packages/datadog-instrumentations/src/knex.js +0 -1
- package/packages/datadog-instrumentations/src/langchain.js +1 -1
- package/packages/datadog-instrumentations/src/langgraph.js +1 -1
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
- package/packages/datadog-instrumentations/src/mariadb.js +0 -2
- package/packages/datadog-instrumentations/src/mercurius.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +22 -25
- package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
- package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
- package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/mysql2.js +0 -2
- package/packages/datadog-instrumentations/src/openai-agents.js +1 -1
- package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
- package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
- package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
- package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
- package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
- package/packages/datadog-instrumentations/src/openai.js +97 -80
- package/packages/datadog-instrumentations/src/oracledb.js +9 -3
- package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -16
- package/packages/datadog-instrumentations/src/playwright.js +238 -55
- package/packages/datadog-instrumentations/src/postgres.js +7 -0
- package/packages/datadog-instrumentations/src/router.js +0 -2
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
- package/packages/datadog-instrumentations/src/sequelize.js +0 -1
- package/packages/datadog-instrumentations/src/supabase.js +15 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
- package/packages/datadog-instrumentations/src/vitest-main.js +37 -17
- package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
- package/packages/datadog-instrumentations/src/vitest-worker.js +56 -23
- package/packages/datadog-instrumentations/src/webdriverio.js +23 -42
- package/packages/datadog-instrumentations/src/ws.js +0 -1
- package/packages/datadog-plugin-ai/src/utils.js +0 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +7 -2
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +1 -1
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +95 -1
- package/packages/datadog-plugin-cucumber/src/index.js +10 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +171 -75
- package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
- package/packages/datadog-plugin-cypress/src/support.js +52 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -24
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -36
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-request-context.js +31 -0
- package/packages/datadog-plugin-graphql/src/resolve-error.js +32 -11
- package/packages/datadog-plugin-graphql/src/utils.js +0 -5
- package/packages/datadog-plugin-jest/src/index.js +13 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
- package/packages/datadog-plugin-mocha/src/index.js +39 -11
- package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
- package/packages/datadog-plugin-openai/src/index.js +16 -1
- package/packages/datadog-plugin-openai/src/realtime.js +144 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
- package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
- package/packages/datadog-plugin-playwright/src/index.js +76 -9
- package/packages/datadog-plugin-postgres/src/index.js +167 -0
- package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
- package/packages/datadog-plugin-redis/src/index.js +15 -1
- package/packages/datadog-plugin-supabase/src/error.js +18 -0
- package/packages/datadog-plugin-supabase/src/index.js +21 -0
- package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
- package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
- package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
- package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
- package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
- package/packages/datadog-plugin-supabase/src/url.js +17 -0
- package/packages/datadog-plugin-vitest/src/index.js +10 -0
- package/packages/datadog-plugin-ws/src/util.js +0 -4
- package/packages/datadog-turbopack/index.js +206 -0
- package/packages/datadog-turbopack/src/constants.js +5 -0
- package/packages/datadog-turbopack/src/loader.js +484 -0
- package/packages/datadog-webpack/src/loader.js +0 -1
- package/packages/dd-trace/src/aiguard/client.js +2 -3
- package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
- package/packages/dd-trace/src/aiguard/index.js +3 -2
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +53 -25
- package/packages/dd-trace/src/aiguard/integrations/evaluate.js +49 -25
- package/packages/dd-trace/src/aiguard/integrations/index.js +4 -3
- package/packages/dd-trace/src/aiguard/integrations/openai.js +132 -29
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +116 -42
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
- package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
- package/packages/dd-trace/src/aiguard/messages/utils.js +29 -2
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +25 -0
- package/packages/dd-trace/src/aiguard/redaction.js +0 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/activation.js +1 -1
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
- package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
- package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
- package/packages/dd-trace/src/appsec/index.js +2 -2
- package/packages/dd-trace/src/appsec/lambda.js +71 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
- package/packages/dd-trace/src/appsec/remote_config.js +8 -6
- package/packages/dd-trace/src/appsec/reporter.js +10 -6
- package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/common.js +4 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +23 -5
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +1 -20
- package/packages/dd-trace/src/appsec/telemetry/user.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/waf.js +1 -20
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
- package/packages/dd-trace/src/carrier.js +0 -5
- package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
- package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
- package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
- package/packages/dd-trace/src/config/defaults.js +3 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +74 -66
- package/packages/dd-trace/src/config/helper.js +9 -2
- package/packages/dd-trace/src/config/index.js +44 -29
- package/packages/dd-trace/src/config/parsers.js +34 -6
- package/packages/dd-trace/src/config/remote_config.js +25 -109
- package/packages/dd-trace/src/config/supported-configurations.json +146 -9
- package/packages/dd-trace/src/datastreams/encoding.js +0 -1
- package/packages/dd-trace/src/datastreams/pathway.js +0 -1
- package/packages/dd-trace/src/debugger/constants.js +10 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +76 -17
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
- package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
- package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +34 -8
- package/packages/dd-trace/src/debugger/devtools_client/send.js +40 -14
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
- package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -6
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
- package/packages/dd-trace/src/debugger/index.js +50 -2
- package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
- package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
- package/packages/dd-trace/src/dogstatsd.js +0 -23
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
- package/packages/dd-trace/src/encode/0.4.js +0 -7
- package/packages/dd-trace/src/encode/0.5.js +0 -2
- package/packages/dd-trace/src/encode/tags-processors.js +0 -1
- package/packages/dd-trace/src/evp_proxy/discovery.js +3 -5
- package/packages/dd-trace/src/evp_proxy/path.js +11 -4
- package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
- package/packages/dd-trace/src/exporters/common/docker.js +4 -1
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
- package/packages/dd-trace/src/exporters/common/proxy.js +3 -0
- package/packages/dd-trace/src/exporters/common/request.js +1 -0
- package/packages/dd-trace/src/exporters/common/url.js +0 -2
- package/packages/dd-trace/src/exporters/common/writer.js +0 -2
- package/packages/dd-trace/src/id.js +0 -11
- package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
- package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
- package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
- package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
- package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
- package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
- package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
- package/packages/dd-trace/src/llmobs/index.js +1 -3
- package/packages/dd-trace/src/llmobs/noop.js +10 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
- package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
- package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
- package/packages/dd-trace/src/llmobs/prompts/manager.js +639 -0
- package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +92 -0
- package/packages/dd-trace/src/llmobs/sdk.js +21 -6
- package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
- package/packages/dd-trace/src/llmobs/tagger.js +30 -7
- package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
- package/packages/dd-trace/src/llmobs/util.js +0 -34
- package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
- package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
- package/packages/dd-trace/src/log/channels.js +3 -0
- package/packages/dd-trace/src/log/index.js +23 -5
- package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
- package/packages/dd-trace/src/msgpack/chunk.js +0 -1
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
- package/packages/dd-trace/src/openfeature/encoding.js +0 -2
- package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/index.js +0 -4
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
- package/packages/dd-trace/src/openfeature/writers/base.js +0 -6
- package/packages/dd-trace/src/openfeature/writers/exposures.js +0 -5
- package/packages/dd-trace/src/openfeature/writers/util.js +0 -4
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +4 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +103 -35
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +36 -13
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
- package/packages/dd-trace/src/opentracing/span_context.js +0 -1
- package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
- package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
- package/packages/dd-trace/src/plugin_manager.js +9 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +0 -1
- package/packages/dd-trace/src/plugins/database.js +2 -6
- package/packages/dd-trace/src/plugins/index.js +8 -0
- package/packages/dd-trace/src/plugins/plugin.js +0 -4
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/git.js +1 -3
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
- package/packages/dd-trace/src/plugins/util/llm.js +0 -2
- package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
- package/packages/dd-trace/src/plugins/util/test.js +25 -21
- package/packages/dd-trace/src/plugins/util/url.js +0 -5
- package/packages/dd-trace/src/priority_sampler.js +0 -6
- package/packages/dd-trace/src/process-tags/index.js +0 -1
- package/packages/dd-trace/src/profiler.js +132 -35
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
- package/packages/dd-trace/src/profiling/profiler.js +101 -41
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
- package/packages/dd-trace/src/propagation-hash/index.js +0 -1
- package/packages/dd-trace/src/proxy.js +21 -45
- package/packages/dd-trace/src/random_sampler.js +0 -4
- package/packages/dd-trace/src/rate_limiter.js +0 -4
- package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
- package/packages/dd-trace/src/remote_config/index.js +0 -1
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
- package/packages/dd-trace/src/sampler.js +0 -4
- package/packages/dd-trace/src/sampling_rule.js +0 -7
- package/packages/dd-trace/src/serverless/vercel.js +0 -1
- package/packages/dd-trace/src/serverless.js +0 -1
- package/packages/dd-trace/src/service-naming/index.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
- package/packages/dd-trace/src/span_processor.js +2 -2
- package/packages/dd-trace/src/span_sampler.js +0 -1
- package/packages/dd-trace/src/standalone/product.js +2 -2
- package/packages/dd-trace/src/standalone/tracesource.js +0 -1
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
- package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
- package/packages/dd-trace/src/telemetry/metrics.js +0 -2
- package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
- package/packages/dd-trace/src/util.js +13 -1
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +0 -10
|
@@ -6,7 +6,11 @@ const { getGeneratedPosition } = require('./source-maps')
|
|
|
6
6
|
const session = require('./session')
|
|
7
7
|
const { compile, compileSegments, templateRequiresEvaluation } = require('./condition')
|
|
8
8
|
const { MAX_SNAPSHOTS_PER_SECOND_PER_PROBE, MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE } = require('./defaults')
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
compileBreakpointCondition,
|
|
11
|
+
getRemoveProbeExpression,
|
|
12
|
+
isSnapshotProducingProbe,
|
|
13
|
+
} = require('./probe_sampler')
|
|
10
14
|
const {
|
|
11
15
|
DEFAULT_MAX_REFERENCE_DEPTH,
|
|
12
16
|
DEFAULT_MAX_COLLECTION_SIZE,
|
|
@@ -53,6 +57,7 @@ module.exports = {
|
|
|
53
57
|
addBreakpoint: lock(addBreakpoint),
|
|
54
58
|
removeBreakpoint: lock(removeBreakpoint),
|
|
55
59
|
modifyBreakpoint: lock(modifyBreakpoint),
|
|
60
|
+
refreshBreakpoints: lock(refreshBreakpoints),
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
async function addBreakpoint (probe) {
|
|
@@ -76,12 +81,6 @@ async function addBreakpoint (probe) {
|
|
|
76
81
|
}
|
|
77
82
|
delete probe.segments
|
|
78
83
|
|
|
79
|
-
// Optimize for fast calculations when probe is hit
|
|
80
|
-
const snapshotsPerSecond = probe.sampling?.snapshotsPerSecond ?? (probe.captureSnapshot
|
|
81
|
-
? MAX_SNAPSHOTS_PER_SECOND_PER_PROBE
|
|
82
|
-
: MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE)
|
|
83
|
-
probe.nsBetweenSampling = BigInt(Math.trunc(1 / snapshotsPerSecond * 1e9))
|
|
84
|
-
|
|
85
84
|
// Warning: The code below relies on undocumented behavior of the inspector!
|
|
86
85
|
// It expects that `await session.post('Debugger.enable')` will wait for all loaded scripts to be emitted as
|
|
87
86
|
// `Debugger.scriptParsed` events. If this ever changes, we will have a race condition!
|
|
@@ -156,6 +155,15 @@ async function addBreakpoint (probe) {
|
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
157
|
|
|
158
|
+
// Must be calculated after `compiledCaptureExpressions` has been resolved, since capture-expression probes produce
|
|
159
|
+
// snapshots and therefore default to the snapshot rate.
|
|
160
|
+
//
|
|
161
|
+
// Optimize for fast calculations when probe is hit
|
|
162
|
+
const snapshotsPerSecond = probe.sampling?.snapshotsPerSecond ?? (isSnapshotProducingProbe(probe)
|
|
163
|
+
? MAX_SNAPSHOTS_PER_SECOND_PER_PROBE
|
|
164
|
+
: MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE)
|
|
165
|
+
probe.nsBetweenSampling = BigInt(Math.trunc(1 / snapshotsPerSecond * 1e9))
|
|
166
|
+
|
|
159
167
|
const locationKey = generateLocationKey(scriptId, lineNumber, columnNumber)
|
|
160
168
|
const breakpoint = locationToBreakpoint.get(locationKey)
|
|
161
169
|
|
|
@@ -234,23 +242,77 @@ async function modifyBreakpoint (probe) {
|
|
|
234
242
|
await addBreakpoint(probe)
|
|
235
243
|
}
|
|
236
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Rebuild the breakpoint conditions at the locations of the given probes from the current state of the probes
|
|
247
|
+
* attached to them.
|
|
248
|
+
*
|
|
249
|
+
* A breakpoint condition bakes in whether each probe produces snapshots, which decides if a hit counts against the
|
|
250
|
+
* global snapshot rate limit and how a skipped hit is classified. That changes when the pause handler permanently
|
|
251
|
+
* disables capture for a probe after a fatal capture error, so the conditions have to be recompiled.
|
|
252
|
+
*
|
|
253
|
+
* Probes sharing a location share a breakpoint, so each location is only refreshed once. A probe that has been removed
|
|
254
|
+
* in the meantime is ignored: its location no longer needs the update.
|
|
255
|
+
*
|
|
256
|
+
* The locations are independent, so one that fails does not stop the others from being refreshed. Any failure is
|
|
257
|
+
* thrown once every location has been attempted.
|
|
258
|
+
*
|
|
259
|
+
* @param {{ id: string }[]} probes - Probes attached to the breakpoints to refresh.
|
|
260
|
+
* @returns {Promise<void>}
|
|
261
|
+
*/
|
|
262
|
+
async function refreshBreakpoints (probes) {
|
|
263
|
+
if (!sessionStarted) return
|
|
264
|
+
|
|
265
|
+
// Breakpoints set next to each other can snap to the same logical location and be hit at the same time, so the
|
|
266
|
+
// probes can be spread over more than one breakpoint.
|
|
267
|
+
const locationKeys = new Set()
|
|
268
|
+
for (const { id } of probes) {
|
|
269
|
+
const locationKey = probeToLocation.get(id)
|
|
270
|
+
if (locationKey !== undefined) locationKeys.add(locationKey)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** @type {Error[] | undefined} */
|
|
274
|
+
let errors
|
|
275
|
+
for (const locationKey of locationKeys) {
|
|
276
|
+
try {
|
|
277
|
+
// eslint-disable-next-line no-await-in-loop
|
|
278
|
+
await updateBreakpointInternal(locationToBreakpoint.get(locationKey))
|
|
279
|
+
} catch (err) {
|
|
280
|
+
// Keep going: the remaining locations would otherwise hold on to the condition this refresh exists to replace
|
|
281
|
+
errors ??= []
|
|
282
|
+
errors.push(err)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (errors !== undefined) {
|
|
287
|
+
throw errors.length === 1 ? errors[0] : new AggregateError(errors, 'Error refreshing breakpoints')
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Replace the breakpoint at a location with one whose condition matches the probes currently attached to it.
|
|
293
|
+
*
|
|
294
|
+
* @param {{ id: string, location: object, locationKey: string }} breakpoint - The breakpoint to replace.
|
|
295
|
+
* @param {object} [probe] - A probe to attach to the breakpoint first, when one is being added.
|
|
296
|
+
* @returns {Promise<void>}
|
|
297
|
+
*/
|
|
237
298
|
async function updateBreakpointInternal (breakpoint, probe) {
|
|
238
299
|
const probesAtLocation = breakpointToProbes.get(breakpoint.id)
|
|
239
300
|
|
|
240
|
-
// If a probe is provided, add it to the breakpoint. If not, it's because we're removing a probe
|
|
241
|
-
// breakpoint condition must be rebuilt to match the
|
|
301
|
+
// If a probe is provided, add it to the breakpoint. If not, it's because we're removing a probe or the probes at the
|
|
302
|
+
// location changed. In all cases the breakpoint condition must be rebuilt to match the probes at the location.
|
|
303
|
+
let context // identifies the update in the error messages below
|
|
242
304
|
if (probe) {
|
|
243
305
|
probesAtLocation.set(probe.id, probe)
|
|
244
306
|
probeToLocation.set(probe.id, breakpoint.locationKey)
|
|
307
|
+
context = `while adding probe ${probe.id} (version: ${probe.version})`
|
|
308
|
+
} else {
|
|
309
|
+
context = `at ${breakpoint.locationKey}`
|
|
245
310
|
}
|
|
246
311
|
|
|
247
312
|
try {
|
|
248
313
|
await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
|
|
249
314
|
} catch (err) {
|
|
250
|
-
|
|
251
|
-
? `Error replacing breakpoint while adding probe ${probe.id} (version: ${probe.version})`
|
|
252
|
-
: `Error replacing breakpoint after removing probe from ${breakpoint.locationKey}`
|
|
253
|
-
throw new Error(message, { cause: err })
|
|
315
|
+
throw new Error(`Error replacing breakpoint ${context}`, { cause: err })
|
|
254
316
|
}
|
|
255
317
|
breakpointToProbes.delete(breakpoint.id)
|
|
256
318
|
let result
|
|
@@ -260,10 +322,7 @@ async function updateBreakpointInternal (breakpoint, probe) {
|
|
|
260
322
|
condition: compileBreakpointCondition([...probesAtLocation.values()]),
|
|
261
323
|
}))
|
|
262
324
|
} catch (err) {
|
|
263
|
-
|
|
264
|
-
? `Error setting breakpoint while adding probe ${probe.id} (version: ${probe.version})`
|
|
265
|
-
: `Error setting breakpoint after removing probe from ${breakpoint.locationKey}`
|
|
266
|
-
throw new Error(message, { cause: err })
|
|
325
|
+
throw new Error(`Error setting breakpoint ${context}`, { cause: err })
|
|
267
326
|
}
|
|
268
327
|
breakpoint.id = result.breakpointId
|
|
269
328
|
breakpointToProbes.set(result.breakpointId, probesAtLocation)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { workerData: { config: parentConfig, parentThreadId, configPort } } = require('node:worker_threads')
|
|
4
4
|
const processTags = require('../../process-tags')
|
|
5
|
+
const { DEFAULT_QUEUE_MAX_BYTES } = require('../constants')
|
|
5
6
|
const log = require('./log')
|
|
6
7
|
|
|
7
8
|
processTags.initialize()
|
|
@@ -10,6 +11,7 @@ const config = module.exports = {
|
|
|
10
11
|
...parentConfig,
|
|
11
12
|
parentThreadId,
|
|
12
13
|
maxTotalPayloadSize: 5 * 1024 * 1024, // 5MB
|
|
14
|
+
queueMaxBytes: DEFAULT_QUEUE_MAX_BYTES,
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
updateConfig(parentConfig)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { workerData } = require('node:worker_threads')
|
|
4
|
+
|
|
5
|
+
const { GuardrailMetrics } = require('../guardrail-metrics')
|
|
6
|
+
|
|
7
|
+
// For testing purposes, we allow `workerData` to be undefined and fallback to counters that are never drained
|
|
8
|
+
const buffer = workerData?.guardrailMetricsBuffer ?? GuardrailMetrics.createBuffer()
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The worker's view of the guardrail counters shared with the main thread, which drains them into telemetry.
|
|
12
|
+
*
|
|
13
|
+
* @type {GuardrailMetrics}
|
|
14
|
+
*/
|
|
15
|
+
module.exports = new GuardrailMetrics(buffer)
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { randomUUID } = require('crypto')
|
|
4
|
-
const { workerData: { probeSamplerBuffer } } = require('worker_threads')
|
|
4
|
+
const { parentPort, workerData: { probeSamplerBuffer } } = require('worker_threads')
|
|
5
5
|
const { version } = require('../../../../../package.json')
|
|
6
6
|
const processTags = require('../../process-tags')
|
|
7
7
|
const { INSPECT_SEGMENT_GLOBAL_PROPERTY } = require('../constants')
|
|
8
|
+
const { EVENT_TYPE, INCOMPLETE_REASON } = require('../guardrail-metrics')
|
|
8
9
|
const {
|
|
10
|
+
CONDITION_ERROR_FLAG,
|
|
9
11
|
MAX_SAMPLED_PROBES_PER_PAUSE,
|
|
10
12
|
SAMPLED_PROBE_COUNT_INDEX,
|
|
11
13
|
SAMPLED_PROBE_INDEXES_START,
|
|
12
14
|
SAMPLED_PROBE_OVERFLOW_INDEX,
|
|
13
15
|
} = require('../probe_sampler_constants')
|
|
16
|
+
const { getTakeConditionErrorExpression } = require('./probe_sampler')
|
|
14
17
|
const { breakpointToProbes, samplingIndexToProbe } = require('./state')
|
|
18
|
+
const { refreshBreakpoints } = require('./breakpoints')
|
|
15
19
|
const session = require('./session')
|
|
16
20
|
const { getLocalStateForCallFrame, evaluateCaptureExpressions } = require('./snapshot')
|
|
17
21
|
const send = require('./send')
|
|
@@ -55,7 +59,11 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
55
59
|
let numberOfProbesWithSnapshots = 0
|
|
56
60
|
let probesWithCaptureExpressions = false
|
|
57
61
|
const probes = []
|
|
58
|
-
|
|
62
|
+
// Expressions evaluated on the paused frame in one round trip, in the order of `probes`: the evaluated template for
|
|
63
|
+
// probes whose template requires evaluation, and the recorded error for probes paused to report a condition error
|
|
64
|
+
let frameExpressions = ''
|
|
65
|
+
/** @type {Set<object> | undefined} */
|
|
66
|
+
let conditionErrorProbes
|
|
59
67
|
|
|
60
68
|
// V8 doesn't allow setting more than one breakpoint at a specific location, however, it's possible to set two
|
|
61
69
|
// breakpoints just next to each other that will "snap" to the same logical location, which in turn will be hit at the
|
|
@@ -81,7 +89,8 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
for (let j = 0; j < numberOfSampledProbeIndexes; j++) {
|
|
84
|
-
const
|
|
92
|
+
const sampledValue = Atomics.load(sampledProbeIndexes, SAMPLED_PROBE_INDEXES_START + j)
|
|
93
|
+
const samplingIndex = sampledValue & ~CONDITION_ERROR_FLAG
|
|
85
94
|
const probe = samplingIndexToProbe.get(samplingIndex)
|
|
86
95
|
|
|
87
96
|
if (probe === undefined) {
|
|
@@ -94,6 +103,15 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
94
103
|
continue
|
|
95
104
|
}
|
|
96
105
|
|
|
106
|
+
if ((sampledValue & CONDITION_ERROR_FLAG) !== 0) {
|
|
107
|
+
// The condition threw, so there's nothing to capture. Only the recorded error is needed from the paused thread.
|
|
108
|
+
conditionErrorProbes ??= new Set()
|
|
109
|
+
conditionErrorProbes.add(probe)
|
|
110
|
+
frameExpressions += `,${getTakeConditionErrorExpression(probe.id)}`
|
|
111
|
+
probes.push(probe)
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
|
|
97
115
|
if (probe.captureSnapshot === true || probe.compiledCaptureExpressions !== undefined) {
|
|
98
116
|
if (probe.captureSnapshot === true) {
|
|
99
117
|
numberOfProbesWithSnapshots++
|
|
@@ -107,7 +125,7 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
107
125
|
}
|
|
108
126
|
|
|
109
127
|
if (probe.templateRequiresEvaluation) {
|
|
110
|
-
|
|
128
|
+
frameExpressions += `,${probe.template}`
|
|
111
129
|
}
|
|
112
130
|
|
|
113
131
|
probes.push(probe)
|
|
@@ -116,7 +134,9 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
116
134
|
|
|
117
135
|
// This can happen if sampled probe indexes are inconsistent with the worker state. Those cases are logged above.
|
|
118
136
|
if (probes.length === 0) {
|
|
119
|
-
|
|
137
|
+
await session.post('Debugger.resume')
|
|
138
|
+
reportPauseDuration(start)
|
|
139
|
+
return
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
const timestamp = Date.now()
|
|
@@ -125,9 +145,9 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
125
145
|
const { result } = /** @type {EvaluateOnCallFrameResult} */ (
|
|
126
146
|
await session.post('Debugger.evaluateOnCallFrame', {
|
|
127
147
|
callFrameId: params.callFrames[0].callFrameId,
|
|
128
|
-
expression:
|
|
148
|
+
expression: frameExpressions.length === 0
|
|
129
149
|
? `[${getDDTagsExpression}]`
|
|
130
|
-
: `${templateExpressionSetupCode}[${getDDTagsExpression}${
|
|
150
|
+
: `${templateExpressionSetupCode}[${getDDTagsExpression}${frameExpressions}]`,
|
|
131
151
|
returnByValue: true,
|
|
132
152
|
includeCommandLineAPI: true,
|
|
133
153
|
})
|
|
@@ -140,17 +160,14 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
140
160
|
}
|
|
141
161
|
|
|
142
162
|
// TODO: Create unique states for each affected probe based on that probes unique `capture` settings (DEBUG-2863)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
let fatalSnapshotErrors
|
|
163
|
+
/** @type {Awaited<ReturnType<typeof getLocalStateForCallFrame>> | undefined} */
|
|
164
|
+
let localState
|
|
146
165
|
if (numberOfProbesWithSnapshots !== 0) {
|
|
147
|
-
|
|
166
|
+
localState = await getLocalStateForCallFrame(
|
|
148
167
|
params.callFrames[0],
|
|
149
168
|
{ maxReferenceDepth, maxCollectionSize, maxFieldCount, maxLength },
|
|
150
169
|
start + config.dynamicInstrumentation.captureTimeoutNs
|
|
151
170
|
)
|
|
152
|
-
processLocalState = result.processLocalState
|
|
153
|
-
fatalSnapshotErrors = result.fatalErrors
|
|
154
171
|
}
|
|
155
172
|
|
|
156
173
|
// Evaluate capture expressions for probes that have them
|
|
@@ -158,7 +175,7 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
158
175
|
if (probesWithCaptureExpressions === true) {
|
|
159
176
|
captureExpressionResults = new Map()
|
|
160
177
|
for (const probe of probes) {
|
|
161
|
-
if (probe.compiledCaptureExpressions === undefined) continue
|
|
178
|
+
if (conditionErrorProbes?.has(probe) || probe.compiledCaptureExpressions === undefined) continue
|
|
162
179
|
// eslint-disable-next-line no-await-in-loop
|
|
163
180
|
captureExpressionResults.set(probe.id, await evaluateCaptureExpressions(
|
|
164
181
|
params.callFrames[0],
|
|
@@ -169,14 +186,7 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
169
186
|
}
|
|
170
187
|
|
|
171
188
|
await session.post('Debugger.resume')
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
// This doesn't measure the overhead of the CDP protocol. The actual pause time is slightly larger.
|
|
175
|
-
// On my machine I'm seeing around 1.7ms of overhead.
|
|
176
|
-
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
177
|
-
log.debug(() => `[debugger:devtools_client] Finished processing breakpoints - main thread paused for: ~${
|
|
178
|
-
Number(diff) / 1_000_000
|
|
179
|
-
} ms`)
|
|
189
|
+
reportPauseDuration(start)
|
|
180
190
|
|
|
181
191
|
const logger = {
|
|
182
192
|
// We can safely use `location.file` from the first probe in the array, since all probes hit by `hitBreakpoints`
|
|
@@ -189,9 +199,13 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
189
199
|
}
|
|
190
200
|
|
|
191
201
|
const stack = await getStackFromCallFrames(params.callFrames)
|
|
192
|
-
const dd = processDD(evalResults[0]) // the first result is the dd tags, the rest are the
|
|
202
|
+
const dd = processDD(evalResults[0]) // the first result is the dd tags, the rest are the frame expression results
|
|
193
203
|
let messageIndex = 1
|
|
194
204
|
|
|
205
|
+
// The probes whose capture got permanently disabled during this pause, if any
|
|
206
|
+
/** @type {object[] | undefined} */
|
|
207
|
+
let captureDisabledProbes
|
|
208
|
+
|
|
195
209
|
// TODO: Send multiple probes in one HTTP request as an array (DEBUG-2848)
|
|
196
210
|
for (const probe of probes) {
|
|
197
211
|
const snapshot = {
|
|
@@ -206,19 +220,48 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
206
220
|
language: 'javascript',
|
|
207
221
|
}
|
|
208
222
|
|
|
223
|
+
// Which guardrail bucket the event belongs to, and which capture limits were enforced while producing it. The
|
|
224
|
+
// snapshot module records the reasons, including runtime errors: a fatal error does not necessarily mean one, as
|
|
225
|
+
// the collector also raises a fatal error to disable capture when it hits its large object safety threshold.
|
|
226
|
+
/** @type {number} */
|
|
227
|
+
let eventType = EVENT_TYPE.LOG
|
|
228
|
+
let incompleteReasons = 0
|
|
229
|
+
|
|
230
|
+
if (conditionErrorProbes?.has(probe)) {
|
|
231
|
+
// Report the failing condition instead of a probe result, so the user can see why the probe doesn't fire
|
|
232
|
+
const error = evalResults[messageIndex++]
|
|
233
|
+
const message = typeof error === 'string' ? error : 'Unknown evaluation error'
|
|
234
|
+
log.debug('[debugger:devtools_client] Condition of probe %s failed to evaluate: %s', probe.id, message)
|
|
235
|
+
snapshot.evaluationErrors = [{ expr: probe.when.dsl, message }]
|
|
236
|
+
ackEmitting(probe)
|
|
237
|
+
send(message, logger, dd, snapshot,
|
|
238
|
+
config.propagateProcessTags.enabled ? processTags.serialized : undefined,
|
|
239
|
+
probe.captureSnapshot === true || probe.compiledCaptureExpressions !== undefined
|
|
240
|
+
? EVENT_TYPE.SNAPSHOT
|
|
241
|
+
: EVENT_TYPE.LOG,
|
|
242
|
+
0)
|
|
243
|
+
continue
|
|
244
|
+
}
|
|
245
|
+
|
|
209
246
|
if (probe.captureSnapshot) {
|
|
210
|
-
|
|
247
|
+
eventType = EVENT_TYPE.SNAPSHOT
|
|
248
|
+
const { processLocalState, fatalErrors, incomplete } = /** @type {NonNullable<typeof localState>} */ (localState)
|
|
249
|
+
if (fatalErrors.length > 0) {
|
|
211
250
|
// There was an error collecting the snapshot for this probe, let's not try again
|
|
212
251
|
probe.captureSnapshot = false
|
|
213
|
-
probe.permanentEvaluationErrors =
|
|
252
|
+
probe.permanentEvaluationErrors = fatalErrors.map(error => ({
|
|
214
253
|
expr: '',
|
|
215
254
|
message: error.message,
|
|
216
255
|
}))
|
|
256
|
+
captureDisabledProbes ??= []
|
|
257
|
+
captureDisabledProbes.push(probe)
|
|
217
258
|
}
|
|
218
259
|
snapshot.captures = {
|
|
219
|
-
lines: { [probe.location.lines[0]]: { locals:
|
|
260
|
+
lines: { [probe.location.lines[0]]: { locals: processLocalState() } },
|
|
220
261
|
}
|
|
262
|
+
incompleteReasons |= incomplete.reasons
|
|
221
263
|
} else if (probe.compiledCaptureExpressions !== undefined) {
|
|
264
|
+
eventType = EVENT_TYPE.SNAPSHOT
|
|
222
265
|
const expressionResult = /** @type {Map} */ (captureExpressionResults).get(probe.id)
|
|
223
266
|
if (expressionResult) {
|
|
224
267
|
// Handle fatal capture errors - disable capture expressions for this probe permanently
|
|
@@ -228,11 +271,14 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
228
271
|
expr: '',
|
|
229
272
|
message: error.message,
|
|
230
273
|
}))
|
|
274
|
+
captureDisabledProbes ??= []
|
|
275
|
+
captureDisabledProbes.push(probe)
|
|
231
276
|
}
|
|
232
277
|
|
|
233
278
|
snapshot.captures = {
|
|
234
279
|
lines: { [probe.location.lines[0]]: { captureExpressions: expressionResult.processCaptureExpressions() } },
|
|
235
280
|
}
|
|
281
|
+
incompleteReasons |= expressionResult.incomplete.reasons
|
|
236
282
|
|
|
237
283
|
// Handle transient evaluation errors - include in snapshot for this capture
|
|
238
284
|
if (expressionResult.evaluationErrors?.length > 0) {
|
|
@@ -249,6 +295,7 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
249
295
|
expr: '',
|
|
250
296
|
message: 'Internal error: capture expression results not found',
|
|
251
297
|
}]
|
|
298
|
+
incompleteReasons |= INCOMPLETE_REASON.RUNTIME_ERROR
|
|
252
299
|
}
|
|
253
300
|
}
|
|
254
301
|
|
|
@@ -283,10 +330,39 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
283
330
|
ackEmitting(probe)
|
|
284
331
|
|
|
285
332
|
send(message, logger, dd, snapshot,
|
|
286
|
-
config.propagateProcessTags.enabled ? processTags.serialized : undefined
|
|
333
|
+
config.propagateProcessTags.enabled ? processTags.serialized : undefined,
|
|
334
|
+
eventType, incompleteReasons)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (captureDisabledProbes !== undefined) {
|
|
338
|
+
// The breakpoint condition bakes in whether each probe produces snapshots, which decides if a hit counts against
|
|
339
|
+
// the global snapshot rate limit and how a skipped hit is classified. Rebuild the conditions now that this
|
|
340
|
+
// changed. The disabled probes can be spread over more than one breakpoint, but each affected location is only
|
|
341
|
+
// refreshed once.
|
|
342
|
+
refreshBreakpoints(captureDisabledProbes).catch((err) => {
|
|
343
|
+
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
344
|
+
log.error(() => {
|
|
345
|
+
let ids = captureDisabledProbes[0].id
|
|
346
|
+
for (let i = 1; i < captureDisabledProbes.length; i++) ids += `, ${captureDisabledProbes[i].id}`
|
|
347
|
+
return `[debugger:devtools_client] Error refreshing breakpoints after disabling capture for probes: ${ids}`
|
|
348
|
+
}, err)
|
|
349
|
+
})
|
|
287
350
|
}
|
|
288
351
|
})
|
|
289
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Called after resuming so reporting the elapsed time doesn't extend the pause. This measures from receipt of the
|
|
355
|
+
* pause notification through the resume response, not the full time V8 suspends the instrumented thread.
|
|
356
|
+
*
|
|
357
|
+
* @param {bigint} start - Monotonic time when the pause notification was received, in nanoseconds.
|
|
358
|
+
*/
|
|
359
|
+
function reportPauseDuration (start) {
|
|
360
|
+
const durationMs = Number(process.hrtime.bigint() - start) / 1_000_000
|
|
361
|
+
parentPort.postMessage({ type: 'thread-paused', durationMs })
|
|
362
|
+
log.debug('[debugger:devtools_client] Finished processing breakpoints - instrumented thread paused for: ~%d ms',
|
|
363
|
+
durationMs)
|
|
364
|
+
}
|
|
365
|
+
|
|
290
366
|
function processDD (result) {
|
|
291
367
|
return result?.trace_id === undefined ? undefined : result
|
|
292
368
|
}
|
|
@@ -1,40 +1,83 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Batches JSON documents into a JSON array payload, flushed when the batch reaches its size limit or after a timeout.
|
|
5
|
+
*
|
|
6
|
+
* The buffer is bounded in bytes: the batch being assembled plus all flushed payloads that are still in flight (handed
|
|
7
|
+
* to `onFlush` but not yet released through its `done` callback) can never exceed `maxQueueBytes`. Documents that would
|
|
8
|
+
* exceed the bound are rejected instead of queued, so a stalled or slow upload target cannot make the buffer grow
|
|
9
|
+
* without bound.
|
|
10
|
+
*/
|
|
3
11
|
class JSONBuffer {
|
|
4
12
|
#maxSize
|
|
13
|
+
#maxQueueBytes
|
|
5
14
|
#timeout
|
|
6
15
|
#onFlush
|
|
7
16
|
#timer
|
|
8
17
|
#partialJson
|
|
18
|
+
#partialBytes = 0
|
|
19
|
+
#inFlightBytes = 0
|
|
9
20
|
|
|
10
|
-
|
|
21
|
+
/**
|
|
22
|
+
* @param {object} options
|
|
23
|
+
* @param {number} options.size - Maximum size in bytes of a single flushed payload
|
|
24
|
+
* @param {number} options.maxQueueBytes - Maximum bytes queued, including payloads still in flight
|
|
25
|
+
* @param {number} options.timeout - Milliseconds to wait for more documents before flushing a partial payload
|
|
26
|
+
* @param {(json: string, done: () => void) => void} options.onFlush - Receives each payload. Must call `done` once
|
|
27
|
+
* the payload is no longer held in memory, so its bytes are released from the queue bound.
|
|
28
|
+
*/
|
|
29
|
+
constructor ({ size, maxQueueBytes, timeout, onFlush }) {
|
|
11
30
|
this.#maxSize = size
|
|
31
|
+
this.#maxQueueBytes = maxQueueBytes
|
|
12
32
|
this.#timeout = timeout
|
|
13
33
|
this.#onFlush = onFlush
|
|
14
34
|
}
|
|
15
35
|
|
|
16
36
|
#flush () {
|
|
17
37
|
const json = `${this.#partialJson}]`
|
|
38
|
+
const bytes = this.#partialBytes + 1
|
|
18
39
|
this.#partialJson = undefined
|
|
19
|
-
this.#
|
|
40
|
+
this.#partialBytes = 0
|
|
41
|
+
this.#inFlightBytes += bytes
|
|
42
|
+
|
|
43
|
+
let released = false
|
|
44
|
+
this.#onFlush(json, () => {
|
|
45
|
+
if (released) return
|
|
46
|
+
released = true
|
|
47
|
+
this.#inFlightBytes -= bytes
|
|
48
|
+
})
|
|
20
49
|
}
|
|
21
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Add a JSON document to the batch.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} str - The JSON document
|
|
55
|
+
* @param {number} [size] - The size of the document in bytes. Calculated if not provided.
|
|
56
|
+
*/
|
|
22
57
|
write (str, size = Buffer.byteLength(str)) {
|
|
58
|
+
// The document is prefixed by `[` or `,` and the payload is terminated by `]`, hence the extra 2 bytes
|
|
59
|
+
if (this.#partialJson !== undefined && this.#partialBytes + size + 2 > this.#maxSize) {
|
|
60
|
+
clearTimeout(this.#timer)
|
|
61
|
+
this.#timer = undefined
|
|
62
|
+
this.#flush()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (this.#partialBytes + this.#inFlightBytes + size + 2 > this.#maxQueueBytes) return false
|
|
66
|
+
|
|
23
67
|
if (this.#partialJson === undefined) {
|
|
24
68
|
this.#partialJson = `[${str}`
|
|
69
|
+
this.#partialBytes = size + 1
|
|
25
70
|
if (this.#timer === undefined) {
|
|
26
71
|
this.#timer = setTimeout(() => this.#flush(), this.#timeout)
|
|
27
72
|
} else {
|
|
28
73
|
this.#timer.refresh()
|
|
29
74
|
}
|
|
30
|
-
} else if (Buffer.byteLength(this.#partialJson) + size + 2 > this.#maxSize) {
|
|
31
|
-
clearTimeout(this.#timer)
|
|
32
|
-
this.#timer = undefined
|
|
33
|
-
this.#flush()
|
|
34
|
-
this.write(str, size)
|
|
35
75
|
} else {
|
|
36
76
|
this.#partialJson += `,${str}`
|
|
77
|
+
this.#partialBytes += size + 1
|
|
37
78
|
}
|
|
79
|
+
|
|
80
|
+
return true
|
|
38
81
|
}
|
|
39
82
|
}
|
|
40
83
|
|
|
@@ -13,7 +13,9 @@ const { config: { debug = false, logLevel } = {}, logPort } = workerData ?? {}
|
|
|
13
13
|
const LEVELS = ['error', 'warn', 'info', 'debug']
|
|
14
14
|
const on = (level, ...args) => {
|
|
15
15
|
if (typeof args[0] === 'function') {
|
|
16
|
-
|
|
16
|
+
// Resolve the message only now that we know it will be logged. Keep the remaining arguments: the main thread
|
|
17
|
+
// logger reads a trailing error as the cause of the log record.
|
|
18
|
+
args[0] = args[0]()
|
|
17
19
|
}
|
|
18
20
|
logPort.postMessage({ level, args })
|
|
19
21
|
}
|
|
@@ -8,6 +8,19 @@ const SAMPLER_EXPRESSION = `globalThis[Symbol.for(${JSON.stringify(DD_TRACE_SYMB
|
|
|
8
8
|
module.exports = {
|
|
9
9
|
compileBreakpointCondition,
|
|
10
10
|
getRemoveProbeExpression,
|
|
11
|
+
getTakeConditionErrorExpression,
|
|
12
|
+
isSnapshotProducingProbe,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Determine whether a probe produces snapshots. Probes that capture the full local state and probes that only capture
|
|
17
|
+
* specific expressions both emit snapshot payloads, so they share the snapshot sampling defaults and count towards the
|
|
18
|
+
* global snapshot rate limit.
|
|
19
|
+
*
|
|
20
|
+
* @param {{ captureSnapshot?: boolean, compiledCaptureExpressions?: object[] }} probe - The probe to inspect.
|
|
21
|
+
*/
|
|
22
|
+
function isSnapshotProducingProbe (probe) {
|
|
23
|
+
return probe.captureSnapshot === true || probe.compiledCaptureExpressions !== undefined
|
|
11
24
|
}
|
|
12
25
|
|
|
13
26
|
/**
|
|
@@ -15,12 +28,21 @@ module.exports = {
|
|
|
15
28
|
* the debuggee.
|
|
16
29
|
*
|
|
17
30
|
* @param {string} id - The probe id.
|
|
18
|
-
* @returns {string}
|
|
19
31
|
*/
|
|
20
32
|
function getRemoveProbeExpression (id) {
|
|
21
33
|
return `${SAMPLER_EXPRESSION}?.remove(${JSON.stringify(id)})`
|
|
22
34
|
}
|
|
23
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Build the expression that hands over the condition error recorded for a probe. Called by the devtools worker and
|
|
38
|
+
* evaluated on the paused frame of the debuggee.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} id - The probe id.
|
|
41
|
+
*/
|
|
42
|
+
function getTakeConditionErrorExpression (id) {
|
|
43
|
+
return `${SAMPLER_EXPRESSION}?.takeConditionError(${JSON.stringify(id)})`
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
/**
|
|
25
47
|
* Build a Chrome DevTools breakpoint condition that samples all matching probes at a location. Called by the devtools
|
|
26
48
|
* worker.
|
|
@@ -33,7 +55,6 @@ function getRemoveProbeExpression (id) {
|
|
|
33
55
|
* captureSnapshot?: boolean,
|
|
34
56
|
* compiledCaptureExpressions?: object[]
|
|
35
57
|
* }[]} probes - The probes at the breakpoint location.
|
|
36
|
-
* @returns {string}
|
|
37
58
|
*/
|
|
38
59
|
function compileBreakpointCondition (probes) {
|
|
39
60
|
const probeConditions = probes.map(compileProbeCondition)
|
|
@@ -62,19 +83,24 @@ function compileBreakpointCondition (probes) {
|
|
|
62
83
|
* captureSnapshot?: boolean,
|
|
63
84
|
* compiledCaptureExpressions?: object[]
|
|
64
85
|
* }} probe - The probe to sample.
|
|
65
|
-
* @returns {string}
|
|
66
86
|
*/
|
|
67
87
|
function compileProbeCondition (probe) {
|
|
68
88
|
const sample = `$dd_sampler.makeSampleDecision(${probe.samplingIndex}, ${JSON.stringify(probe.id)}, ` +
|
|
69
|
-
`${probe.nsBetweenSampling}n, ${probe
|
|
89
|
+
`${probe.nsBetweenSampling}n, ${isSnapshotProducingProbe(probe)})`
|
|
70
90
|
|
|
71
91
|
if (probe.condition === undefined) {
|
|
72
92
|
return `$dd_sampled = ${sample} || $dd_sampled`
|
|
73
93
|
}
|
|
74
94
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
// A condition that throws is reported once per throttle window and skipped at probe entry in between
|
|
96
|
+
return `if ($dd_sampler.shouldEvaluateCondition(${JSON.stringify(probe.id)})) {
|
|
97
|
+
try {
|
|
98
|
+
if ((${probe.condition}) === true) {
|
|
99
|
+
$dd_sampled = ${sample} || $dd_sampled
|
|
100
|
+
}
|
|
101
|
+
} catch ($dd_error) {
|
|
102
|
+
$dd_sampled = $dd_sampler.conditionError(${probe.samplingIndex}, ${JSON.stringify(probe.id)}, $dd_error) ||
|
|
103
|
+
$dd_sampled
|
|
78
104
|
}
|
|
79
|
-
}
|
|
105
|
+
}`
|
|
80
106
|
}
|