dd-trace 6.16.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/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 +0 -6
- 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/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 +0 -1
- package/ci/test-optimization-validation/source-text.js +0 -3
- package/ci/vitest-no-worker-init-setup.mjs +41 -16
- package/index.d.ts +165 -0
- package/package.json +17 -16
- package/packages/datadog-esbuild/src/utils.js +0 -2
- package/packages/datadog-instrumentations/src/aerospike.js +28 -6
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -2
- package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +0 -2
- 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/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/instrumentation-utils.js +0 -3
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
- package/packages/datadog-instrumentations/src/helpers/register.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +72 -24
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
- 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/targets.json +16 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +0 -5
- 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/mariadb-bundle.js +0 -24
- package/packages/datadog-instrumentations/src/mariadb.js +0 -2
- 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/mysql2.js +0 -2
- 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 +51 -12
- 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 +49 -13
- 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 +0 -1
- 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-durable-functions/src/index.js +0 -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-graphql/src/resolve-error.js +1 -2
- 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 +0 -6
- package/packages/datadog-turbopack/src/loader.js +0 -16
- 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 +2 -2
- package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
- package/packages/dd-trace/src/aiguard/integrations/openai.js +81 -7
- 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 +0 -1
- 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-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/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 +73 -67
- package/packages/dd-trace/src/config/helper.js +0 -1
- package/packages/dd-trace/src/config/index.js +24 -24
- 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 +139 -10
- 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 +62 -10
- 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 +21 -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 +0 -1
- package/packages/dd-trace/src/evp_proxy/path.js +0 -2
- 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/final-flush-request-tracker.js +0 -6
- 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/meter_provider.js +0 -1
- 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 +1 -14
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +30 -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/plugins/ci_plugin.js +0 -1
- package/packages/dd-trace/src/plugins/database.js +2 -6
- package/packages/dd-trace/src/plugins/index.js +7 -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 +21 -20
- 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
|
@@ -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,7 @@ const SAMPLER_EXPRESSION = `globalThis[Symbol.for(${JSON.stringify(DD_TRACE_SYMB
|
|
|
8
8
|
module.exports = {
|
|
9
9
|
compileBreakpointCondition,
|
|
10
10
|
getRemoveProbeExpression,
|
|
11
|
+
getTakeConditionErrorExpression,
|
|
11
12
|
isSnapshotProducingProbe,
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -17,7 +18,6 @@ module.exports = {
|
|
|
17
18
|
* global snapshot rate limit.
|
|
18
19
|
*
|
|
19
20
|
* @param {{ captureSnapshot?: boolean, compiledCaptureExpressions?: object[] }} probe - The probe to inspect.
|
|
20
|
-
* @returns {boolean}
|
|
21
21
|
*/
|
|
22
22
|
function isSnapshotProducingProbe (probe) {
|
|
23
23
|
return probe.captureSnapshot === true || probe.compiledCaptureExpressions !== undefined
|
|
@@ -28,12 +28,21 @@ function isSnapshotProducingProbe (probe) {
|
|
|
28
28
|
* the debuggee.
|
|
29
29
|
*
|
|
30
30
|
* @param {string} id - The probe id.
|
|
31
|
-
* @returns {string}
|
|
32
31
|
*/
|
|
33
32
|
function getRemoveProbeExpression (id) {
|
|
34
33
|
return `${SAMPLER_EXPRESSION}?.remove(${JSON.stringify(id)})`
|
|
35
34
|
}
|
|
36
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
|
+
|
|
37
46
|
/**
|
|
38
47
|
* Build a Chrome DevTools breakpoint condition that samples all matching probes at a location. Called by the devtools
|
|
39
48
|
* worker.
|
|
@@ -46,7 +55,6 @@ function getRemoveProbeExpression (id) {
|
|
|
46
55
|
* captureSnapshot?: boolean,
|
|
47
56
|
* compiledCaptureExpressions?: object[]
|
|
48
57
|
* }[]} probes - The probes at the breakpoint location.
|
|
49
|
-
* @returns {string}
|
|
50
58
|
*/
|
|
51
59
|
function compileBreakpointCondition (probes) {
|
|
52
60
|
const probeConditions = probes.map(compileProbeCondition)
|
|
@@ -75,7 +83,6 @@ function compileBreakpointCondition (probes) {
|
|
|
75
83
|
* captureSnapshot?: boolean,
|
|
76
84
|
* compiledCaptureExpressions?: object[]
|
|
77
85
|
* }} probe - The probe to sample.
|
|
78
|
-
* @returns {string}
|
|
79
86
|
*/
|
|
80
87
|
function compileProbeCondition (probe) {
|
|
81
88
|
const sample = `$dd_sampler.makeSampleDecision(${probe.samplingIndex}, ${JSON.stringify(probe.id)}, ` +
|
|
@@ -85,9 +92,15 @@ function compileProbeCondition (probe) {
|
|
|
85
92
|
return `$dd_sampled = ${sample} || $dd_sampled`
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
|
91
104
|
}
|
|
92
|
-
}
|
|
105
|
+
}`
|
|
93
106
|
}
|
|
@@ -5,17 +5,18 @@ const { stringify } = require('querystring')
|
|
|
5
5
|
|
|
6
6
|
const { version } = require('../../../../../package.json')
|
|
7
7
|
const request = require('../../exporters/common/request')
|
|
8
|
-
const { DEBUGGER_DIAGNOSTICS_V1, DEBUGGER_INPUT_V2 } = require('../constants')
|
|
8
|
+
const { DEBUGGER_DIAGNOSTICS_V1, DEBUGGER_INPUT_V2, MAX_MESSAGE_LENGTH } = require('../constants')
|
|
9
|
+
const { DROPPED_REASON, INCOMPLETE_REASON } = require('../guardrail-metrics')
|
|
9
10
|
const log = require('./log')
|
|
10
11
|
const JSONBuffer = require('./json-buffer')
|
|
11
12
|
const config = require('./config')
|
|
13
|
+
const guardrailMetrics = require('./guardrail-metrics')
|
|
12
14
|
const getRequestOptions = require('./request-options')
|
|
13
15
|
const { pruneSnapshot } = require('./snapshot-pruner')
|
|
14
16
|
const buildTags = require('./tags')
|
|
15
17
|
|
|
16
18
|
module.exports = send
|
|
17
19
|
|
|
18
|
-
const MAX_MESSAGE_LENGTH = 8 * 1024 // 8KB
|
|
19
20
|
const MAX_LOG_PAYLOAD_SIZE_MB = 1
|
|
20
21
|
const MAX_LOG_PAYLOAD_SIZE_BYTES = MAX_LOG_PAYLOAD_SIZE_MB * 1024 * 1024
|
|
21
22
|
|
|
@@ -30,18 +31,33 @@ setInputPath(config.inputPath)
|
|
|
30
31
|
|
|
31
32
|
const jsonBuffer = new JSONBuffer({
|
|
32
33
|
size: config.maxTotalPayloadSize,
|
|
34
|
+
maxQueueBytes: config.queueMaxBytes,
|
|
33
35
|
timeout: config.dynamicInstrumentation.uploadIntervalSeconds * 1000,
|
|
34
36
|
onFlush,
|
|
35
37
|
})
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Queue a probe result for upload.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} message - The evaluated log message
|
|
43
|
+
* @param {object} logger - The logger metadata
|
|
44
|
+
* @param {object | undefined} dd - The trace and span ids of the active trace, if any
|
|
45
|
+
* @param {object} snapshot - The snapshot payload
|
|
46
|
+
* @param {string | undefined} processTags - The serialized process tags, if enabled
|
|
47
|
+
* @param {number} eventType - The guardrail event type, one of `EVENT_TYPE`
|
|
48
|
+
* @param {number} incompleteReasons - Bitmask of `INCOMPLETE_REASON` flags enforced while capturing the snapshot
|
|
49
|
+
*/
|
|
50
|
+
function send (message, logger, dd, snapshot, processTags, eventType, incompleteReasons) {
|
|
51
|
+
if (message?.length > MAX_MESSAGE_LENGTH) {
|
|
52
|
+
message = message.slice(0, MAX_MESSAGE_LENGTH) + '…'
|
|
53
|
+
incompleteReasons |= INCOMPLETE_REASON.STRING_LENGTH
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
const payload = {
|
|
39
57
|
ddsource,
|
|
40
58
|
hostname,
|
|
41
59
|
service,
|
|
42
|
-
message
|
|
43
|
-
? message.slice(0, MAX_MESSAGE_LENGTH) + '…'
|
|
44
|
-
: message,
|
|
60
|
+
message,
|
|
45
61
|
logger,
|
|
46
62
|
dd,
|
|
47
63
|
process_tags: processTags,
|
|
@@ -52,6 +68,7 @@ function send (message, logger, dd, snapshot, processTags) {
|
|
|
52
68
|
let size = Buffer.byteLength(json)
|
|
53
69
|
|
|
54
70
|
if (size > MAX_LOG_PAYLOAD_SIZE_BYTES) {
|
|
71
|
+
incompleteReasons |= INCOMPLETE_REASON.PAYLOAD_TOO_LARGE
|
|
55
72
|
let pruned
|
|
56
73
|
try {
|
|
57
74
|
pruned = pruneSnapshot(json, size, MAX_LOG_PAYLOAD_SIZE_BYTES)
|
|
@@ -61,7 +78,7 @@ function send (message, logger, dd, snapshot, processTags) {
|
|
|
61
78
|
|
|
62
79
|
if (pruned) {
|
|
63
80
|
json = pruned
|
|
64
|
-
} else {
|
|
81
|
+
} else if (snapshot.captures !== undefined) {
|
|
65
82
|
// Fallback if pruning fails
|
|
66
83
|
const line = Object.keys(snapshot.captures.lines)[0]
|
|
67
84
|
snapshot.captures.lines[line] = { pruned: true }
|
|
@@ -70,28 +87,36 @@ function send (message, logger, dd, snapshot, processTags) {
|
|
|
70
87
|
size = Buffer.byteLength(json)
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
jsonBuffer.write(json, size)
|
|
90
|
+
if (jsonBuffer.write(json, size)) {
|
|
91
|
+
if (incompleteReasons !== 0) guardrailMetrics.captureIncomplete(incompleteReasons, eventType)
|
|
92
|
+
} else {
|
|
93
|
+
// The upload queue is full, typically because the intake is slow or unreachable. Dropping is the only option that
|
|
94
|
+
// keeps memory bounded without blocking.
|
|
95
|
+
log.debug('[debugger:devtools_client] Dropping probe result for probe %s: upload queue is full', snapshot.probe.id)
|
|
96
|
+
guardrailMetrics.eventDropped(DROPPED_REASON.QUEUE_FULL, eventType)
|
|
97
|
+
}
|
|
74
98
|
}
|
|
75
99
|
|
|
76
100
|
/**
|
|
77
101
|
* @param {string} payload - The payload to send
|
|
102
|
+
* @param {() => void} done - Releases the payload from the upload queue
|
|
78
103
|
*/
|
|
79
|
-
function onFlush (payload) {
|
|
104
|
+
function onFlush (payload, done) {
|
|
80
105
|
log.debug('[debugger:devtools_client] Flushing probe payload buffer')
|
|
81
106
|
|
|
82
107
|
request(payload, buildRequestOptions(), (err, res, statusCode) => {
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
108
|
+
if (handleV2FallbackIfNeeded(statusCode, payload, done)) return
|
|
109
|
+
done()
|
|
110
|
+
if (err) log.error('[debugger:devtools_client] Error sending probe payload', err)
|
|
86
111
|
})
|
|
87
112
|
}
|
|
88
113
|
|
|
89
114
|
/**
|
|
90
115
|
* @param {number} statusCode - The status code of the response
|
|
91
116
|
* @param {string} payload - The payload to send
|
|
92
|
-
* @
|
|
117
|
+
* @param {() => void} done - Releases the payload from the upload queue
|
|
93
118
|
*/
|
|
94
|
-
function handleV2FallbackIfNeeded (statusCode, payload) {
|
|
119
|
+
function handleV2FallbackIfNeeded (statusCode, payload, done) {
|
|
95
120
|
if (statusCode !== 404 || config.inputPath !== DEBUGGER_INPUT_V2) {
|
|
96
121
|
return false
|
|
97
122
|
}
|
|
@@ -103,6 +128,7 @@ function handleV2FallbackIfNeeded (statusCode, payload) {
|
|
|
103
128
|
setInputPath(DEBUGGER_DIAGNOSTICS_V1)
|
|
104
129
|
|
|
105
130
|
request(payload, buildRequestOptions(), (err) => {
|
|
131
|
+
done()
|
|
106
132
|
if (err) {
|
|
107
133
|
log.error('[debugger:devtools_client] Error sending probe payload after fallback to %s',
|
|
108
134
|
DEBUGGER_DIAGNOSTICS_V1,
|