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.
Files changed (334) hide show
  1. package/ci/diagnose.js +0 -23
  2. package/ci/test-optimization-validation/approval-artifacts.js +0 -3
  3. package/ci/test-optimization-validation/approval.js +0 -6
  4. package/ci/test-optimization-validation/artifact-id.js +0 -1
  5. package/ci/test-optimization-validation/bounded-json.js +0 -1
  6. package/ci/test-optimization-validation/cli.js +0 -12
  7. package/ci/test-optimization-validation/command-output-policy.js +0 -1
  8. package/ci/test-optimization-validation/command-runner.js +0 -3
  9. package/ci/test-optimization-validation/environment.js +0 -4
  10. package/ci/test-optimization-validation/executable-approval.js +0 -1
  11. package/ci/test-optimization-validation/executable.js +0 -5
  12. package/ci/test-optimization-validation/framework-adapters/cucumber.js +0 -6
  13. package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
  14. package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
  15. package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
  16. package/ci/test-optimization-validation/generated-test-contract.js +0 -5
  17. package/ci/test-optimization-validation/generated-verifier.js +0 -1
  18. package/ci/test-optimization-validation/literal-environment.js +0 -1
  19. package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
  20. package/ci/test-optimization-validation/manifest-schema.js +0 -21
  21. package/ci/test-optimization-validation/offline-fixtures.js +0 -4
  22. package/ci/test-optimization-validation/plan-writer.js +0 -11
  23. package/ci/test-optimization-validation/preflight-runner.js +0 -1
  24. package/ci/test-optimization-validation/redaction.js +0 -4
  25. package/ci/test-optimization-validation/report-writer.js +0 -16
  26. package/ci/test-optimization-validation/runner-command.js +0 -3
  27. package/ci/test-optimization-validation/runner-contract.js +0 -4
  28. package/ci/test-optimization-validation/safe-files.js +0 -1
  29. package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
  30. package/ci/test-optimization-validation/scenarios/ci-wiring.js +0 -1
  31. package/ci/test-optimization-validation/source-text.js +0 -3
  32. package/ci/vitest-no-worker-init-setup.mjs +41 -16
  33. package/index.d.ts +165 -0
  34. package/package.json +17 -16
  35. package/packages/datadog-esbuild/src/utils.js +0 -2
  36. package/packages/datadog-instrumentations/src/aerospike.js +28 -6
  37. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -2
  38. package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
  39. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +0 -2
  40. package/packages/datadog-instrumentations/src/console.js +97 -0
  41. package/packages/datadog-instrumentations/src/cucumber.js +72 -12
  42. package/packages/datadog-instrumentations/src/cypress-config.js +0 -23
  43. package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
  44. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
  45. package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -0
  46. package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +0 -3
  47. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
  48. package/packages/datadog-instrumentations/src/helpers/register.js +4 -0
  49. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +72 -24
  50. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
  51. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
  52. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +12 -0
  53. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
  54. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
  55. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +16 -0
  56. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +0 -5
  58. package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
  59. package/packages/datadog-instrumentations/src/jest.js +141 -51
  60. package/packages/datadog-instrumentations/src/knex.js +0 -1
  61. package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
  62. package/packages/datadog-instrumentations/src/mariadb.js +0 -2
  63. package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
  64. package/packages/datadog-instrumentations/src/mocha/main.js +22 -25
  65. package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
  66. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
  67. package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
  68. package/packages/datadog-instrumentations/src/mysql2.js +0 -2
  69. package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
  70. package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
  71. package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
  72. package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
  73. package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
  74. package/packages/datadog-instrumentations/src/openai.js +51 -12
  75. package/packages/datadog-instrumentations/src/oracledb.js +9 -3
  76. package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -16
  77. package/packages/datadog-instrumentations/src/playwright.js +238 -55
  78. package/packages/datadog-instrumentations/src/postgres.js +7 -0
  79. package/packages/datadog-instrumentations/src/router.js +0 -2
  80. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
  81. package/packages/datadog-instrumentations/src/sequelize.js +0 -1
  82. package/packages/datadog-instrumentations/src/supabase.js +15 -0
  83. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
  84. package/packages/datadog-instrumentations/src/vitest-main.js +37 -17
  85. package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
  86. package/packages/datadog-instrumentations/src/vitest-worker.js +49 -13
  87. package/packages/datadog-instrumentations/src/webdriverio.js +23 -42
  88. package/packages/datadog-instrumentations/src/ws.js +0 -1
  89. package/packages/datadog-plugin-ai/src/utils.js +0 -2
  90. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
  91. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
  92. package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
  93. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +0 -1
  94. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
  95. package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
  96. package/packages/datadog-plugin-azure-durable-functions/src/index.js +0 -1
  97. package/packages/datadog-plugin-cucumber/src/index.js +10 -0
  98. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +171 -75
  99. package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
  100. package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
  101. package/packages/datadog-plugin-cypress/src/support.js +52 -7
  102. package/packages/datadog-plugin-graphql/src/resolve-error.js +1 -2
  103. package/packages/datadog-plugin-graphql/src/utils.js +0 -5
  104. package/packages/datadog-plugin-jest/src/index.js +13 -0
  105. package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
  106. package/packages/datadog-plugin-mocha/src/index.js +39 -11
  107. package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
  108. package/packages/datadog-plugin-openai/src/index.js +16 -1
  109. package/packages/datadog-plugin-openai/src/realtime.js +144 -0
  110. package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
  111. package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
  112. package/packages/datadog-plugin-playwright/src/index.js +76 -9
  113. package/packages/datadog-plugin-postgres/src/index.js +167 -0
  114. package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
  115. package/packages/datadog-plugin-redis/src/index.js +15 -1
  116. package/packages/datadog-plugin-supabase/src/error.js +18 -0
  117. package/packages/datadog-plugin-supabase/src/index.js +21 -0
  118. package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
  119. package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
  120. package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
  121. package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
  122. package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
  123. package/packages/datadog-plugin-supabase/src/url.js +17 -0
  124. package/packages/datadog-plugin-vitest/src/index.js +10 -0
  125. package/packages/datadog-plugin-ws/src/util.js +0 -4
  126. package/packages/datadog-turbopack/index.js +0 -6
  127. package/packages/datadog-turbopack/src/loader.js +0 -16
  128. package/packages/datadog-webpack/src/loader.js +0 -1
  129. package/packages/dd-trace/src/aiguard/client.js +2 -3
  130. package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
  131. package/packages/dd-trace/src/aiguard/index.js +2 -2
  132. package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
  133. package/packages/dd-trace/src/aiguard/integrations/openai.js +81 -7
  134. package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
  135. package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
  136. package/packages/dd-trace/src/aiguard/messages/utils.js +0 -1
  137. package/packages/dd-trace/src/aiguard/redaction.js +0 -1
  138. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  139. package/packages/dd-trace/src/appsec/activation.js +1 -1
  140. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
  141. package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
  142. package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
  143. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
  144. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  145. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
  146. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
  147. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  148. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
  149. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
  150. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
  151. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
  152. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
  153. package/packages/dd-trace/src/appsec/index.js +2 -2
  154. package/packages/dd-trace/src/appsec/lambda.js +71 -2
  155. package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
  156. package/packages/dd-trace/src/appsec/remote_config.js +8 -6
  157. package/packages/dd-trace/src/appsec/reporter.js +10 -6
  158. package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
  159. package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
  160. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  161. package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
  162. package/packages/dd-trace/src/carrier.js +0 -5
  163. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
  164. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
  165. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
  166. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
  167. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
  168. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
  169. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
  170. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
  171. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
  172. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
  173. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
  174. package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
  175. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
  176. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
  177. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
  178. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
  179. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
  180. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
  181. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
  182. package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
  183. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
  184. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
  185. package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
  186. package/packages/dd-trace/src/config/defaults.js +3 -2
  187. package/packages/dd-trace/src/config/generated-config-types.d.ts +73 -67
  188. package/packages/dd-trace/src/config/helper.js +0 -1
  189. package/packages/dd-trace/src/config/index.js +24 -24
  190. package/packages/dd-trace/src/config/parsers.js +34 -6
  191. package/packages/dd-trace/src/config/remote_config.js +25 -109
  192. package/packages/dd-trace/src/config/supported-configurations.json +139 -10
  193. package/packages/dd-trace/src/datastreams/encoding.js +0 -1
  194. package/packages/dd-trace/src/datastreams/pathway.js +0 -1
  195. package/packages/dd-trace/src/debugger/constants.js +10 -0
  196. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +62 -10
  197. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  198. package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
  199. package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
  200. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
  201. package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
  202. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +21 -8
  203. package/packages/dd-trace/src/debugger/devtools_client/send.js +40 -14
  204. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
  205. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
  206. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
  207. package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -6
  208. package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
  209. package/packages/dd-trace/src/debugger/index.js +50 -2
  210. package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
  211. package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
  212. package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
  213. package/packages/dd-trace/src/dogstatsd.js +0 -23
  214. package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
  215. package/packages/dd-trace/src/encode/0.4.js +0 -7
  216. package/packages/dd-trace/src/encode/0.5.js +0 -2
  217. package/packages/dd-trace/src/encode/tags-processors.js +0 -1
  218. package/packages/dd-trace/src/evp_proxy/discovery.js +0 -1
  219. package/packages/dd-trace/src/evp_proxy/path.js +0 -2
  220. package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
  221. package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
  222. package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
  223. package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
  224. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
  225. package/packages/dd-trace/src/exporters/common/request.js +1 -0
  226. package/packages/dd-trace/src/exporters/common/url.js +0 -2
  227. package/packages/dd-trace/src/exporters/common/writer.js +0 -2
  228. package/packages/dd-trace/src/id.js +0 -11
  229. package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
  230. package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
  231. package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
  232. package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
  233. package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
  234. package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
  235. package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
  236. package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
  237. package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
  238. package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
  239. package/packages/dd-trace/src/llmobs/index.js +1 -3
  240. package/packages/dd-trace/src/llmobs/noop.js +10 -0
  241. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
  242. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
  243. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
  244. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
  245. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
  246. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
  247. package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
  248. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
  249. package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
  250. package/packages/dd-trace/src/llmobs/prompts/manager.js +639 -0
  251. package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
  252. package/packages/dd-trace/src/llmobs/prompts/prompt.js +92 -0
  253. package/packages/dd-trace/src/llmobs/sdk.js +21 -6
  254. package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
  255. package/packages/dd-trace/src/llmobs/tagger.js +30 -7
  256. package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
  257. package/packages/dd-trace/src/llmobs/util.js +0 -34
  258. package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
  259. package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
  260. package/packages/dd-trace/src/log/channels.js +3 -0
  261. package/packages/dd-trace/src/log/index.js +23 -5
  262. package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
  263. package/packages/dd-trace/src/msgpack/chunk.js +0 -1
  264. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
  265. package/packages/dd-trace/src/openfeature/encoding.js +0 -2
  266. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
  267. package/packages/dd-trace/src/openfeature/index.js +0 -4
  268. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
  269. package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
  270. package/packages/dd-trace/src/openfeature/writers/base.js +0 -6
  271. package/packages/dd-trace/src/openfeature/writers/exposures.js +0 -5
  272. package/packages/dd-trace/src/openfeature/writers/util.js +0 -4
  273. package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
  274. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
  275. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
  276. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
  277. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +0 -1
  278. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
  279. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
  280. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -14
  281. package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
  282. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +30 -13
  283. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
  284. package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
  285. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
  286. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
  287. package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
  288. package/packages/dd-trace/src/opentracing/span_context.js +0 -1
  289. package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
  290. package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
  291. package/packages/dd-trace/src/plugins/ci_plugin.js +0 -1
  292. package/packages/dd-trace/src/plugins/database.js +2 -6
  293. package/packages/dd-trace/src/plugins/index.js +7 -0
  294. package/packages/dd-trace/src/plugins/plugin.js +0 -4
  295. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  296. package/packages/dd-trace/src/plugins/util/git.js +1 -3
  297. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
  298. package/packages/dd-trace/src/plugins/util/llm.js +0 -2
  299. package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
  300. package/packages/dd-trace/src/plugins/util/test.js +21 -20
  301. package/packages/dd-trace/src/plugins/util/url.js +0 -5
  302. package/packages/dd-trace/src/priority_sampler.js +0 -6
  303. package/packages/dd-trace/src/process-tags/index.js +0 -1
  304. package/packages/dd-trace/src/profiler.js +132 -35
  305. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
  306. package/packages/dd-trace/src/profiling/profiler.js +101 -41
  307. package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
  308. package/packages/dd-trace/src/propagation-hash/index.js +0 -1
  309. package/packages/dd-trace/src/proxy.js +21 -45
  310. package/packages/dd-trace/src/random_sampler.js +0 -4
  311. package/packages/dd-trace/src/rate_limiter.js +0 -4
  312. package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
  313. package/packages/dd-trace/src/remote_config/index.js +0 -1
  314. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
  315. package/packages/dd-trace/src/sampler.js +0 -4
  316. package/packages/dd-trace/src/sampling_rule.js +0 -7
  317. package/packages/dd-trace/src/serverless/vercel.js +0 -1
  318. package/packages/dd-trace/src/serverless.js +0 -1
  319. package/packages/dd-trace/src/service-naming/index.js +0 -1
  320. package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
  321. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
  322. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
  323. package/packages/dd-trace/src/span_processor.js +2 -2
  324. package/packages/dd-trace/src/span_sampler.js +0 -1
  325. package/packages/dd-trace/src/standalone/product.js +2 -2
  326. package/packages/dd-trace/src/standalone/tracesource.js +0 -1
  327. package/packages/dd-trace/src/startup-log.js +1 -1
  328. package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
  329. package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
  330. package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
  331. package/packages/dd-trace/src/telemetry/metrics.js +0 -2
  332. package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
  333. package/packages/dd-trace/src/util.js +13 -1
  334. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
