dd-trace 6.13.0 → 6.14.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 (201) hide show
  1. package/LICENSE-3rdparty.csv +3 -1
  2. package/ci/init.js +8 -3
  3. package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
  4. package/ci/test-optimization-validation/ci-remediation.js +6 -6
  5. package/ci/test-optimization-validation/command-blocker.js +7 -5
  6. package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
  7. package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
  8. package/ci/test-optimization-validation/package-check.js +1 -1
  9. package/ci/test-optimization-validation/report-writer.js +7 -5
  10. package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
  11. package/ci/vitest-no-worker-init-setup.mjs +13 -13
  12. package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
  13. package/package.json +13 -10
  14. package/packages/datadog-esbuild/index.js +3 -1
  15. package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
  16. package/packages/datadog-instrumentations/src/fs.js +24 -20
  17. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
  18. package/packages/datadog-instrumentations/src/graphql.js +16 -16
  19. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
  20. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  21. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +265 -0
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +251 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +11 -1
  32. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
  33. package/packages/datadog-instrumentations/src/jest.js +25 -20
  34. package/packages/datadog-instrumentations/src/knex.js +76 -0
  35. package/packages/datadog-instrumentations/src/mariadb.js +6 -0
  36. package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
  37. package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
  38. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  39. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
  40. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
  41. package/packages/datadog-instrumentations/src/net.js +14 -17
  42. package/packages/datadog-instrumentations/src/next.js +212 -62
  43. package/packages/datadog-instrumentations/src/openai.js +42 -40
  44. package/packages/datadog-instrumentations/src/pg.js +15 -0
  45. package/packages/datadog-instrumentations/src/playwright.js +109 -13
  46. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
  47. package/packages/datadog-instrumentations/src/sequelize.js +94 -2
  48. package/packages/datadog-instrumentations/src/undici.js +53 -4
  49. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +37 -3
  50. package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
  51. package/packages/datadog-instrumentations/src/vitest-worker.js +71 -14
  52. package/packages/datadog-instrumentations/src/webdriverio.js +965 -6
  53. package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
  54. package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
  55. package/packages/datadog-plugin-amqp10/src/util.js +2 -1
  56. package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
  57. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
  58. package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
  59. package/packages/datadog-plugin-cucumber/src/index.js +0 -2
  60. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
  61. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
  62. package/packages/datadog-plugin-graphql/src/execute.js +998 -196
  63. package/packages/datadog-plugin-graphql/src/index.js +27 -7
  64. package/packages/datadog-plugin-graphql/src/jit.js +136 -0
  65. package/packages/datadog-plugin-graphql/src/request.js +18 -27
  66. package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
  67. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
  68. package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
  69. package/packages/datadog-plugin-graphql/src/utils.js +208 -120
  70. package/packages/datadog-plugin-graphql/src/validate.js +10 -23
  71. package/packages/datadog-plugin-jest/src/index.js +0 -6
  72. package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
  73. package/packages/datadog-plugin-mocha/src/index.js +403 -75
  74. package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
  75. package/packages/datadog-plugin-mysql/src/index.js +41 -15
  76. package/packages/datadog-plugin-net/src/tcp.js +3 -1
  77. package/packages/datadog-plugin-next/src/index.js +63 -29
  78. package/packages/datadog-plugin-playwright/src/index.js +167 -27
  79. package/packages/datadog-plugin-undici/src/index.js +27 -41
  80. package/packages/datadog-plugin-vitest/src/index.js +6 -12
  81. package/packages/dd-trace/src/aiguard/evaluation.js +2 -1
  82. package/packages/dd-trace/src/aiguard/messages/anthropic.js +8 -1
  83. package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
  84. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
  85. package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
  86. package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
  87. package/packages/dd-trace/src/appsec/graphql.js +6 -2
  88. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
  89. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
  90. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
  91. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
  92. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
  93. package/packages/dd-trace/src/appsec/lambda.js +44 -26
  94. package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
  95. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
  96. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
  97. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +5 -173
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
  100. package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
  101. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
  102. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +394 -225
  103. package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
  104. package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
  105. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
  106. package/packages/dd-trace/src/ci-visibility/final-flush.js +2 -1
  107. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
  108. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
  109. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
  110. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
  111. package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
  112. package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
  113. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
  114. package/packages/dd-trace/src/config/index.js +73 -13
  115. package/packages/dd-trace/src/config/parsers.js +11 -1
  116. package/packages/dd-trace/src/config/stable.js +3 -3
  117. package/packages/dd-trace/src/config/supported-configurations.json +20 -2
  118. package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
  119. package/packages/dd-trace/src/debugger/config.js +12 -1
  120. package/packages/dd-trace/src/debugger/constants.js +1 -0
  121. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
  122. package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
  123. package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -40
  124. package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
  125. package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
  126. package/packages/dd-trace/src/debugger/index.js +23 -3
  127. package/packages/dd-trace/src/dogstatsd.js +510 -76
  128. package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
  129. package/packages/dd-trace/src/encode/0.4.js +5 -5
  130. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
  131. package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
  132. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  133. package/packages/dd-trace/src/exporters/agent/writer.js +24 -7
  134. package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
  135. package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
  136. package/packages/dd-trace/src/exporters/common/agents.js +28 -6
  137. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
  138. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
  139. package/packages/dd-trace/src/exporters/common/request.js +31 -11
  140. package/packages/dd-trace/src/exporters/common/url.js +40 -1
  141. package/packages/dd-trace/src/exporters/common/writer.js +9 -7
  142. package/packages/dd-trace/src/flush.js +6 -3
  143. package/packages/dd-trace/src/id.js +14 -0
  144. package/packages/dd-trace/src/index.js +5 -2
  145. package/packages/dd-trace/src/llmobs/experiments/dataset.js +2 -1
  146. package/packages/dd-trace/src/llmobs/index.js +32 -32
  147. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
  148. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
  149. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
  150. package/packages/dd-trace/src/llmobs/util.js +0 -33
  151. package/packages/dd-trace/src/llmobs/writers/base.js +49 -32
  152. package/packages/dd-trace/src/log/index.js +7 -1
  153. package/packages/dd-trace/src/{ci-visibility/log-submission → log-submission}/log-submission-plugin.js +48 -19
  154. package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
  155. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  156. package/packages/dd-trace/src/opentelemetry/logs/index.js +5 -24
  157. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
  158. package/packages/dd-trace/src/opentelemetry/metrics/index.js +15 -22
  159. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +14 -4
  160. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +10 -0
  161. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
  162. package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
  163. package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
  164. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
  165. package/packages/dd-trace/src/opentracing/propagation/text_map.js +93 -18
  166. package/packages/dd-trace/src/payload-tagging/index.js +2 -1
  167. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
  168. package/packages/dd-trace/src/plugins/tracing.js +12 -10
  169. package/packages/dd-trace/src/plugins/util/ci.js +3 -1
  170. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
  171. package/packages/dd-trace/src/plugins/util/test.js +83 -20
  172. package/packages/dd-trace/src/plugins/util/url.js +2 -2
  173. package/packages/dd-trace/src/plugins/util/web.js +4 -9
  174. package/packages/dd-trace/src/profiling/config.js +1 -0
  175. package/packages/dd-trace/src/profiling/oom.js +7 -2
  176. package/packages/dd-trace/src/profiling/profiler.js +23 -13
  177. package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
  178. package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
  179. package/packages/dd-trace/src/proxy.js +75 -5
  180. package/packages/dd-trace/src/remote_config/index.js +319 -101
  181. package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
  182. package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
  183. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -1
  184. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -1
  185. package/packages/dd-trace/src/sampling_rule.js +36 -9
  186. package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +4 -8
  187. package/packages/dd-trace/src/serverless/vercel.js +53 -20
  188. package/packages/dd-trace/src/serverless.js +10 -3
  189. package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
  190. package/packages/dd-trace/src/span_stats.js +24 -28
  191. package/packages/dd-trace/src/startup-log.js +3 -2
  192. package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
  193. package/packages/dd-trace/src/telemetry/send-data.js +18 -16
  194. package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
  195. package/packages/dd-trace/src/tracer.js +4 -5
  196. package/packages/dd-trace/src/tracer_metadata.js +11 -3
  197. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  198. package/vendor/dist/protobufjs/index.js +1 -1
  199. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  200. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
  201. package/packages/dd-trace/src/encode/agentless-json.js +0 -210
