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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { INCOMPLETE_REASON } = require('../../guardrail-metrics')
|
|
3
4
|
const { LARGE_OBJECT_SKIP_THRESHOLD } = require('./constants')
|
|
4
5
|
const { collectionSizeSym, largeCollectionSkipThresholdSym, fieldCountSym, timeBudgetSym } = require('./symbols')
|
|
5
6
|
const { normalizeName, REDACTED_IDENTIFIERS } = require('./redaction')
|
|
@@ -15,15 +16,24 @@ module.exports = {
|
|
|
15
16
|
* @typedef {import('inspector').Runtime.RemoteObject & { properties?: object[] }} RemoteObjectWithProperties
|
|
16
17
|
*/
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Accumulates which capture limits were enforced while processing a single event, so they can be reported once per
|
|
21
|
+
* event instead of once per affected node.
|
|
22
|
+
*
|
|
23
|
+
* @typedef {object} IncompleteCapture
|
|
24
|
+
* @property {number} reasons - Bitmask of {@link INCOMPLETE_REASON} flags
|
|
25
|
+
*/
|
|
26
|
+
|
|
18
27
|
/**
|
|
19
28
|
* Process a RemoteObject into the snapshot format.
|
|
20
29
|
*
|
|
21
30
|
* @param {RemoteObjectWithProperties} remoteObject
|
|
22
31
|
* @param {number} maxLength - Maximum string length
|
|
32
|
+
* @param {IncompleteCapture} incomplete - Receives the capture limits enforced on the object
|
|
23
33
|
* @returns {object} The processed value in snapshot format
|
|
24
34
|
*/
|
|
25
|
-
function processRemoteObject (remoteObject, maxLength) {
|
|
26
|
-
return getPropertyValueRaw({ value: remoteObject }, maxLength)
|
|
35
|
+
function processRemoteObject (remoteObject, maxLength, incomplete) {
|
|
36
|
+
return getPropertyValueRaw({ value: remoteObject }, maxLength, incomplete)
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
// Matches classes in source code, no matter how it's written:
|
|
@@ -33,7 +43,15 @@ function processRemoteObject (remoteObject, maxLength) {
|
|
|
33
43
|
// - Anonymous, with odd whitespace: class\n{}
|
|
34
44
|
const CLASS_REGEX = /^class\s([^{]*)/
|
|
35
45
|
|
|
36
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Process the collected properties of an object into the snapshot format.
|
|
48
|
+
*
|
|
49
|
+
* @param {object[]} props - The collected property descriptors
|
|
50
|
+
* @param {number} maxLength - Maximum string length
|
|
51
|
+
* @param {IncompleteCapture} incomplete - Receives the capture limits enforced on the properties
|
|
52
|
+
* @returns {Record<string, object>} The processed properties in snapshot format
|
|
53
|
+
*/
|
|
54
|
+
function processProperties (props, maxLength, incomplete) {
|
|
37
55
|
const result = {}
|
|
38
56
|
|
|
39
57
|
for (const prop of props) {
|
|
@@ -42,20 +60,26 @@ function processProperties (props, maxLength) {
|
|
|
42
60
|
if (name.includes('.')) {
|
|
43
61
|
name = name.replaceAll('.', '_')
|
|
44
62
|
}
|
|
45
|
-
result[name] = getPropertyValue(prop, maxLength)
|
|
63
|
+
result[name] = getPropertyValue(prop, maxLength, incomplete)
|
|
46
64
|
}
|
|
47
65
|
|
|
48
66
|
return result
|
|
49
67
|
}
|
|
50
68
|
|
|
69
|
+
// Capture limits enforced while processing a value that ends up redacted never make it into the snapshot, so they are
|
|
70
|
+
// not recorded as incomplete capture reasons either
|
|
71
|
+
const discardedIncomplete = { reasons: 0 }
|
|
72
|
+
|
|
51
73
|
// TODO: Improve performance of redaction algorithm.
|
|
52
74
|
// This algorithm is probably slower than if we embedded the redaction logic inside the functions below.
|
|
53
75
|
// That way we didn't have to traverse objects that will just be redacted anyway.
|
|
54
|
-
function getPropertyValue (prop, maxLength) {
|
|
55
|
-
return
|
|
76
|
+
function getPropertyValue (prop, maxLength, incomplete) {
|
|
77
|
+
return shouldRedactProperty(prop)
|
|
78
|
+
? notCapturedRedacted(getPropertyValueRaw(prop, maxLength, discardedIncomplete).type)
|
|
79
|
+
: getPropertyValueRaw(prop, maxLength, incomplete)
|
|
56
80
|
}
|
|
57
81
|
|
|
58
|
-
function getPropertyValueRaw (prop, maxLength) {
|
|
82
|
+
function getPropertyValueRaw (prop, maxLength, incomplete) {
|
|
59
83
|
// Special case for getters and setters which does not have a value property
|
|
60
84
|
if (prop.get) {
|
|
61
85
|
const hasGet = prop.get.type !== 'undefined'
|
|
@@ -69,15 +93,15 @@ function getPropertyValueRaw (prop, maxLength) {
|
|
|
69
93
|
|
|
70
94
|
switch (prop.value?.type) {
|
|
71
95
|
case 'object':
|
|
72
|
-
return getObjectValue(prop.value, maxLength)
|
|
96
|
+
return getObjectValue(prop.value, maxLength, incomplete)
|
|
73
97
|
case 'string':
|
|
74
|
-
return toString(prop.value.value, maxLength)
|
|
98
|
+
return toString(prop.value.value, maxLength, incomplete)
|
|
75
99
|
case 'number':
|
|
76
100
|
return { type: 'number', value: prop.value.description } // use `description` to get it as string
|
|
77
101
|
case 'boolean':
|
|
78
102
|
return { type: 'boolean', value: prop.value.value === true ? 'true' : 'false' }
|
|
79
103
|
case 'function':
|
|
80
|
-
return toFunctionOrClass(prop.value, maxLength)
|
|
104
|
+
return toFunctionOrClass(prop.value, maxLength, incomplete)
|
|
81
105
|
case undefined: // TODO: Add test for when a prop has no value. I think it's if it's defined after the breakpoint?
|
|
82
106
|
case 'undefined':
|
|
83
107
|
return { type: 'undefined' }
|
|
@@ -88,18 +112,19 @@ function getPropertyValueRaw (prop, maxLength) {
|
|
|
88
112
|
default:
|
|
89
113
|
// As of this writing, the Chrome DevTools Protocol doesn't allow any other types than the ones listed above, but
|
|
90
114
|
// in the future new ones might be added.
|
|
115
|
+
incomplete.reasons |= INCOMPLETE_REASON.OTHER
|
|
91
116
|
return { type: prop.value.type, notCapturedReason: 'Unsupported property type' }
|
|
92
117
|
}
|
|
93
118
|
}
|
|
94
119
|
|
|
95
|
-
function getObjectValue (obj, maxLength) {
|
|
120
|
+
function getObjectValue (obj, maxLength, incomplete) {
|
|
96
121
|
const timeBudgetReached = obj[timeBudgetSym] === true
|
|
97
122
|
|
|
98
123
|
switch (obj.subtype) {
|
|
99
124
|
case undefined:
|
|
100
|
-
return toObject(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
125
|
+
return toObject(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
101
126
|
case 'array':
|
|
102
|
-
return toArray(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
127
|
+
return toArray(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
103
128
|
case 'null':
|
|
104
129
|
return { type: 'null', isNull: true }
|
|
105
130
|
// case 'node': // TODO: What does this subtype represent?
|
|
@@ -113,28 +138,28 @@ function getObjectValue (obj, maxLength) {
|
|
|
113
138
|
return { type: obj.className, value }
|
|
114
139
|
}
|
|
115
140
|
case 'map':
|
|
116
|
-
return toMap(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
141
|
+
return toMap(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
117
142
|
case 'set':
|
|
118
|
-
return toSet(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
143
|
+
return toSet(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
119
144
|
case 'error':
|
|
120
145
|
// TODO: Convert stack trace to array to avoid string truncation or disable truncation in this case?
|
|
121
|
-
return toObject(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
146
|
+
return toObject(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
122
147
|
case 'proxy':
|
|
123
148
|
// Use `description` instead of `className` as the `type` to get type of target object (`Proxy(Error)` vs `proxy`)
|
|
124
|
-
return toObject(obj.description, obj.properties, maxLength, timeBudgetReached)
|
|
149
|
+
return toObject(obj.description, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
125
150
|
case 'promise':
|
|
126
|
-
return toObject(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
151
|
+
return toObject(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
127
152
|
case 'typedarray':
|
|
128
|
-
return toArray(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
153
|
+
return toArray(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
129
154
|
case 'generator':
|
|
130
155
|
// Use `subtype` instead of `className` to make it obvious it's a generator
|
|
131
|
-
return toObject(obj.subtype, obj.properties, maxLength, timeBudgetReached)
|
|
156
|
+
return toObject(obj.subtype, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
132
157
|
case 'arraybuffer':
|
|
133
|
-
return toArrayBuffer(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
158
|
+
return toArrayBuffer(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
134
159
|
case 'weakmap':
|
|
135
|
-
return toMap(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
160
|
+
return toMap(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
136
161
|
case 'weakset':
|
|
137
|
-
return toSet(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
162
|
+
return toSet(obj.className, obj.properties, maxLength, timeBudgetReached, incomplete)
|
|
138
163
|
// case 'iterator': // TODO: I've not been able to trigger this subtype
|
|
139
164
|
// case 'dataview': // TODO: Looks like the internal ArrayBuffer is only accessible via the `buffer` getter
|
|
140
165
|
// case 'webassemblymemory': // TODO: Looks like the internal ArrayBuffer is only accessible via the `buffer` getter
|
|
@@ -142,31 +167,34 @@ function getObjectValue (obj, maxLength) {
|
|
|
142
167
|
default:
|
|
143
168
|
// As of this writing, the Chrome DevTools Protocol doesn't allow any other subtypes than the ones listed above,
|
|
144
169
|
// but in the future new ones might be added.
|
|
170
|
+
incomplete.reasons |= INCOMPLETE_REASON.OTHER
|
|
145
171
|
return { type: obj.subtype, notCapturedReason: 'Unsupported object type' }
|
|
146
172
|
}
|
|
147
173
|
}
|
|
148
174
|
|
|
149
|
-
function toFunctionOrClass (value, maxLength) {
|
|
175
|
+
function toFunctionOrClass (value, maxLength, incomplete) {
|
|
150
176
|
const classMatch = value.description.match(CLASS_REGEX)
|
|
151
177
|
|
|
152
178
|
if (classMatch === null) {
|
|
153
179
|
// This is a function
|
|
154
180
|
const timeBudgetReached = value[timeBudgetSym] === true
|
|
155
181
|
// TODO: Would it make sense to detect if it's an arrow function or not?
|
|
156
|
-
return toObject(value.className, value.properties, maxLength, timeBudgetReached)
|
|
182
|
+
return toObject(value.className, value.properties, maxLength, timeBudgetReached, incomplete)
|
|
157
183
|
}
|
|
158
184
|
// This is a class
|
|
159
185
|
const className = classMatch[1].trim()
|
|
160
186
|
return { type: className ? `class ${className}` : 'class' }
|
|
161
187
|
}
|
|
162
188
|
|
|
163
|
-
function toString (str, maxLength) {
|
|
189
|
+
function toString (str, maxLength, incomplete) {
|
|
164
190
|
const size = str.length
|
|
165
191
|
|
|
166
192
|
if (size <= maxLength) {
|
|
167
193
|
return { type: 'string', value: str }
|
|
168
194
|
}
|
|
169
195
|
|
|
196
|
+
incomplete.reasons |= INCOMPLETE_REASON.STRING_LENGTH
|
|
197
|
+
|
|
170
198
|
return {
|
|
171
199
|
type: 'string',
|
|
172
200
|
value: str.slice(0, maxLength),
|
|
@@ -175,16 +203,17 @@ function toString (str, maxLength) {
|
|
|
175
203
|
}
|
|
176
204
|
}
|
|
177
205
|
|
|
178
|
-
function toObject (type, props, maxLength, timeBudgetReached) {
|
|
179
|
-
if (timeBudgetReached === true) return notCapturedTimeBudget(type)
|
|
180
|
-
if (props === undefined) return notCapturedDepth(type)
|
|
206
|
+
function toObject (type, props, maxLength, timeBudgetReached, incomplete) {
|
|
207
|
+
if (timeBudgetReached === true) return notCapturedTimeBudget(type, incomplete)
|
|
208
|
+
if (props === undefined) return notCapturedDepth(type, incomplete)
|
|
181
209
|
|
|
182
210
|
const result = {
|
|
183
211
|
type,
|
|
184
|
-
fields: processProperties(props, maxLength),
|
|
212
|
+
fields: processProperties(props, maxLength, incomplete),
|
|
185
213
|
}
|
|
186
214
|
|
|
187
215
|
if (props[fieldCountSym] !== undefined) {
|
|
216
|
+
incomplete.reasons |= INCOMPLETE_REASON.FIELD_COUNT
|
|
188
217
|
result.notCapturedReason = 'fieldCount'
|
|
189
218
|
result.size = props[fieldCountSym]
|
|
190
219
|
}
|
|
@@ -192,27 +221,29 @@ function toObject (type, props, maxLength, timeBudgetReached) {
|
|
|
192
221
|
return result
|
|
193
222
|
}
|
|
194
223
|
|
|
195
|
-
function toArray (type, elements, maxLength, timeBudgetReached) {
|
|
196
|
-
if (timeBudgetReached === true) return notCapturedTimeBudget(type)
|
|
197
|
-
if (elements === undefined) return notCapturedDepth(type)
|
|
224
|
+
function toArray (type, elements, maxLength, timeBudgetReached, incomplete) {
|
|
225
|
+
if (timeBudgetReached === true) return notCapturedTimeBudget(type, incomplete)
|
|
226
|
+
if (elements === undefined) return notCapturedDepth(type, incomplete)
|
|
198
227
|
|
|
199
228
|
const result = {
|
|
200
229
|
type,
|
|
201
230
|
elements: elements.map((element) => {
|
|
202
|
-
return getPropertyValue(element, maxLength)
|
|
231
|
+
return getPropertyValue(element, maxLength, incomplete)
|
|
203
232
|
}),
|
|
204
233
|
}
|
|
205
234
|
|
|
206
|
-
setNotCaptureReasonOnCollection(result, elements)
|
|
207
|
-
setNotCaptureReasonOnTooLargeCollection(result, elements)
|
|
235
|
+
setNotCaptureReasonOnCollection(result, elements, incomplete)
|
|
236
|
+
setNotCaptureReasonOnTooLargeCollection(result, elements, incomplete)
|
|
208
237
|
|
|
209
238
|
return result
|
|
210
239
|
}
|
|
211
240
|
|
|
212
|
-
function toMap (type, pairs, maxLength, timeBudgetReached) {
|
|
213
|
-
if (timeBudgetReached === true) return notCapturedTimeBudget(type)
|
|
214
|
-
if (pairs === undefined) return notCapturedDepth(type)
|
|
215
|
-
if (pairs.length > 0 && pairs.every(({ value }) => value[timeBudgetSym] === true))
|
|
241
|
+
function toMap (type, pairs, maxLength, timeBudgetReached, incomplete) {
|
|
242
|
+
if (timeBudgetReached === true) return notCapturedTimeBudget(type, incomplete)
|
|
243
|
+
if (pairs === undefined) return notCapturedDepth(type, incomplete)
|
|
244
|
+
if (pairs.length > 0 && pairs.every(({ value }) => value[timeBudgetSym] === true)) {
|
|
245
|
+
return notCapturedTimeBudget(type, incomplete)
|
|
246
|
+
}
|
|
216
247
|
|
|
217
248
|
const result = {
|
|
218
249
|
type,
|
|
@@ -227,32 +258,34 @@ function toMap (type, pairs, maxLength, timeBudgetReached) {
|
|
|
227
258
|
// second containing the value of this entry of the Map.
|
|
228
259
|
|
|
229
260
|
if (value[timeBudgetSym] === true) {
|
|
261
|
+
incomplete.reasons |= INCOMPLETE_REASON.TIMEOUT
|
|
230
262
|
return [{ notCapturedReason: 'timeout' }, { notCapturedReason: 'timeout' }]
|
|
231
263
|
}
|
|
232
264
|
if (value.properties === undefined) {
|
|
265
|
+
incomplete.reasons |= INCOMPLETE_REASON.OTHER
|
|
233
266
|
return [{ notCapturedReason: 'unknown' }, { notCapturedReason: 'unknown' }]
|
|
234
267
|
}
|
|
235
268
|
|
|
236
269
|
const shouldRedact = shouldRedactMapValue(value.properties[0])
|
|
237
|
-
const key = getPropertyValue(value.properties[0], maxLength)
|
|
270
|
+
const key = getPropertyValue(value.properties[0], maxLength, incomplete)
|
|
238
271
|
const val = shouldRedact
|
|
239
272
|
? notCapturedRedacted(value.properties[1].value.type)
|
|
240
|
-
: getPropertyValue(value.properties[1], maxLength)
|
|
273
|
+
: getPropertyValue(value.properties[1], maxLength, incomplete)
|
|
241
274
|
return [key, val]
|
|
242
275
|
}),
|
|
243
276
|
}
|
|
244
277
|
|
|
245
|
-
setNotCaptureReasonOnCollection(result, pairs)
|
|
246
|
-
setNotCaptureReasonOnTooLargeCollection(result, pairs)
|
|
278
|
+
setNotCaptureReasonOnCollection(result, pairs, incomplete)
|
|
279
|
+
setNotCaptureReasonOnTooLargeCollection(result, pairs, incomplete)
|
|
247
280
|
|
|
248
281
|
return result
|
|
249
282
|
}
|
|
250
283
|
|
|
251
|
-
function toSet (type, values, maxLength, timeBudgetReached) {
|
|
252
|
-
if (timeBudgetReached === true) return notCapturedTimeBudget(type)
|
|
253
|
-
if (values === undefined) return notCapturedDepth(type)
|
|
284
|
+
function toSet (type, values, maxLength, timeBudgetReached, incomplete) {
|
|
285
|
+
if (timeBudgetReached === true) return notCapturedTimeBudget(type, incomplete)
|
|
286
|
+
if (values === undefined) return notCapturedDepth(type, incomplete)
|
|
254
287
|
if (values.length > 0 && values.every(({ value }) => value[timeBudgetSym] === true)) {
|
|
255
|
-
return notCapturedTimeBudget(type)
|
|
288
|
+
return notCapturedTimeBudget(type, incomplete)
|
|
256
289
|
}
|
|
257
290
|
|
|
258
291
|
const result = {
|
|
@@ -267,33 +300,42 @@ function toSet (type, values, maxLength, timeBudgetReached) {
|
|
|
267
300
|
// children, of which there will always be exactly one, which contain the
|
|
268
301
|
// actual value in this entry of the Set.
|
|
269
302
|
|
|
270
|
-
if (value[timeBudgetSym] === true)
|
|
271
|
-
|
|
303
|
+
if (value[timeBudgetSym] === true) {
|
|
304
|
+
incomplete.reasons |= INCOMPLETE_REASON.TIMEOUT
|
|
305
|
+
return { notCapturedReason: 'timeout' }
|
|
306
|
+
}
|
|
307
|
+
if (value.properties === undefined) {
|
|
308
|
+
incomplete.reasons |= INCOMPLETE_REASON.OTHER
|
|
309
|
+
return { notCapturedReason: 'unknown' }
|
|
310
|
+
}
|
|
272
311
|
|
|
273
|
-
return getPropertyValue(value.properties[0], maxLength)
|
|
312
|
+
return getPropertyValue(value.properties[0], maxLength, incomplete)
|
|
274
313
|
}),
|
|
275
314
|
}
|
|
276
315
|
|
|
277
|
-
setNotCaptureReasonOnCollection(result, values)
|
|
278
|
-
setNotCaptureReasonOnTooLargeCollection(result, values)
|
|
316
|
+
setNotCaptureReasonOnCollection(result, values, incomplete)
|
|
317
|
+
setNotCaptureReasonOnTooLargeCollection(result, values, incomplete)
|
|
279
318
|
|
|
280
319
|
return result
|
|
281
320
|
}
|
|
282
321
|
|
|
283
|
-
function toArrayBuffer (type, bytes, maxLength, timeBudgetReached) {
|
|
284
|
-
if (timeBudgetReached === true) return notCapturedTimeBudget(type)
|
|
285
|
-
if (bytes === undefined) return notCapturedDepth(type)
|
|
322
|
+
function toArrayBuffer (type, bytes, maxLength, timeBudgetReached, incomplete) {
|
|
323
|
+
if (timeBudgetReached === true) return notCapturedTimeBudget(type, incomplete)
|
|
324
|
+
if (bytes === undefined) return notCapturedDepth(type, incomplete)
|
|
286
325
|
|
|
287
326
|
const size = bytes.length
|
|
288
327
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
328
|
+
if (size > maxLength) {
|
|
329
|
+
incomplete.reasons |= INCOMPLETE_REASON.STRING_LENGTH
|
|
330
|
+
return {
|
|
331
|
+
type,
|
|
332
|
+
value: arrayBufferToString(bytes, maxLength),
|
|
333
|
+
truncated: true,
|
|
334
|
+
size: bytes.length,
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return { type, value: arrayBufferToString(bytes, size) }
|
|
297
339
|
}
|
|
298
340
|
|
|
299
341
|
function arrayBufferToString (bytes, size) {
|
|
@@ -304,9 +346,8 @@ function arrayBufferToString (bytes, size) {
|
|
|
304
346
|
return buf.toString()
|
|
305
347
|
}
|
|
306
348
|
|
|
307
|
-
function
|
|
308
|
-
|
|
309
|
-
return REDACTED_IDENTIFIERS.has(name) ? notCapturedRedacted(obj.type) : obj
|
|
349
|
+
function shouldRedactProperty (prop) {
|
|
350
|
+
return REDACTED_IDENTIFIERS.has(getNormalizedNameFromProp(prop))
|
|
310
351
|
}
|
|
311
352
|
|
|
312
353
|
function shouldRedactMapValue (key) {
|
|
@@ -323,15 +364,19 @@ function getNormalizedNameFromProp (prop) {
|
|
|
323
364
|
return normalizeName(prop.name, prop.symbol !== undefined)
|
|
324
365
|
}
|
|
325
366
|
|
|
326
|
-
function setNotCaptureReasonOnCollection (result, collection) {
|
|
367
|
+
function setNotCaptureReasonOnCollection (result, collection, incomplete) {
|
|
327
368
|
if (collection[collectionSizeSym] !== undefined) {
|
|
369
|
+
incomplete.reasons |= INCOMPLETE_REASON.COLLECTION_SIZE
|
|
328
370
|
result.notCapturedReason = 'collectionSize'
|
|
329
371
|
result.size = collection[collectionSizeSym]
|
|
330
372
|
}
|
|
331
373
|
}
|
|
332
374
|
|
|
333
|
-
function setNotCaptureReasonOnTooLargeCollection (result, collection) {
|
|
375
|
+
function setNotCaptureReasonOnTooLargeCollection (result, collection, incomplete) {
|
|
334
376
|
if (collection[largeCollectionSkipThresholdSym] !== undefined) {
|
|
377
|
+
// The collection was skipped entirely because it exceeded the skip threshold, which is a different limit than the
|
|
378
|
+
// `maxCollectionSize` limit that `collectionSize` represents
|
|
379
|
+
incomplete.reasons |= INCOMPLETE_REASON.OTHER
|
|
335
380
|
result.notCapturedReason = `Large collection with too many elements (skip threshold: ${
|
|
336
381
|
LARGE_OBJECT_SKIP_THRESHOLD
|
|
337
382
|
})`
|
|
@@ -339,7 +384,8 @@ function setNotCaptureReasonOnTooLargeCollection (result, collection) {
|
|
|
339
384
|
}
|
|
340
385
|
}
|
|
341
386
|
|
|
342
|
-
function notCapturedDepth (type) {
|
|
387
|
+
function notCapturedDepth (type, incomplete) {
|
|
388
|
+
incomplete.reasons |= INCOMPLETE_REASON.DEPTH
|
|
343
389
|
return { type, notCapturedReason: 'depth' }
|
|
344
390
|
}
|
|
345
391
|
|
|
@@ -347,6 +393,7 @@ function notCapturedRedacted (type) {
|
|
|
347
393
|
return { type, notCapturedReason: 'redactedIdent' }
|
|
348
394
|
}
|
|
349
395
|
|
|
350
|
-
function notCapturedTimeBudget (type) {
|
|
396
|
+
function notCapturedTimeBudget (type, incomplete) {
|
|
397
|
+
incomplete.reasons |= INCOMPLETE_REASON.TIMEOUT
|
|
351
398
|
return { type, notCapturedReason: 'timeout' }
|
|
352
399
|
}
|
|
@@ -143,7 +143,6 @@ class PriorityQueue {
|
|
|
143
143
|
*
|
|
144
144
|
* @param {TreeNode} a - First node to compare
|
|
145
145
|
* @param {TreeNode} b - Second node to compare
|
|
146
|
-
* @returns {number} - > 0 if a has higher priority, < 0 if b has higher priority, 0 if equal
|
|
147
146
|
*/
|
|
148
147
|
#compare (a, b) {
|
|
149
148
|
const keyA = a.priorityKey
|
|
@@ -243,7 +242,6 @@ function parseJsonToTree (json) {
|
|
|
243
242
|
*
|
|
244
243
|
* @param {string} json - The JSON string to skip
|
|
245
244
|
* @param {number} startIndex - The index to start skipping from
|
|
246
|
-
* @returns {number} The index of the closing quote
|
|
247
245
|
*/
|
|
248
246
|
function skipString (json, startIndex) {
|
|
249
247
|
let index = startIndex + 1 // Skip opening quote
|
|
@@ -353,7 +351,6 @@ function selectNodesToPrune (root, bytesToRemove) {
|
|
|
353
351
|
*
|
|
354
352
|
* @param {string} json - The JSON string to rebuild
|
|
355
353
|
* @param {Set<TreeNode>} prunedNodes - The set of nodes to replace with {"pruned":true}
|
|
356
|
-
* @returns {string} The rebuilt JSON string
|
|
357
354
|
*/
|
|
358
355
|
function rebuildJson (json, prunedNodes) {
|
|
359
356
|
// Convert set to array and sort by start position (descending)
|
|
@@ -7,8 +7,10 @@ const { version } = require('../../../../../package.json')
|
|
|
7
7
|
const TTLSet = require('../../../../../vendor/dist/ttl-set')
|
|
8
8
|
const request = require('../../exporters/common/request')
|
|
9
9
|
const FormData = require('../../exporters/common/form-data')
|
|
10
|
-
const { DEBUGGER_DIAGNOSTICS_V1 } = require('../constants')
|
|
10
|
+
const { DEBUGGER_DIAGNOSTICS_V1, DIAGNOSTICS_QUEUE_MAX_BYTES } = require('../constants')
|
|
11
|
+
const { DROPPED_REASON, EVENT_TYPE } = require('../guardrail-metrics')
|
|
11
12
|
const config = require('./config')
|
|
13
|
+
const guardrailMetrics = require('./guardrail-metrics')
|
|
12
14
|
const JSONBuffer = require('./json-buffer')
|
|
13
15
|
const log = require('./log')
|
|
14
16
|
const getRequestOptions = require('./request-options')
|
|
@@ -28,8 +30,11 @@ const ddtags = buildTags(config, getHostname(), version, log)
|
|
|
28
30
|
|
|
29
31
|
const cache = new TTLSet(60 * 60 * 1000) // 1 hour
|
|
30
32
|
|
|
33
|
+
// Diagnostics are queued separately from probe results so that large snapshots cannot starve them. Each diagnostic is
|
|
34
|
+
// a few hundred bytes, so this bound leaves room for thousands of pending status updates.
|
|
31
35
|
const jsonBuffer = new JSONBuffer({
|
|
32
36
|
size: config.maxTotalPayloadSize,
|
|
37
|
+
maxQueueBytes: DIAGNOSTICS_QUEUE_MAX_BYTES,
|
|
33
38
|
timeout: config.dynamicInstrumentation.uploadIntervalSeconds * 1000,
|
|
34
39
|
onFlush,
|
|
35
40
|
})
|
|
@@ -81,15 +86,24 @@ function ackError (err, { id: probeId, version }) {
|
|
|
81
86
|
stacktrace: err.stack,
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
send(payload)
|
|
89
|
+
return send(payload)
|
|
85
90
|
})
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
function send (payload) {
|
|
89
|
-
jsonBuffer.write(JSON.stringify(payload))
|
|
94
|
+
if (jsonBuffer.write(JSON.stringify(payload))) return true
|
|
95
|
+
|
|
96
|
+
const { probeId, status } = payload.debugger.diagnostics
|
|
97
|
+
log.debug('[debugger:devtools_client] Dropping %s status for probe %s: diagnostics queue is full', status, probeId)
|
|
98
|
+
guardrailMetrics.eventDropped(DROPPED_REASON.QUEUE_FULL, EVENT_TYPE.DIAGNOSTIC)
|
|
99
|
+
return false
|
|
90
100
|
}
|
|
91
101
|
|
|
92
|
-
|
|
102
|
+
/**
|
|
103
|
+
* @param {string} payload - The payload to send
|
|
104
|
+
* @param {() => void} done - Releases the payload from the diagnostics queue
|
|
105
|
+
*/
|
|
106
|
+
function onFlush (payload, done) {
|
|
93
107
|
log.debug('[debugger:devtools_client] Flushing diagnostics payload buffer')
|
|
94
108
|
|
|
95
109
|
const form = new FormData()
|
|
@@ -106,6 +120,7 @@ function onFlush (payload) {
|
|
|
106
120
|
const options = getRequestOptions(config, path, form.getHeaders())
|
|
107
121
|
|
|
108
122
|
request(form, options, (err) => {
|
|
123
|
+
done()
|
|
109
124
|
if (err) log.error('[debugger:devtools_client] Error sending diagnostics payload', err)
|
|
110
125
|
})
|
|
111
126
|
}
|
|
@@ -123,6 +138,5 @@ function statusPayload (probeId, probeVersion, status) {
|
|
|
123
138
|
function onlyUniqueUpdates (type, id, version, fn) {
|
|
124
139
|
const key = `${type}-${id}-${version}`
|
|
125
140
|
if (cache.has(key)) return
|
|
126
|
-
fn()
|
|
127
|
-
cache.add(key)
|
|
141
|
+
if (fn()) cache.add(key)
|
|
128
142
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Guardrail telemetry counters shared between the main thread and the debugger worker thread.
|
|
5
|
+
*
|
|
6
|
+
* Guardrail decisions are made in two places: the probe sampler that runs inside the V8 breakpoint condition on the
|
|
7
|
+
* main thread (rate limits) and the debugger worker (capture limits, queue overflow). Neither should pay for a message
|
|
8
|
+
* or a telemetry API call per skipped, dropped or incomplete event, so both increment counters in a shared buffer using
|
|
9
|
+
* atomics, and the main thread periodically drains the counters into instrumentation telemetry metrics.
|
|
10
|
+
*
|
|
11
|
+
* The metric names, tags and reason codes are defined by the "Debugger Observability for GA" specification and are
|
|
12
|
+
* shared with the other tracers. All metrics are counts in the `live_debugger` telemetry namespace.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const TELEMETRY_NAMESPACE = 'live_debugger'
|
|
16
|
+
|
|
17
|
+
const EVENT_TYPE = Object.freeze({
|
|
18
|
+
SNAPSHOT: 0,
|
|
19
|
+
LOG: 1,
|
|
20
|
+
DIAGNOSTIC: 2,
|
|
21
|
+
})
|
|
22
|
+
const EVENT_TYPE_NAMES = ['snapshot', 'log', 'diagnostic']
|
|
23
|
+
|
|
24
|
+
/** Attempts stopped before event creation (`events.skipped`) */
|
|
25
|
+
const SKIPPED_REASON = Object.freeze({
|
|
26
|
+
RATE_LIMIT_GLOBAL: 0,
|
|
27
|
+
RATE_LIMIT_PROBE: 1,
|
|
28
|
+
EVALUATION_TIMEOUT: 2,
|
|
29
|
+
})
|
|
30
|
+
const SKIPPED_REASON_NAMES = ['rateLimitGlobal', 'rateLimitProbe', 'evaluationTimeout']
|
|
31
|
+
|
|
32
|
+
/** Complete events dropped before transport (`events.dropped`) */
|
|
33
|
+
const DROPPED_REASON = Object.freeze({
|
|
34
|
+
QUEUE_FULL: 0,
|
|
35
|
+
// The spec allows either trimming oversized payloads or dropping them whole. This tracer trims, and reports
|
|
36
|
+
// `capture.incomplete{payloadTooLarge}` instead, so this reason exists for spec parity but is never emitted.
|
|
37
|
+
PAYLOAD_TOO_LARGE: 1,
|
|
38
|
+
})
|
|
39
|
+
const DROPPED_REASON_NAMES = ['queueFull', 'payloadTooLarge']
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Capture enforced limits (`capture.incomplete`). These are bit flags so that the reasons hit while producing a single
|
|
43
|
+
* event can be accumulated in a bitmask and reported once per event per reason.
|
|
44
|
+
*/
|
|
45
|
+
const INCOMPLETE_REASON = Object.freeze({
|
|
46
|
+
RUNTIME_ERROR: 1 << 0,
|
|
47
|
+
TIMEOUT: 1 << 1,
|
|
48
|
+
DEPTH: 1 << 2,
|
|
49
|
+
FIELD_COUNT: 1 << 3,
|
|
50
|
+
COLLECTION_SIZE: 1 << 4,
|
|
51
|
+
STRING_LENGTH: 1 << 5,
|
|
52
|
+
PAYLOAD_TOO_LARGE: 1 << 6,
|
|
53
|
+
OTHER: 1 << 7,
|
|
54
|
+
})
|
|
55
|
+
const INCOMPLETE_REASON_NAMES = [
|
|
56
|
+
'runtimeError', 'timeout', 'depth', 'fieldCount', 'collectionSize', 'stringLength', 'payloadTooLarge', 'other',
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
const EVENT_TYPE_COUNT = EVENT_TYPE_NAMES.length
|
|
60
|
+
const SKIPPED_OFFSET = 0
|
|
61
|
+
const DROPPED_OFFSET = SKIPPED_OFFSET + SKIPPED_REASON_NAMES.length * EVENT_TYPE_COUNT
|
|
62
|
+
const INCOMPLETE_OFFSET = DROPPED_OFFSET + DROPPED_REASON_NAMES.length * EVENT_TYPE_COUNT
|
|
63
|
+
const SLOT_COUNT = INCOMPLETE_OFFSET + INCOMPLETE_REASON_NAMES.length * EVENT_TYPE_COUNT
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {object} MetricSlot
|
|
67
|
+
* @property {string} metric - The telemetry metric name
|
|
68
|
+
* @property {string[]} tags - The telemetry tags, sorted
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/** @type {MetricSlot[]} */
|
|
72
|
+
const SLOTS = []
|
|
73
|
+
addSlots('events.skipped', SKIPPED_REASON_NAMES)
|
|
74
|
+
addSlots('events.dropped', DROPPED_REASON_NAMES)
|
|
75
|
+
addSlots('capture.incomplete', INCOMPLETE_REASON_NAMES)
|
|
76
|
+
|
|
77
|
+
class GuardrailMetrics {
|
|
78
|
+
/** @type {Int32Array} */
|
|
79
|
+
#counters
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {SharedArrayBuffer} buffer - A buffer created with {@link GuardrailMetrics.createBuffer}
|
|
83
|
+
*/
|
|
84
|
+
constructor (buffer) {
|
|
85
|
+
this.#counters = new Int32Array(buffer)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Create the shared buffer backing the counters.
|
|
90
|
+
*
|
|
91
|
+
* @returns {SharedArrayBuffer}
|
|
92
|
+
*/
|
|
93
|
+
static createBuffer () {
|
|
94
|
+
return new SharedArrayBuffer(SLOT_COUNT * Int32Array.BYTES_PER_ELEMENT)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Record an attempt that was stopped before an event was created.
|
|
99
|
+
*
|
|
100
|
+
* @param {number} reason - One of {@link SKIPPED_REASON}
|
|
101
|
+
* @param {number} eventType - One of {@link EVENT_TYPE}
|
|
102
|
+
*/
|
|
103
|
+
eventSkipped (reason, eventType) {
|
|
104
|
+
Atomics.add(this.#counters, SKIPPED_OFFSET + reason * EVENT_TYPE_COUNT + eventType, 1)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Record a complete event that was dropped before transport.
|
|
109
|
+
*
|
|
110
|
+
* @param {number} reason - One of {@link DROPPED_REASON}
|
|
111
|
+
* @param {number} eventType - One of {@link EVENT_TYPE}
|
|
112
|
+
* @param {number} [count] - The number of dropped events
|
|
113
|
+
*/
|
|
114
|
+
eventDropped (reason, eventType, count = 1) {
|
|
115
|
+
Atomics.add(this.#counters, DROPPED_OFFSET + reason * EVENT_TYPE_COUNT + eventType, count)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Record the capture limits enforced while producing a single event, once per reason.
|
|
120
|
+
*
|
|
121
|
+
* @param {number} reasons - A bitmask of {@link INCOMPLETE_REASON} flags
|
|
122
|
+
* @param {number} eventType - One of {@link EVENT_TYPE}
|
|
123
|
+
*/
|
|
124
|
+
captureIncomplete (reasons, eventType) {
|
|
125
|
+
for (let bit = 0; reasons !== 0; bit++, reasons >>>= 1) {
|
|
126
|
+
if ((reasons & 1) === 1) {
|
|
127
|
+
Atomics.add(this.#counters, INCOMPLETE_OFFSET + bit * EVENT_TYPE_COUNT + eventType, 1)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Reset all counters and report the ones that were non-zero.
|
|
134
|
+
*
|
|
135
|
+
* @param {(metric: string, tags: string[], count: number) => void} report - Called once per non-zero counter
|
|
136
|
+
*/
|
|
137
|
+
drain (report) {
|
|
138
|
+
for (let i = 0; i < SLOT_COUNT; i++) {
|
|
139
|
+
const count = Atomics.exchange(this.#counters, i, 0)
|
|
140
|
+
if (count !== 0) {
|
|
141
|
+
const { metric, tags } = SLOTS[i]
|
|
142
|
+
report(metric, tags, count)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @param {string} metric
|
|
150
|
+
* @param {string[]} reasonNames
|
|
151
|
+
*/
|
|
152
|
+
function addSlots (metric, reasonNames) {
|
|
153
|
+
for (const reason of reasonNames) {
|
|
154
|
+
for (const eventType of EVENT_TYPE_NAMES) {
|
|
155
|
+
SLOTS.push({ metric, tags: [`event_type:${eventType}`, `reason:${reason}`] })
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
DROPPED_REASON,
|
|
162
|
+
EVENT_TYPE,
|
|
163
|
+
GuardrailMetrics,
|
|
164
|
+
INCOMPLETE_REASON,
|
|
165
|
+
SKIPPED_REASON,
|
|
166
|
+
TELEMETRY_NAMESPACE,
|
|
167
|
+
}
|