@@ -16,10 +16,15 @@ let testManagementTests = {}
16
16
  let isImpactedTestsEnabled = false
17
17
  let isModifiedTest = false
18
18
  let isTestIsolationEnabled = false
19
+ let isDynamicAtrEnabled = false
20
+ let isTextTerminal = false
19
21
  let hasWarnedMissingBeforeEachTaskResult = false
20
22
  let hasWarnedMissingBeforeEachRetryResult = false
21
23
  // Array of test names that have been retried and the reason
22
24
  const retryReasonsByTestName = new Map()
25
+ // Dynamic ATR computes the selected budget after the first attempt. Keep that result
26
+ // in browser state and apply it when Cypress starts the retry runnable.
27
+ const dynamicAtrRetryCountByTest = new Map()
23
28
  // Track test errors suppressed by test management so we can still report them to Datadog.
24
29
  const suppressedTestFailures = new Map()
25
30
 
@@ -93,7 +98,6 @@ function getTestProperties (testName) {
93
98
 
94
99
  /**
95
100
  * @param {string} message
96
- * @returns {void}
97
101
  */
98
102
  function warnMissingBeforeEachTaskResult (message) {
99
103
  // eslint-disable-next-line no-console
@@ -192,7 +196,6 @@ function setRumCorrelationCookie (traceId) {
192
196
 
193
197
  /**
194
198
  * @param {boolean} isCookieSet
195
- * @returns {void}
196
199
  */
197
200
  function restartRumSession (isCookieSet) {
198
201
  if (!isCookieSet || isTestIsolationEnabled || !originalWindow) {
@@ -362,20 +365,47 @@ Cypress.mocha.getRunner().runTests = function (suite, fn) {
362
365
  return oldRunTests.apply(this, [suite, fn])
363
366
  }
364
367
 
365
- Cypress.on('test:before:run', (attributes, test) => {
368
+ /**
369
+ * @param {{ id: string }} test
370
+ */
371
+ function getDynamicAtrTestKey (test) {
372
+ // Cypress preserves the runnable ID when cloning a retry, including across browser reloads.
373
+ return `${Cypress.mocha.getRootSuite().file}\0${test.id}`
374
+ }
375
+
376
+ /**
377
+ * @param {{ id: string, _retries: number }} test
378
+ */
379
+ function configureTestRetries (test) {
366
380
  if (shouldDisableFrameworkRetries(test)) {
367
381
  disableFrameworkRetries(test)
382
+ return
383
+ }
384
+
385
+ if (!isTextTerminal) return
386
+
387
+ const dynamicAtrRetryCount = dynamicAtrRetryCountByTest.get(getDynamicAtrTestKey(test))
388
+ if (Number.isSafeInteger(dynamicAtrRetryCount)) {
389
+ test._retries = dynamicAtrRetryCount
390
+ } else if (isDynamicAtrEnabled) {
391
+ // Cypress forbids calling retries(count) on the original runnable.
392
+ // Ensure local retries: 0 overrides still reach the duration-based budget selection.
393
+ test._retries = Math.max(1, test._retries)
368
394
  }
395
+ }
396
+
397
+ Cypress.on('test:before:run', (attributes, test) => {
398
+ configureTestRetries(test)
369
399
  })
370
400
 
371
401
  Cypress.on('test:before:run:async', (attributes, test) => {
372
- if (shouldDisableFrameworkRetries(test)) {
373
- disableFrameworkRetries(test)
374
- }
402
+ configureTestRetries(test)
375
403
  })
376
404
 
377
405
  beforeEach(function () {
378
406
  const currentTest = Cypress.mocha.getRunner().suite.ctx.currentTest
407
+ // The first test:before:run event can precede the suite configuration task.
408
+ configureTestRetries(currentTest)
379
409
  const testName = currentTest.fullTitle()
380
410
 
381
411
  const retryMessage = retryReasonsByTestName.get(testName)
@@ -427,6 +457,7 @@ before(function () {
427
457
  cy.task('dd:testSuiteStart', {
428
458
  testSuite: Cypress.mocha.getRootSuite().file,
429
459
  testSuiteAbsolutePath: Cypress.spec && Cypress.spec.absolute,
460
+ isTextTerminal: Cypress.config('isTextTerminal'),
430
461
  }).then((suiteConfig) => {
431
462
  if (suiteConfig) {
432
463
  isEarlyFlakeDetectionEnabled = suiteConfig.isEarlyFlakeDetectionEnabled
@@ -439,6 +470,12 @@ before(function () {
439
470
  isImpactedTestsEnabled = suiteConfig.isImpactedTestsEnabled
440
471
  isModifiedTest = suiteConfig.isModifiedTest
441
472
  isTestIsolationEnabled = suiteConfig.isTestIsolationEnabled
473
+ isDynamicAtrEnabled = suiteConfig.isDynamicAtrEnabled
474
+ isTextTerminal = suiteConfig.isTextTerminal
475
+ if (isDynamicAtrEnabled && isTextTerminal) {
476
+ // The first test event can precede this task, and an earlier user hook can skip our beforeEach.
477
+ Cypress.mocha.getRootSuite().eachTest(configureTestRetries)
478
+ }
442
479
  rumTestExecutionIdCookieName = suiteConfig.rumTestExecutionIdCookieName
443
480
  if (Number.isFinite(suiteConfig.rumFlushWaitMillis)) {
444
481
  rumFlushWaitMillis = suiteConfig.rumFlushWaitMillis
@@ -448,6 +485,7 @@ before(function () {
448
485
  })
449
486
 
450
487
  after(() => {
488
+ dynamicAtrRetryCountByTest.clear()
451
489
  try {
452
490
  if (safeGetRum(originalWindow)) {
453
491
  originalWindow.dispatchEvent(new Event('beforeunload'))
@@ -475,6 +513,7 @@ afterEach(function () {
475
513
  : currentTest.err
476
514
 
477
515
  const testInfo = {
516
+ testId: currentTest.id,
478
517
  testName,
479
518
  testItTitle: currentTest.title,
480
519
  testSuite: Cypress.mocha.getRootSuite().file,
@@ -522,5 +561,11 @@ afterEach(function () {
522
561
  suppressedTestFailures.delete(testName)
523
562
  }
524
563
 
525
- cy.task('dd:afterEach', { test: testInfo, coverage, commands: commandsToReport })
564
+ cy.task('dd:afterEach', { test: testInfo, coverage, commands: commandsToReport }).then((taskResult) => {
565
+ // Preserve the first-attempt result until Cypress starts the retry runnable.
566
+ // Changing the completed test here is too late for Cypress's retry lifecycle.
567
+ if (taskResult && Number.isSafeInteger(taskResult.dynamicAtrRetryCount)) {
568
+ dynamicAtrRetryCountByTest.set(getDynamicAtrTestKey(currentTest), taskResult.dynamicAtrRetryCount)
569
+ }
570
+ })
526
571
  })
@@ -62,7 +62,7 @@ class GraphQLToolsResolveErrorPlugin extends TracingPlugin {
62
62
  */
63
63
  function recordResolveErrorForPath (error, path, fieldNodes) {
64
64
  const rootCtx = legacyStorage.getStore()?.graphqlRootCtx
65
- if (!rootCtx?.config.collapse || !rootCtx.fields) return
65
+ if (!rootCtx?.config?.collapse || !rootCtx.fields) return
66
66
 
67
67
  const field = findResolveField(rootCtx.fields, getPathString(path), fieldNodes?.[0])
68
68
  if (field) recordResolveError(field, error)
@@ -70,7 +70,6 @@ function recordResolveErrorForPath (error, path, fieldNodes) {
70
70
 
71
71
  /**
72
72
  * @param {(string | number)[]} path
73
- * @returns {string}
74
73
  */
75
74
  function getPathString (path) {
76
75
  let pathString = ''
@@ -54,7 +54,6 @@ function getRequestCache (owner, configuredLimit) {
54
54
  /**
55
55
  * @param {string | null | undefined} operationName
56
56
  * @param {boolean} calculateSignature
57
- * @returns {string}
58
57
  */
59
58
  function operationCacheKey (operationName, calculateSignature) {
60
59
  return `${calculateSignature === false ? 0 : 1}\n${operationName ?? ''}`
@@ -309,7 +308,6 @@ const HEALTH_CHECK_QUERY = 'query __ApolloServiceHealthCheck__ { __typename }'
309
308
  * Matches the raw query string before it is parsed (the only input parse has).
310
309
  *
311
310
  * @param {unknown} source Raw query string or a graphql `Source` body.
312
- * @returns {boolean}
313
311
  */
314
312
  function isApolloHealthCheckSource (source) {
315
313
  return source === HEALTH_CHECK_QUERY
@@ -319,7 +317,6 @@ function isApolloHealthCheckSource (source) {
319
317
  * Matches Apollo's parsed health-check operation exactly for cached documents.
320
318
  *
321
319
  * @param {import('graphql').OperationDefinitionNode | undefined} operation
322
- * @returns {boolean}
323
320
  */
324
321
  function isApolloHealthCheck (operation) {
325
322
  const selections = operation?.selectionSet?.selections
@@ -342,7 +339,6 @@ function isApolloHealthCheck (operation) {
342
339
 
343
340
  /**
344
341
  * @param {import('graphql').GraphQLOutputType} type
345
- * @returns {string}
346
342
  */
347
343
  function getBaseTypeName (type) {
348
344
  let current = type
@@ -357,7 +353,6 @@ let tools
357
353
  * @param {string | undefined} operationName
358
354
  * @param {import('graphql').OperationTypeNode} operationType
359
355
  * @param {boolean} [calculate]
360
- * @returns {string}
361
356
  */
362
357
  function getSignature (document, operationName, operationType, calculate) {
363
358
  if (calculate !== false && tools !== false) {
@@ -41,6 +41,7 @@ const {
41
41
  TEST_HAS_FAILED_ALL_RETRIES,
42
42
  TEST_RETRY_REASON_TYPES,
43
43
  TEST_IS_MODIFIED,
44
+ setExpectedEmptyTestSessionTags,
44
45
  } = require('../../dd-trace/src/plugins/util/test')
45
46
  const { COMPONENT } = require('../../dd-trace/src/constants')
46
47
  const id = require('../../dd-trace/src/id')
@@ -116,12 +117,22 @@ class JestPlugin extends CiPlugin {
116
117
  isEarlyFlakeDetectionEnabled,
117
118
  isEarlyFlakeDetectionFaulty,
118
119
  isTestManagementTestsEnabled,
120
+ isExpectedEmptySession,
119
121
  onDone,
120
122
  }) => {
121
123
  const finishSession = () => {
122
124
  this.testSessionSpan.setTag(TEST_STATUS, status)
123
125
  this.testModuleSpan.setTag(TEST_STATUS, status)
124
126
 
127
+ if (isExpectedEmptySession) {
128
+ setExpectedEmptyTestSessionTags(
129
+ this.testSessionSpan,
130
+ this.testModuleSpan,
131
+ 'No tests were found',
132
+ 'zero_tests'
133
+ )
134
+ }
135
+
125
136
  if (error) {
126
137
  this.testSessionSpan.setTag('error', error)
127
138
  this.testModuleSpan.setTag('error', error)
@@ -204,6 +215,8 @@ class JestPlugin extends CiPlugin {
204
215
  config._ddIsTestManagementTestsEnabled = this.libraryConfig?.isTestManagementEnabled ?? false
205
216
  config._ddTestManagementAttemptToFixRetries = this.libraryConfig?.testManagementAttemptToFixRetries ?? 0
206
217
  config._ddFlakyTestRetriesCount = this.libraryConfig?.flakyTestRetriesCount
218
+ config._ddIsDynamicAtrEnabled = this.libraryConfig?.isDynamicAtrEnabled ?? false
219
+ config._ddDynamicAtrBuckets = this.libraryConfig?.dynamicAtrBuckets
207
220
  config._ddIsDiEnabled = this.libraryConfig?.isDiEnabled ?? false
208
221
  config._ddIsKnownTestsEnabled = this.libraryConfig?.isKnownTestsEnabled ?? false
209
222
  config._ddIsImpactedTestsEnabled = this.libraryConfig?.isImpactedTestsEnabled ?? false
@@ -58,7 +58,6 @@ class KafkajsProducerPlugin extends ProducerPlugin {
58
58
  /**
59
59
  *
60
60
  * @param {{ result: ProducerResponseItem[] }} ctx
61
- * @returns {void}
62
61
  */
63
62
  commit (ctx) {
64
63
  const commitList = ctx.result
@@ -12,6 +12,9 @@ const {
12
12
  getEfdRetryCountForDuration,
13
13
  hasEfdRetries,
14
14
  } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
15
+ const {
16
+ getDynamicAtrRetryCount,
17
+ } = require('../../dd-trace/src/ci-visibility/dynamic-atr-retries')
15
18
  const {
16
19
  SCREENSHOT_UPLOAD_RESULT_ERROR,
17
20
  SCREENSHOT_UPLOAD_RESULT_UPLOADED,
@@ -65,6 +68,7 @@ const {
65
68
  TEST_BROWSER_NAME,
66
69
  TEST_BROWSER_VERSION,
67
70
  TEST_IS_RUM_ACTIVE,
71
+ setExpectedEmptyTestSessionTags,
68
72
  } = require('../../dd-trace/src/plugins/util/test')
69
73
  const { COMPONENT } = require('../../dd-trace/src/constants')
70
74
  const {
@@ -184,7 +188,6 @@ function setWebdriverioRumTestCorrelation (context, activeSpan) {
184
188
  * Converts a screenshot capture failure into its upload result.
185
189
  *
186
190
  * @param {unknown} error
187
- * @returns {string}
188
191
  */
189
192
  function handleWebdriverioScreenshotError (error) {
190
193
  log.error('Error capturing WebdriverIO failure screenshot: %s', error?.message || String(error))
@@ -882,6 +885,7 @@ class MochaPlugin extends CiPlugin {
882
885
  isTestManagementEnabled,
883
886
  isParallel,
884
887
  isFrameworkError,
888
+ isExpectedEmptySession,
885
889
  onDone,
886
890
  }) => {
887
891
  this._exportPendingWorkerTraces()
@@ -894,6 +898,15 @@ class MochaPlugin extends CiPlugin {
894
898
  this.testSessionSpan.setTag(TEST_STATUS, status)
895
899
  this.testModuleSpan.setTag(TEST_STATUS, status)
896
900
 
901
+ if (isExpectedEmptySession) {
902
+ setExpectedEmptyTestSessionTags(
903
+ this.testSessionSpan,
904
+ this.testModuleSpan,
905
+ 'No tests were executed',
906
+ 'zero_tests'
907
+ )
908
+ }
909
+
897
910
  if (error) {
898
911
  this.testSessionSpan.setTag('error', error)
899
912
  this.testModuleSpan.setTag('error', error)
@@ -1027,7 +1040,17 @@ class MochaPlugin extends CiPlugin {
1027
1040
  } else if (isEarlyFlakeDetection) {
1028
1041
  retryCount = this.libraryConfig.earlyFlakeDetectionRetryPolicy.schedulingRetryCount
1029
1042
  } else if (isAtr) {
1030
- retryCount = this.libraryConfig.flakyTestRetriesCount
1043
+ // When dynamic ATR is enabled, use the max bucket value as the initial count.
1044
+ // The actual duration-based count is computed after the first attempt.
1045
+ if (this.libraryConfig.isDynamicAtrEnabled) {
1046
+ const maximumDynamicAtrRetries = this.libraryConfig.dynamicAtrBuckets
1047
+ ? Math.max(...this.libraryConfig.dynamicAtrBuckets)
1048
+ : this.libraryConfig.earlyFlakeDetectionRetryPolicy.schedulingRetryCount
1049
+ // Dynamic ATR guarantees one retry, including the >5m EFD fallback bucket.
1050
+ retryCount = Math.max(1, maximumDynamicAtrRetries)
1051
+ } else {
1052
+ retryCount = this.libraryConfig.flakyTestRetriesCount
1053
+ }
1031
1054
  }
1032
1055
 
1033
1056
  const test = {
@@ -1041,6 +1064,7 @@ class MochaPlugin extends CiPlugin {
1041
1064
  isAttemptToFix,
1042
1065
  isAtr,
1043
1066
  isDisabled,
1067
+ isDynamicAtr: isAtr && this.libraryConfig?.isDynamicAtrEnabled,
1044
1068
  isEarlyFlakeDetection,
1045
1069
  isModified,
1046
1070
  isNew,
@@ -1090,7 +1114,6 @@ class MochaPlugin extends CiPlugin {
1090
1114
  *
1091
1115
  * @param {object} test
1092
1116
  * @param {object|undefined} parentStore
1093
- * @returns {void}
1094
1117
  */
1095
1118
  #startWebdriverioJasmineAttempt (test, parentStore) {
1096
1119
  test.attemptStart = performance.now()
@@ -1121,7 +1144,6 @@ class MochaPlugin extends CiPlugin {
1121
1144
  * Delays Jasmine's parent runner until every Datadog-managed spec execution has completed.
1122
1145
  *
1123
1146
  * @param {object} context
1124
- * @returns {void}
1125
1147
  */
1126
1148
  #configureWebdriverioJasmineLifecycle (context) {
1127
1149
  const isLegacyJasmine = Boolean(context.self?.queueableFn)
@@ -1215,6 +1237,19 @@ class MochaPlugin extends CiPlugin {
1215
1237
  }
1216
1238
  }
1217
1239
 
1240
+ // Dynamic ATR: after the first attempt, compute the duration-based retry budget.
1241
+ if (
1242
+ testStatus !== 'skip' &&
1243
+ test.isDynamicAtr &&
1244
+ test.attempt === 0
1245
+ ) {
1246
+ test.retryCount = getDynamicAtrRetryCount(
1247
+ performance.now() - test.attemptStart,
1248
+ this.libraryConfig.earlyFlakeDetectionRetryPolicy,
1249
+ this.libraryConfig.dynamicAtrBuckets
1250
+ )
1251
+ }
1252
+
1218
1253
  const hasManagedRetry = testStatus !== 'skip' && test.attempt < test.retryCount
1219
1254
  test.willRetry = hasManagedRetry && (
1220
1255
  test.isAttemptToFix ||
@@ -1250,7 +1285,6 @@ class MochaPlugin extends CiPlugin {
1250
1285
  *
1251
1286
  * @param {object} test
1252
1287
  * @param {WebdriverioJasmineResult} result
1253
- * @returns {void}
1254
1288
  */
1255
1289
  #finishWebdriverioJasmineRetry (test, result) {
1256
1290
  const status = getJasmineStatus(test.reportedStatus || result.status)
@@ -1290,7 +1324,6 @@ class MochaPlugin extends CiPlugin {
1290
1324
  * Advances a Jasmine test and starts its next attempt span.
1291
1325
  *
1292
1326
  * @param {object} test
1293
- * @returns {void}
1294
1327
  */
1295
1328
  #startNextWebdriverioJasmineAttempt (test) {
1296
1329
  test.attempt++
@@ -1404,7 +1437,6 @@ class MochaPlugin extends CiPlugin {
1404
1437
  *
1405
1438
  * @param {object} test
1406
1439
  * @param {WebdriverioJasmineResult} result
1407
- * @returns {void}
1408
1440
  */
1409
1441
  #completeWebdriverioJasmineTest (test, result) {
1410
1442
  const state = this._webdriverioJasmineState
@@ -1460,7 +1492,6 @@ class MochaPlugin extends CiPlugin {
1460
1492
  *
1461
1493
  * @param {object} span - Failed test span
1462
1494
  * @param {() => void} [onDone] - Called after the screenshot upload finishes
1463
- * @returns {boolean} Whether a screenshot upload exists for the span
1464
1495
  */
1465
1496
  #startWebdriverioScreenshotUpload (span, onDone) {
1466
1497
  if (
@@ -1547,7 +1578,6 @@ class MochaPlugin extends CiPlugin {
1547
1578
  * @param {object} span - Failed test span
1548
1579
  * @param {{callbacks: Array<() => void>, finished: boolean}} upload - Upload state
1549
1580
  * @param {string} result - Aggregate screenshot upload result
1550
- * @returns {void}
1551
1581
  */
1552
1582
  #finishWebdriverioScreenshotUpload (span, upload, result) {
1553
1583
  if (upload.finished) return
@@ -1577,7 +1607,6 @@ class MochaPlugin extends CiPlugin {
1577
1607
  * @param {object} span - Failed test span
1578
1608
  * @param {string|string[]} screenshots - Base64-encoded PNG data
1579
1609
  * @param {(result: string) => void} onDone - Aggregate upload completion callback
1580
- * @returns {void}
1581
1610
  */
1582
1611
  #uploadWebdriverioScreenshots (span, screenshots, onDone) {
1583
1612
  const screenshotList = Array.isArray(screenshots) ? screenshots : [screenshots]
@@ -1647,7 +1676,6 @@ class MochaPlugin extends CiPlugin {
1647
1676
  * resolveCallback?: (onDone: () => void) => void,
1648
1677
  * rejectCallback?: (onDone: () => void) => void
1649
1678
  * }} context
1650
- * @returns {void}
1651
1679
  */
1652
1680
  #finishWebdriverioJasmineWorker (context) {
1653
1681
  const state = this._webdriverioJasmineState
@@ -206,7 +206,6 @@ const REDACT_LEAF = '"?"'
206
206
 
207
207
  /**
208
208
  * @param {RegExp} value
209
- * @returns {string}
210
209
  */
211
210
  function stringifyRegExp (value) {
212
211
  return `{"$regex":${JSON.stringify(value.source)},"$options":${JSON.stringify(value.flags)}}`
@@ -2,15 +2,30 @@
2
2
 
3
3
  const CompositePlugin = require('../../dd-trace/src/plugins/composite')
4
4
  const OpenAiLLMObsPlugin = require('../../dd-trace/src/llmobs/plugins/openai')
5
+ const OpenAiRealtimeLLMObsPlugins = require('../../dd-trace/src/llmobs/plugins/openai/realtime')
6
+ const OpenAiRealtimeTracingPlugins = require('./realtime')
5
7
  const OpenAiTracingPlugin = require('./tracing')
6
8
 
7
9
  class OpenAiPlugin extends CompositePlugin {
8
10
  static id = 'openai'
9
11
  static get plugins () {
10
- return {
12
+ const plugins = {
11
13
  llmobs: OpenAiLLMObsPlugin,
12
14
  tracing: OpenAiTracingPlugin,
13
15
  }
16
+
17
+ // LLM Obs plugins must be registered before their tracing counterparts so that annotations are
18
+ // added to the span before it finishes: subscribers run in registration order, and the realtime
19
+ // tracing plugins finish their span in `end`.
20
+ for (const Plugin of OpenAiRealtimeLLMObsPlugins) {
21
+ plugins[Plugin.id] = Plugin
22
+ }
23
+
24
+ for (const Plugin of OpenAiRealtimeTracingPlugins) {
25
+ plugins[Plugin.id] = Plugin
26
+ }
27
+
28
+ return plugins
14
29
  }
15
30
  }
16
31
 
@@ -0,0 +1,144 @@
1
+ 'use strict'
2
+
3
+ const { MEASURED } = require('../../../ext/tags')
4
+ const { ERROR_MESSAGE, ERROR_TYPE } = require('../../dd-trace/src/constants')
5
+ const { storage } = require('../../datadog-core')
6
+ const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
7
+
8
+ /**
9
+ * APM spans for the phases of one OpenAI Realtime turn.
10
+ *
11
+ * The turn is replayed as a back-dated tree once it is complete, so every span here is created with
12
+ * an explicit `startTime` and finished with an explicit `finishTime` rather than measuring wall
13
+ * clock. Nesting falls out of the synchronous scoping of the instrumentation's `traceSync` calls:
14
+ * the phase spans are created inside the turn root's callback, so `startSpan` picks the root up as
15
+ * their parent from the active store.
16
+ */
17
+ class RealtimeTracingPlugin extends TracingPlugin {
18
+ // `component` defaults to the plugin id, which differs per phase here, so pin both explicitly to
19
+ // keep `component:openai` consistent with every other span the integration emits.
20
+ static component = 'openai'
21
+ static system = 'openai'
22
+
23
+ /**
24
+ * Whether a failed response marks this span errored. True for the model's own work and for the
25
+ * turn as a whole; false for the speaking windows, which describe when audio moved rather than
26
+ * whether the model succeeded.
27
+ */
28
+ static flagsFailure = true
29
+
30
+ /**
31
+ * The APM resource name for this phase. Implemented by every subclass.
32
+ *
33
+ * @param {object} ctx
34
+ * @throws {Error} When a subclass has not implemented it.
35
+ */
36
+ resource (ctx) {
37
+ throw new Error(`resource must be implemented by ${this.constructor.name}`)
38
+ }
39
+
40
+ /**
41
+ * @param {object} ctx
42
+ * @returns {object}
43
+ */
44
+ bindStart (ctx) {
45
+ this.startSpan('openai.request', {
46
+ service: this.config.service,
47
+ resource: this.resource(ctx),
48
+ type: 'openai',
49
+ kind: 'client',
50
+ meta: {
51
+ [MEASURED]: 1,
52
+ 'openai.request.model': ctx.turn.model,
53
+ },
54
+ startTime: ctx.startTime,
55
+ }, ctx)
56
+
57
+ return ctx.currentStore
58
+ }
59
+
60
+ /**
61
+ * @param {object} ctx
62
+ */
63
+ end (ctx) {
64
+ const span = ctx.currentStore?.span
65
+ if (span === undefined) return
66
+
67
+ if (ctx.turn.failed && this.constructor.flagsFailure) {
68
+ span.setTag('error', 1)
69
+
70
+ // The provider's own account of the failure, when `response.done` carried one. Without it the
71
+ // span says only that a realtime call broke. The LLM Observability error event reads these
72
+ // same tags, so setting them here serves both.
73
+ const { error } = ctx.turn
74
+ if (error !== undefined) {
75
+ if (error.type !== undefined) span.setTag(ERROR_TYPE, error.type)
76
+ const message = error.message ?? error.code
77
+ if (message !== undefined) span.setTag(ERROR_MESSAGE, message)
78
+ }
79
+ }
80
+ span.finish(ctx.finishTime)
81
+ }
82
+ }
83
+
84
+ /** The whole perceived turn, and the root of this turn's trace. */
85
+ class RealtimeTurnTracingPlugin extends RealtimeTracingPlugin {
86
+ static id = 'openai_realtime_turn'
87
+ static operation = 'turn'
88
+ static prefix = 'tracing:apm:openai:realtime:turn'
89
+
90
+ constructor (...args) {
91
+ super(...args)
92
+
93
+ // Captured at `response.created`, replayed at finalize: by then the active context belongs to
94
+ // the WebSocket message handler, not to the caller who opened the connection. The LLM
95
+ // Observability plugin composes its own store on top of whatever this sets.
96
+ this.addSub('dd-trace:openai:realtime:capture-context', turn => {
97
+ const store = storage('legacy').getStore()
98
+ const previous = turn.runInContext
99
+ turn.runInContext = previous === undefined
100
+ ? fn => storage('legacy').run(store, fn)
101
+ : fn => previous(() => storage('legacy').run(store, fn))
102
+ })
103
+ }
104
+
105
+ resource () {
106
+ return 'createRealtimeTurn'
107
+ }
108
+ }
109
+
110
+ /** The model's generation work: opens at the end of user speech, closes at `response.done`. */
111
+ class RealtimeResponseTracingPlugin extends RealtimeTracingPlugin {
112
+ static id = 'openai_realtime_response'
113
+ static operation = 'response'
114
+ static prefix = 'tracing:apm:openai:realtime:response'
115
+
116
+ resource () {
117
+ return 'createRealtimeResponse'
118
+ }
119
+ }
120
+
121
+ /**
122
+ * A speaking window — the human's or the agent's. One plugin covers both: they differ only by
123
+ * resource and name, which is data, not a type.
124
+ */
125
+ class RealtimeSpeechTracingPlugin extends RealtimeTracingPlugin {
126
+ static id = 'openai_realtime_speech'
127
+ static operation = 'speech'
128
+ static prefix = 'tracing:apm:openai:realtime:speech'
129
+ // A speaking window happened regardless of whether the model's response failed.
130
+ static flagsFailure = false
131
+
132
+ /**
133
+ * @param {{ phase: { operation: string } }} ctx
134
+ */
135
+ resource (ctx) {
136
+ return ctx.phase.operation
137
+ }
138
+ }
139
+
140
+ module.exports = [
141
+ RealtimeTurnTracingPlugin,
142
+ RealtimeResponseTracingPlugin,
143
+ RealtimeSpeechTracingPlugin,
144
+ ]
@@ -578,7 +578,6 @@ class OpenAIAgentsIntegration {
578
578
  *
579
579
  * @param {string | undefined | null} spanId agents-core spanId to start from
580
580
  * @param {string} ancestorId agents-core ancestor spanId
581
- * @returns {boolean}
582
581
  */
583
582
  #hasUntracedPathToAncestor (spanId, ancestorId) {
584
583
  let currentId = spanId
@@ -596,7 +595,6 @@ class OpenAIAgentsIntegration {
596
595
  * mistaken for top-level, or an error would finalize the workflow span early.
597
596
  *
598
597
  * @param {object} oaiSpan
599
- * @returns {boolean}
600
598
  */
601
599
  #isTopLevelSpan (oaiSpan) {
602
600
  let currentId = oaiSpan.parentId
@@ -681,7 +679,6 @@ class OpenAIAgentsIntegration {
681
679
  * Read the mutable tracer configuration so remote/runtime enablement is
682
680
  * reflected without reconstructing the plugin.
683
681
  *
684
- * @returns {boolean}
685
682
  */
686
683
  #isLLMObsEnabled () {
687
684
  return this.#llmobsEnabled && !!this.#config.llmobs?.DD_LLMOBS_ENABLED
@@ -690,7 +687,6 @@ class OpenAIAgentsIntegration {
690
687
  /**
691
688
  * Resolve model provider from the model invocation's async-local context.
692
689
  *
693
- * @returns {string}
694
690
  */
695
691
  #getCurrentModelProvider () {
696
692
  const baseURL = legacyStorage.getStore()?.[MODEL_BASE_URL_STORE_KEY]
@@ -14,7 +14,6 @@ const AGENTS_ERROR_TYPE = 'AgentsCoreError'
14
14
  * missing).
15
15
  *
16
16
  * @param {object} oaiSpan
17
- * @returns {string}
18
17
  */
19
18
  function deriveSpanName (oaiSpan) {
20
19
  const spanData = oaiSpan.spanData