@@ -45,10 +45,16 @@ function formatMetricTags (tagsDictionary) {
45
45
  return Object.keys(tagsDictionary).reduce((/** @type {string[]} */ acc, tagKey) => {
46
46
  if (tagKey === 'statusCode') {
47
47
  const statusCode = tagsDictionary[tagKey]
48
- if (isStatusCode400(statusCode)) {
49
- acc.push(`status_code:${statusCode}`)
48
+ if (statusCode) {
49
+ acc.push(`status_code:${statusCode}`, `error_type:${getErrorTypeFromStatusCode(statusCode)}`)
50
+ } else if (!tagsDictionary.errorType) {
51
+ acc.push('error_type:network')
50
52
  }
51
- acc.push(`error_type:${getErrorTypeFromStatusCode(statusCode)}`)
53
+ return acc
54
+ }
55
+ if (tagKey === 'errorType') {
56
+ const errorType = tagsDictionary[tagKey]
57
+ if (errorType) acc.push(`error_type:${errorType}`)
52
58
  return acc
53
59
  }
54
60
  const formattedTagKey = /** @type {string} */(formattedTags[tagKey] || tagKey)
@@ -129,11 +135,8 @@ const TELEMETRY_TEST_MANAGEMENT_TESTS_ERRORS = 'test_management_tests.request_er
129
135
  const TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_TESTS = 'test_management_tests.response_tests'
130
136
  const TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_BYTES = 'test_management_tests.response_bytes'
131
137
 
132
- function isStatusCode400 (statusCode) {
133
- return statusCode >= 400 && statusCode < 500
134
- }
135
-
136
138
  function getErrorTypeFromStatusCode (statusCode) {
139
+ if (typeof statusCode !== 'number') return 'network'
137
140
  if (statusCode >= 400 && statusCode < 500) {
138
141
  return 'status_code_4xx_response'
139
142
  }
@@ -0,0 +1,61 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ TEST_FAILURE_VIDEO_SCOPE,
5
+ TEST_FAILURE_VIDEO_UPLOADED,
6
+ TEST_FAILURE_VIDEO_UPLOAD_ERROR,
7
+ } = require('../plugins/util/test')
8
+
9
+ const VIDEO_UPLOAD_RESULT_UPLOADED = 'uploaded'
10
+ const VIDEO_UPLOAD_RESULT_ERROR = 'error'
11
+ const VIDEO_UPLOAD_SCOPE_TEST_SUITE = 'test_suite'
12
+
13
+ /**
14
+ * Combines video upload results, giving errors precedence over successes.
15
+ *
16
+ * @param {Array<string|undefined>} uploadResults - Per-video upload results
17
+ * @returns {string|undefined} Combined upload result
18
+ */
19
+ function getVideoUploadResult (uploadResults) {
20
+ let hasUploaded = false
21
+ for (const uploadResult of uploadResults) {
22
+ if (uploadResult === VIDEO_UPLOAD_RESULT_ERROR) return VIDEO_UPLOAD_RESULT_ERROR
23
+ if (uploadResult === VIDEO_UPLOAD_RESULT_UPLOADED) hasUploaded = true
24
+ }
25
+ return hasUploaded ? VIDEO_UPLOAD_RESULT_UPLOADED : undefined
26
+ }
27
+
28
+ /**
29
+ * Returns the tag that represents an aggregate video upload outcome.
30
+ *
31
+ * @param {string|undefined} uploadResult - Aggregate video upload result
32
+ * @returns {string|undefined} Video upload result tag
33
+ */
34
+ function getVideoUploadTag (uploadResult) {
35
+ if (uploadResult === VIDEO_UPLOAD_RESULT_ERROR) return TEST_FAILURE_VIDEO_UPLOAD_ERROR
36
+ if (uploadResult === VIDEO_UPLOAD_RESULT_UPLOADED) return TEST_FAILURE_VIDEO_UPLOADED
37
+ }
38
+
39
+ /**
40
+ * Tags a test or test suite span with its video upload outcome and optional scope.
41
+ *
42
+ * @param {object} span - Test or test suite span to tag
43
+ * @param {string|undefined} uploadResult - Aggregate video upload result
44
+ * @param {string} [scope] - Media lookup scope
45
+ * @returns {void}
46
+ */
47
+ function setVideoUploadTags (span, uploadResult, scope) {
48
+ const uploadTag = getVideoUploadTag(uploadResult)
49
+ if (!uploadTag) return
50
+ span.setTag(uploadTag, 'true')
51
+ if (scope) span.setTag(TEST_FAILURE_VIDEO_SCOPE, scope)
52
+ }
53
+
54
+ module.exports = {
55
+ VIDEO_UPLOAD_RESULT_ERROR,
56
+ VIDEO_UPLOAD_RESULT_UPLOADED,
57
+ VIDEO_UPLOAD_SCOPE_TEST_SUITE,
58
+ getVideoUploadResult,
59
+ getVideoUploadTag,
60
+ setVideoUploadTags,
61
+ }
@@ -65,6 +65,7 @@ export interface GeneratedConfig {
65
65
  };
66
66
  dbmPropagationMode: "disabled" | "service" | "full" | "dynamic_service";
67
67
  DD_ACTION_EXECUTION_ID: string | undefined;
68
+ DD_AGENTLESS_ENABLED: boolean;
68
69
  DD_AGENTLESS_LOG_SUBMISSION_ENABLED: boolean;
69
70
  DD_AGENTLESS_LOG_SUBMISSION_URL: string | undefined;
70
71
  DD_API_KEY: string | undefined;
@@ -581,6 +582,7 @@ export interface GeneratedConfig {
581
582
  DD_TEST_EARLY_FLAKE_DETECTION_RETRY_COUNT: number | undefined;
582
583
  DD_TEST_FAILED_TEST_REPLAY_ENABLED: boolean;
583
584
  DD_TEST_FAILURE_SCREENSHOTS_ENABLED: boolean | undefined;
585
+ DD_TEST_FAILURE_VIDEOS_ENABLED: boolean | undefined;
584
586
  DD_TEST_FLEET_CONFIG_PATH: string | undefined;
585
587
  DD_TEST_LOCAL_CONFIG_PATH: string | undefined;
586
588
  DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES: number;
@@ -610,6 +612,7 @@ export interface GeneratedEnvVarConfig {
610
612
  DATADOG_API_KEY: string | undefined;
611
613
  DD_ACTION_EXECUTION_ID: string | undefined;
612
614
  DD_AGENT_HOST: string;
615
+ DD_AGENTLESS_ENABLED: boolean;
613
616
  DD_AGENTLESS_LOG_SUBMISSION_ENABLED: boolean;
614
617
  DD_AGENTLESS_LOG_SUBMISSION_URL: string | undefined;
615
618
  DD_AI_GUARD_BLOCK: boolean;
@@ -827,6 +830,7 @@ export interface GeneratedEnvVarConfig {
827
830
  DD_TEST_EARLY_FLAKE_DETECTION_RETRY_COUNT: number | undefined;
828
831
  DD_TEST_FAILED_TEST_REPLAY_ENABLED: boolean;
829
832
  DD_TEST_FAILURE_SCREENSHOTS_ENABLED: boolean | undefined;
833
+ DD_TEST_FAILURE_VIDEOS_ENABLED: boolean | undefined;
830
834
  DD_TEST_FLEET_CONFIG_PATH: string | undefined;
831
835
  DD_TEST_LOCAL_CONFIG_PATH: string | undefined;
832
836
  DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES: number;
@@ -4,8 +4,10 @@ const fs = require('node:fs')
4
4
  const os = require('node:os')
5
5
  const { URL, format } = require('node:url')
6
6
 
7
+ const { channel } = require('dc-polyfill')
8
+
7
9
  const exporters = require('../../../../ext/exporters')
8
- const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
10
+ const createRfdc = require('../../../../vendor/dist/rfdc')
9
11
  const uuid = require('../../../../vendor/dist/crypto-randomuuid') // we need to keep the old uuid dep because of cypress
10
12
  const set = require('../../../datadog-core/src/utils/src/set')
11
13
  const { DD_MAJOR, NODE_MAJOR } = require('../../../../version')
@@ -42,7 +44,12 @@ const {
42
44
  const { normalizeService } = require('./normalize-service')
43
45
  const { programmaticTypeCoercions, transformers } = require('./parsers')
44
46
 
45
- const RUNTIME_ID = uuid()
47
+ const rfdc = createRfdc({
48
+ proto: false,
49
+ circles: false,
50
+ constructorHandlers: [[RegExp, transformers.toCamelCase]],
51
+ })
52
+
46
53
  const TEST_OPTIMIZATION_WORKER_EXPORTERS = new Set([
47
54
  exporters.CUCUMBER_WORKER,
48
55
  exporters.JEST_WORKER,
@@ -51,6 +58,21 @@ const TEST_OPTIMIZATION_WORKER_EXPORTERS = new Set([
51
58
  exporters.VITEST_WORKER,
52
59
  ])
53
60
 
61
+ let runtimeId
62
+
63
+ channel('datadog:identity:update').subscribe(refreshRuntimeId)
64
+
65
+ /**
66
+ * Lazily generates the process-wide runtime ID on first access instead of at module load,
67
+ * so modules that merely require this file without constructing a Config never pay for it.
68
+ *
69
+ * @returns {string}
70
+ */
71
+ function getRuntimeId () {
72
+ runtimeId ??= uuid()
73
+ return runtimeId
74
+ }
75
+
54
76
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
55
77
 
56
78
  /**
@@ -390,11 +412,6 @@ class Config extends ConfigBase {
390
412
  if (!trackedConfigOrigins.has('dogstatsd.hostname')) {
391
413
  setAndTrack(this, 'dogstatsd.hostname', agentHostname)
392
414
  }
393
- // Disable log injection when OTEL logs are enabled
394
- // OTEL logs and DD log injection are mutually exclusive
395
- if (this.DD_LOGS_OTEL_ENABLED) {
396
- setAndTrack(this, 'logInjection', false)
397
- }
398
415
  if (this.DD_METRICS_OTEL_ENABLED &&
399
416
  trackedConfigOrigins.has('OTEL_METRICS_EXPORTER') &&
400
417
  this.OTEL_METRICS_EXPORTER === 'none') {
@@ -476,6 +493,12 @@ class Config extends ConfigBase {
476
493
  setAndTrack(this, 'runtimeMetrics.enabled', false)
477
494
  }
478
495
 
496
+ const agentlessTracingEnabled = this.DD_AGENTLESS_ENABLED ||
497
+ isTrue(getEnvironmentVariable('_DD_APM_TRACING_AGENTLESS_ENABLED'))
498
+ if (agentlessTracingEnabled && !this.isCiVisibility) {
499
+ setAndTrack(this, 'OTEL_TRACES_EXPORTER', 'none')
500
+ }
501
+
479
502
  // Apply the OTel sampler when the user opted into OTel traces or explicitly set the sampler.
480
503
  // OTEL_TRACES_SAMPLER has `default: parentbased_always_on` (per OTel spec), so opt-in users
481
504
  // that don't set the sampler still get parent-based sampling. Electron exporter spans go over
@@ -602,7 +625,7 @@ class Config extends ConfigBase {
602
625
  if (this.version) {
603
626
  this.tags.version = this.version
604
627
  }
605
- this.tags['runtime-id'] = RUNTIME_ID
628
+ this.tags['runtime-id'] = getRuntimeId()
606
629
  const platformTags = getServerlessPlatformTags()
607
630
  if (platformTags) {
608
631
  for (let i = 0; i < platformTags.length; i += 2) {
@@ -622,11 +645,30 @@ class Config extends ConfigBase {
622
645
  setAndTrack(this, 'telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED', false)
623
646
  }
624
647
 
625
- // Experimental agentless APM span intake
626
- // When enabled, sends spans directly to Datadog intake without an agent
627
- // TODO: Replace this with a proper configuration
628
- const agentlessEnabled = isTrue(getEnvironmentVariable('_DD_APM_TRACING_AGENTLESS_ENABLED'))
629
- if (agentlessEnabled) {
648
+ if (this.DD_AGENTLESS_ENABLED) {
649
+ if (!trackedConfigOrigins.has('DD_AGENTLESS_LOG_SUBMISSION_ENABLED') && !this.DD_LOGS_OTEL_ENABLED) {
650
+ setAndTrack(this, 'DD_AGENTLESS_LOG_SUBMISSION_ENABLED', true)
651
+ }
652
+ setAndTrack(this, 'testOptimization.DD_CIVISIBILITY_AGENTLESS_ENABLED', true)
653
+ setAndTrack(this, 'llmobs.agentlessEnabled', true)
654
+ setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE', 'agentless')
655
+ if (this.DD_API_KEY === undefined) {
656
+ setAndTrack(this, 'dynamicInstrumentation.enabled', false)
657
+ }
658
+ setAndTrack(this, 'runtimeMetrics.enabled', false)
659
+ setAndTrack(this, 'dsmEnabled', false)
660
+ const profilingExporters = this.DD_PROFILING_EXPORTERS.filter(exporter => exporter !== 'agent')
661
+ setAndTrack(this, 'DD_PROFILING_EXPORTERS', profilingExporters)
662
+ if (profilingExporters.length === 0) {
663
+ setAndTrack(this, 'profiling.DD_PROFILING_ENABLED', 'false')
664
+ }
665
+ }
666
+
667
+ if (this.DD_AGENTLESS_LOG_SUBMISSION_ENABLED && this.DD_LOGS_OTEL_ENABLED) {
668
+ setAndTrack(this, 'DD_LOGS_OTEL_ENABLED', false)
669
+ }
670
+
671
+ if (agentlessTracingEnabled && !this.isCiVisibility) {
630
672
  setAndTrack(this, 'experimental.exporter', 'agentless')
631
673
  // Disable client-side stats computation
632
674
  setAndTrack(this, 'stats.DD_TRACE_STATS_COMPUTATION_ENABLED', false)
@@ -642,6 +684,12 @@ class Config extends ConfigBase {
642
684
  }
643
685
  }
644
686
 
687
+ // Disable log injection when OTEL logs are enabled
688
+ // OTEL logs and DD log injection are mutually exclusive
689
+ if (this.DD_LOGS_OTEL_ENABLED) {
690
+ setAndTrack(this, 'logInjection', false)
691
+ }
692
+
645
693
  // Apply all fallbacks to the calculated config.
646
694
  for (const [configName, alias] of fallbackConfigurations) {
647
695
  if (!trackedConfigOrigins.has(configName) && trackedConfigOrigins.has(alias)) {
@@ -788,3 +836,15 @@ function getConfig (options) {
788
836
  }
789
837
  return configInstance
790
838
  }
839
+
840
+ /**
841
+ * Regenerates the runtime ID.
842
+ *
843
+ * Used for Lambda MicroVM `/run` lifecycle hooks, giving each clone a distinct runtime identity.
844
+ *
845
+ * @param {import('./config-base')} config
846
+ */
847
+ function refreshRuntimeId (config) {
848
+ runtimeId = uuid()
849
+ config.tags['runtime-id'] = runtimeId
850
+ }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const fs = require('fs')
4
+ const { isRegExp } = require('node:util').types
4
5
 
5
6
  const { DD_MAJOR, NODE_MAJOR } = require('../../../../version')
6
7
  const tagger = require('../tagger')
@@ -72,6 +73,9 @@ const transformers = {
72
73
  toUpperCase (value) {
73
74
  return toCase(value, 'toUpperCase')
74
75
  },
76
+ /**
77
+ * @param {unknown} value
78
+ */
75
79
  toCamelCase (value) {
76
80
  if (Array.isArray(value)) {
77
81
  return value.map(item => {
@@ -79,6 +83,10 @@ const transformers = {
79
83
  })
80
84
  }
81
85
  if (typeof value === 'object' && value !== null) {
86
+ // RegExp matchers are supported configuration leaves and need their own clone.
87
+ if (isRegExp(value)) {
88
+ return new RegExp(value)
89
+ }
82
90
  const result = {}
83
91
  for (const [key, innerValue] of Object.entries(value)) {
84
92
  const camelCaseKey = key.replaceAll(/_(\w)/g, (_, letter) => letter.toUpperCase())
@@ -90,8 +98,10 @@ const transformers = {
90
98
  },
91
99
  parseOtelTags (object) {
92
100
  const tags = {}
101
+ const environment = object['deployment.environment.name'] ?? object['deployment.environment']
93
102
  for (const [key, value] of Object.entries(object)) {
94
- tags[RENAMED_OTEL_TAGS.get(key) ?? key] = value
103
+ const renamedKey = RENAMED_OTEL_TAGS.get(key)
104
+ tags[renamedKey ?? key] = renamedKey === 'env' ? environment : value
95
105
  }
96
106
  return tags
97
107
  },
@@ -22,16 +22,16 @@ class StableConfig {
22
22
 
23
23
  // Note: we don't enforce loading because there may be cases where the library is not available and we
24
24
  // want to avoid breaking the application. In those cases, we will not have the file-based configuration.
25
- let libdatadog
25
+ let libdatadogExtras
26
26
  try {
27
- libdatadog = require('@datadog/libdatadog')
27
+ libdatadogExtras = require('@datadog/libdatadog-extras')
28
28
  this.wasm_loaded = true
29
29
  } catch {
30
30
  this.warnings.push('Can\'t load libdatadog library')
31
31
  return
32
32
  }
33
33
 
34
- const libconfig = libdatadog.maybeLoad('library_config')
34
+ const libconfig = libdatadogExtras.maybeLoad('library_config')
35
35
  if (libconfig === undefined) {
36
36
  this.warnings.push('Can\'t load library_config library')
37
37
  return
@@ -8,18 +8,28 @@
8
8
  "default": null
9
9
  }
10
10
  ],
11
+ "DD_AGENTLESS_ENABLED": [
12
+ {
13
+ "implementation": "A",
14
+ "type": "boolean",
15
+ "default": "false",
16
+ "description": "Enable agentless mode for supported features and disable Agent-only features."
17
+ }
18
+ ],
11
19
  "DD_AGENTLESS_LOG_SUBMISSION_ENABLED": [
12
20
  {
13
21
  "implementation": "A",
14
22
  "type": "boolean",
15
- "default": "false"
23
+ "default": "false",
24
+ "description": "Submit supported logger output directly to the Datadog logs intake."
16
25
  }
17
26
  ],
18
27
  "DD_AGENTLESS_LOG_SUBMISSION_URL": [
19
28
  {
20
29
  "implementation": "A",
21
30
  "type": "string",
22
- "default": null
31
+ "default": null,
32
+ "description": "Override the automatic log submission intake URL."
23
33
  }
24
34
  ],
25
35
  "_DD_APM_TRACING_AGENTLESS_ENABLED": [
@@ -1929,6 +1939,14 @@
1929
1939
  "namespace": "testOptimization"
1930
1940
  }
1931
1941
  ],
1942
+ "DD_TEST_FAILURE_VIDEOS_ENABLED": [
1943
+ {
1944
+ "implementation": "A",
1945
+ "type": "boolean",
1946
+ "default": null,
1947
+ "namespace": "testOptimization"
1948
+ }
1949
+ ],
1932
1950
  "DD_TEST_FLEET_CONFIG_PATH": [
1933
1951
  {
1934
1952
  "implementation": "A",
@@ -3,12 +3,61 @@
3
3
  const { EOL, platform } = require('node:os')
4
4
 
5
5
  // Load binding first to not import other modules if it throws
6
- const libdatadog = require('@datadog/libdatadog')
7
- const binding = libdatadog.load('crashtracker')
6
+ const libdatadogExtras = require('@datadog/libdatadog-extras')
7
+ const binding = libdatadogExtras.load('crashtracker')
8
8
 
9
+ const { channel } = require('dc-polyfill')
10
+ const { getEnvironmentVariable } = require('../config/helper')
9
11
  const log = require('../log')
10
12
  const pkg = require('../../../../package.json')
11
13
  const processTags = require('../process-tags')
14
+ const getAgentlessTelemetryUrl = require('../telemetry/agentless-url')
15
+
16
+ const identityRefreshChannel = channel('datadog:identity:refresh')
17
+ const INHERITED_RECEIVER_ENVIRONMENT_VARIABLES = [
18
+ 'HTTP_PROXY',
19
+ 'HTTPS_PROXY',
20
+ 'NO_PROXY',
21
+ 'http_proxy',
22
+ 'https_proxy',
23
+ 'no_proxy',
24
+ 'SSL_CERT_FILE',
25
+ 'SSL_CERT_DIR',
26
+ ]
27
+
28
+ /**
29
+ * Builds the minimal receiver environment libdatadog needs to select its two direct crash
30
+ * destinations independently: instrumentation telemetry and Errors Tracking intake.
31
+ *
32
+ * @param {import('../config/config-base')} config - Tracer configuration
33
+ * @returns {Array<[string, string]>}
34
+ */
35
+ function getAgentlessReceiverEnvironment (config) {
36
+ if (!config.DD_API_KEY) {
37
+ throw new Error('DD_API_KEY is required for agentless crash tracking')
38
+ }
39
+
40
+ const site = config.site.toLowerCase()
41
+ const telemetryUrl = getAgentlessTelemetryUrl(site).origin
42
+
43
+ const environment = /** @type {Array<[string, string]>} */ ([
44
+ ['_DD_DIRECT_SUBMISSION_ENABLED', 'true'],
45
+ ['DD_API_KEY', config.DD_API_KEY],
46
+ ['DD_SITE', site],
47
+ ['DD_APM_TELEMETRY_DD_URL', telemetryUrl],
48
+ // libdatadog v43 parses the dedicated URL above but does not use it when constructing the
49
+ // endpoint. Keep this compatibility fallback until its telemetry config honors that setting.
50
+ ['DD_TRACE_AGENT_URL', telemetryUrl],
51
+ ])
52
+
53
+ // The receiver environment does not inherit from this process.
54
+ for (const name of INHERITED_RECEIVER_ENVIRONMENT_VARIABLES) {
55
+ const value = getEnvironmentVariable(name)
56
+ if (value) environment.push([name, value])
57
+ }
58
+
59
+ return environment
60
+ }
12
61
 
13
62
  class Crashtracker {
14
63
  #started = false
@@ -33,11 +82,12 @@ class Crashtracker {
33
82
  try {
34
83
  binding.init(
35
84
  this.#getConfig(config),
36
- this.#getReceiverConfig(),
85
+ this.#getReceiverConfig(config),
37
86
  this.#getMetadata(config)
38
87
  )
39
88
  this.#started = true
40
89
  this.#trackUnhandledExceptions()
90
+ identityRefreshChannel.subscribe((config) => this.configure(config))
41
91
  } catch (e) {
42
92
  log.error('Error initializing crashtracker', e)
43
93
  }
@@ -67,7 +117,21 @@ class Crashtracker {
67
117
  * @param {import('../config/config-base')} config - Tracer configuration
68
118
  */
69
119
  #getConfig (config) {
70
- const url = config.url
120
+ let endpoint = null
121
+ if (!config.DD_AGENTLESS_ENABLED) {
122
+ const url = config.url
123
+ endpoint = {
124
+ // TODO: Use the string directly when deserialization is fixed.
125
+ url: {
126
+ scheme: url.protocol.slice(0, -1),
127
+ authority: url.protocol === 'unix:'
128
+ ? Buffer.from(url.pathname).toString('hex')
129
+ : url.host,
130
+ path_and_query: '',
131
+ },
132
+ timeout_ms: 3000,
133
+ }
134
+ }
71
135
 
72
136
  // Out-of-process symbolication currently works on
73
137
  // Linux only, does not work on Mac.
@@ -80,17 +144,7 @@ class Crashtracker {
80
144
  collect_all_threads: true,
81
145
  create_alt_stack: true,
82
146
  use_alt_stack: true,
83
- endpoint: {
84
- // TODO: Use the string directly when deserialization is fixed.
85
- url: {
86
- scheme: url.protocol.slice(0, -1),
87
- authority: url.protocol === 'unix:'
88
- ? Buffer.from(url.pathname).toString('hex')
89
- : url.host,
90
- path_and_query: '',
91
- },
92
- timeout_ms: 3000,
93
- },
147
+ endpoint,
94
148
  timeout: { secs: 5, nanos: 0 },
95
149
  demangle_names: true,
96
150
  signals: [],
@@ -124,11 +178,21 @@ class Crashtracker {
124
178
  }
125
179
  }
126
180
 
127
- #getReceiverConfig () {
181
+ /**
182
+ * @param {import('../config/config-base')} config - Tracer configuration
183
+ * @returns {{
184
+ * args: string[],
185
+ * env: Array<[string, string]>,
186
+ * path_to_receiver_binary: string,
187
+ * stderr_filename: null,
188
+ * stdout_filename: null
189
+ * }}
190
+ */
191
+ #getReceiverConfig (config) {
128
192
  return {
129
193
  args: [],
130
- env: [],
131
- path_to_receiver_binary: libdatadog.find('crashtracker-receiver', true),
194
+ env: config.DD_AGENTLESS_ENABLED ? getAgentlessReceiverEnvironment(config) : [],
195
+ path_to_receiver_binary: libdatadogExtras.find('crashtracker-receiver', true),
132
196
  stderr_filename: null,
133
197
  stdout_filename: null,
134
198
  }
@@ -1,10 +1,21 @@
1
1
  'use strict'
2
2
 
3
+ const { createSiteUrl } = require('../exporters/common/url')
3
4
  const getGitMetadata = require('../git_metadata')
4
5
 
6
+ /**
7
+ * @param {ReturnType<import('../config')>} config
8
+ * @param {string} [inputPath]
9
+ */
5
10
  module.exports = function getDebuggerConfig (config, inputPath) {
6
11
  const { commitSHA, repositoryUrl } = getGitMetadata(config)
12
+ const agentless = config.DD_AGENTLESS_ENABLED
13
+ const agentlessUrl = agentless ? createSiteUrl(config.site, 'debugger-intake') : undefined
14
+ if (agentless && agentlessUrl === undefined) return
15
+
7
16
  return {
17
+ agentless,
18
+ apiKey: agentless ? config.DD_API_KEY : undefined,
8
19
  commitSHA,
9
20
  debug: config.debug,
10
21
  dynamicInstrumentation: config.dynamicInstrumentation,
@@ -16,7 +27,7 @@ module.exports = function getDebuggerConfig (config, inputPath) {
16
27
  repositoryUrl,
17
28
  runtimeId: config.tags['runtime-id'],
18
29
  service: config.service,
19
- url: config.url.toString(),
30
+ url: agentless ? agentlessUrl.origin : config.url.toString(),
20
31
  version: config.version,
21
32
  inputPath,
22
33
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  module.exports = {
4
+ DEBUGGER_INPUT_DIRECT: '/api/v2/debugger',
4
5
  DEBUGGER_DIAGNOSTICS_V1: '/debugger/v1/diagnostics',
5
6
  DEBUGGER_INPUT_V1: '/debugger/v1/input',
6
7
  DEBUGGER_INPUT_V2: '/debugger/v2/input',
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const mutex = require('../../../../../vendor/dist/mutexify/promise')()
3
+ const createMutex = require('../../../../../vendor/dist/mutexify/promise')
4
+ const mutex = createMutex()
4
5
  const { getGeneratedPosition } = require('./source-maps')
5
6
  const session = require('./session')
6
7
  const { compile, compileSegments, templateRequiresEvaluation } = require('./condition')
@@ -0,0 +1,33 @@
1
+ 'use strict'
2
+
3
+ const { getHttpsProxyAgent } = require('../../evp_proxy/direct')
4
+
5
+ /**
6
+ * @param {ReturnType<import('../config')>} config - Debugger configuration
7
+ * @param {string} path - Request path
8
+ * @param {Record<string, string>} headers - Payload headers
9
+ * @returns {{
10
+ * method: 'POST',
11
+ * url: string | URL,
12
+ * path: string,
13
+ * headers: Record<string, string>,
14
+ * agent?: import('node:https').Agent
15
+ * }}
16
+ */
17
+ module.exports = function getRequestOptions (config, path, headers) {
18
+ const options = {
19
+ method: 'POST',
20
+ url: config.url,
21
+ path,
22
+ headers,
23
+ }
24
+
25
+ if (config.agentless) {
26
+ if (config.apiKey !== undefined) headers['DD-API-KEY'] = config.apiKey
27
+ headers['DD-EVP-ORIGIN'] = 'agent-debugger'
28
+ const agent = getHttpsProxyAgent(config.url.href)
29
+ if (agent !== undefined) options.agent = agent
30
+ }
31
+
32
+ return options
33
+ }