dd-trace 5.124.0 → 5.126.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 (208) 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/index.d.ts +8 -0
  14. package/package.json +13 -10
  15. package/packages/datadog-esbuild/index.js +3 -1
  16. package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
  17. package/packages/datadog-instrumentations/src/fs.js +24 -20
  18. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
  19. package/packages/datadog-instrumentations/src/graphql.js +16 -16
  20. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
  21. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  22. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +265 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +14 -5
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +251 -0
  32. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +11 -1
  33. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
  34. package/packages/datadog-instrumentations/src/jest.js +166 -45
  35. package/packages/datadog-instrumentations/src/knex.js +76 -0
  36. package/packages/datadog-instrumentations/src/mariadb.js +6 -0
  37. package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
  38. package/packages/datadog-instrumentations/src/mocha/main.js +66 -20
  39. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  40. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
  41. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
  42. package/packages/datadog-instrumentations/src/net.js +14 -17
  43. package/packages/datadog-instrumentations/src/next.js +212 -62
  44. package/packages/datadog-instrumentations/src/openai.js +42 -40
  45. package/packages/datadog-instrumentations/src/pg.js +15 -0
  46. package/packages/datadog-instrumentations/src/playwright.js +113 -13
  47. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
  48. package/packages/datadog-instrumentations/src/sequelize.js +94 -2
  49. package/packages/datadog-instrumentations/src/undici.js +53 -4
  50. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +37 -3
  51. package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
  52. package/packages/datadog-instrumentations/src/vitest-worker.js +71 -14
  53. package/packages/datadog-instrumentations/src/webdriverio.js +965 -6
  54. package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
  55. package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
  56. package/packages/datadog-plugin-amqp10/src/util.js +2 -1
  57. package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
  58. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
  59. package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
  60. package/packages/datadog-plugin-cucumber/src/index.js +0 -2
  61. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
  62. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
  63. package/packages/datadog-plugin-graphql/src/execute.js +998 -196
  64. package/packages/datadog-plugin-graphql/src/index.js +27 -7
  65. package/packages/datadog-plugin-graphql/src/jit.js +136 -0
  66. package/packages/datadog-plugin-graphql/src/request.js +18 -27
  67. package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
  68. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
  69. package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
  70. package/packages/datadog-plugin-graphql/src/utils.js +208 -120
  71. package/packages/datadog-plugin-graphql/src/validate.js +10 -23
  72. package/packages/datadog-plugin-jest/src/index.js +0 -6
  73. package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
  74. package/packages/datadog-plugin-mocha/src/index.js +403 -75
  75. package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
  76. package/packages/datadog-plugin-mysql/src/index.js +41 -15
  77. package/packages/datadog-plugin-net/src/tcp.js +3 -1
  78. package/packages/datadog-plugin-next/src/index.js +63 -29
  79. package/packages/datadog-plugin-playwright/src/index.js +167 -27
  80. package/packages/datadog-plugin-undici/src/index.js +27 -41
  81. package/packages/datadog-plugin-vitest/src/index.js +6 -12
  82. package/packages/dd-trace/src/aiguard/evaluation.js +2 -1
  83. package/packages/dd-trace/src/aiguard/messages/anthropic.js +8 -1
  84. package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
  85. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
  86. package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
  87. package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
  88. package/packages/dd-trace/src/appsec/graphql.js +6 -2
  89. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
  90. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
  91. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
  92. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +3 -1
  93. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +531 -95
  94. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
  95. package/packages/dd-trace/src/appsec/lambda.js +44 -26
  96. package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
  97. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
  100. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +5 -173
  101. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
  102. package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
  103. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
  104. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +394 -225
  105. package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
  106. package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
  107. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
  108. package/packages/dd-trace/src/ci-visibility/final-flush.js +2 -1
  109. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
  110. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
  111. package/packages/dd-trace/src/ci-visibility/requests/request.js +11 -0
  112. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
  113. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +180 -0
  114. package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
  115. package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
  116. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
  117. package/packages/dd-trace/src/config/index.js +73 -13
  118. package/packages/dd-trace/src/config/parsers.js +11 -1
  119. package/packages/dd-trace/src/config/stable.js +3 -3
  120. package/packages/dd-trace/src/config/supported-configurations.json +22 -2
  121. package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
  122. package/packages/dd-trace/src/debugger/config.js +12 -1
  123. package/packages/dd-trace/src/debugger/constants.js +1 -0
  124. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
  125. package/packages/dd-trace/src/debugger/devtools_client/request-options.js +28 -0
  126. package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -40
  127. package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
  128. package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
  129. package/packages/dd-trace/src/debugger/index.js +23 -3
  130. package/packages/dd-trace/src/dogstatsd.js +510 -76
  131. package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
  132. package/packages/dd-trace/src/encode/0.4.js +5 -5
  133. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
  134. package/packages/dd-trace/src/evp_proxy/direct.js +3 -25
  135. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  136. package/packages/dd-trace/src/exporters/agent/writer.js +24 -7
  137. package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
  138. package/packages/dd-trace/src/exporters/agentless/writer.js +103 -119
  139. package/packages/dd-trace/src/exporters/common/agents.js +28 -6
  140. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
  141. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
  142. package/packages/dd-trace/src/exporters/common/proxy.js +52 -0
  143. package/packages/dd-trace/src/exporters/common/request.js +42 -14
  144. package/packages/dd-trace/src/exporters/common/url.js +40 -1
  145. package/packages/dd-trace/src/exporters/common/writer.js +9 -7
  146. package/packages/dd-trace/src/flush.js +6 -3
  147. package/packages/dd-trace/src/id.js +14 -0
  148. package/packages/dd-trace/src/index.js +5 -2
  149. package/packages/dd-trace/src/llmobs/experiments/dataset.js +2 -1
  150. package/packages/dd-trace/src/llmobs/index.js +32 -32
  151. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
  152. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
  153. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
  154. package/packages/dd-trace/src/llmobs/util.js +0 -33
  155. package/packages/dd-trace/src/llmobs/writers/base.js +49 -32
  156. package/packages/dd-trace/src/log/index.js +7 -1
  157. package/packages/dd-trace/src/{ci-visibility/log-submission → log-submission}/log-submission-plugin.js +48 -19
  158. package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
  159. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  160. package/packages/dd-trace/src/opentelemetry/logs/index.js +5 -24
  161. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
  162. package/packages/dd-trace/src/opentelemetry/metrics/index.js +15 -22
  163. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +14 -4
  164. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +10 -0
  165. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +5 -0
  166. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
  167. package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
  168. package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
  169. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
  170. package/packages/dd-trace/src/opentracing/propagation/text_map.js +101 -20
  171. package/packages/dd-trace/src/payload-tagging/index.js +2 -1
  172. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
  173. package/packages/dd-trace/src/plugins/tracing.js +12 -10
  174. package/packages/dd-trace/src/plugins/util/ci.js +3 -1
  175. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
  176. package/packages/dd-trace/src/plugins/util/test.js +83 -20
  177. package/packages/dd-trace/src/plugins/util/url.js +2 -2
  178. package/packages/dd-trace/src/plugins/util/web.js +4 -9
  179. package/packages/dd-trace/src/priority_sampler.js +4 -0
  180. package/packages/dd-trace/src/profiling/config.js +1 -0
  181. package/packages/dd-trace/src/profiling/oom.js +7 -2
  182. package/packages/dd-trace/src/profiling/profiler.js +23 -13
  183. package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
  184. package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
  185. package/packages/dd-trace/src/proxy.js +75 -5
  186. package/packages/dd-trace/src/remote_config/index.js +319 -101
  187. package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
  188. package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
  189. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -1
  190. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -1
  191. package/packages/dd-trace/src/sampling_rule.js +39 -10
  192. package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +4 -8
  193. package/packages/dd-trace/src/serverless/vercel.js +53 -20
  194. package/packages/dd-trace/src/serverless.js +10 -3
  195. package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
  196. package/packages/dd-trace/src/span_processor.js +18 -3
  197. package/packages/dd-trace/src/span_stats.js +24 -28
  198. package/packages/dd-trace/src/startup-log.js +3 -2
  199. package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
  200. package/packages/dd-trace/src/telemetry/send-data.js +23 -20
  201. package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
  202. package/packages/dd-trace/src/tracer.js +4 -5
  203. package/packages/dd-trace/src/tracer_metadata.js +11 -3
  204. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  205. package/vendor/dist/protobufjs/index.js +1 -1
  206. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  207. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
  208. package/packages/dd-trace/src/encode/agentless-json.js +0 -210
@@ -0,0 +1,180 @@
1
+ 'use strict'
2
+
3
+ const http = require('node:http')
4
+ const https = require('node:https')
5
+
6
+ const { storage } = require('../../../../datadog-core')
7
+ const log = require('../../log')
8
+ const { markEndpointReached } = require('../../exporters/common/retry')
9
+ const { getHttpsProxyAgent } = require('../../exporters/common/proxy')
10
+ const { isLoopbackHost, parseUrl } = require('../../exporters/common/url')
11
+
12
+ const legacyStorage = storage('legacy')
13
+ const MAX_ACTIVE_REQUESTS = 16
14
+
15
+ let activeRequests = 0
16
+
17
+ /**
18
+ * Streams one video request attempt. Test Optimization retry policy stays in the exporter request wrapper.
19
+ *
20
+ * @param {import('node:stream').Readable} body - Video stream for this attempt
21
+ * @param {object} options - HTTP request options
22
+ * @param {(error: Error|null, result?: string|null, statusCode?: number,
23
+ * headers?: import('node:http').IncomingHttpHeaders) => void} callback
24
+ * @returns {void}
25
+ */
26
+ function requestVideo (body, options, callback) {
27
+ if (activeRequests >= MAX_ACTIVE_REQUESTS) {
28
+ if (!body.destroyed) body.destroy()
29
+ const error = new log.NoTransmitError('Maximum active video request count reached.')
30
+ error.code = 'ERR_DD_VIDEO_REQUEST_LIMIT'
31
+ callback(error)
32
+ return
33
+ }
34
+
35
+ let requestOptions
36
+ try {
37
+ requestOptions = getRequestOptions(options)
38
+ } catch (error) {
39
+ if (!body.destroyed) body.destroy()
40
+ callback(error)
41
+ return
42
+ }
43
+
44
+ activeRequests++
45
+ legacyStorage.run({ noop: true }, () => {
46
+ const timeout = options.timeout || 2000
47
+ const client = requestOptions.protocol === 'https:' ? https : http
48
+ let finished = false
49
+ let req = null
50
+
51
+ const complete = (error, result, statusCode, headers) => {
52
+ if (finished) return
53
+ finished = true
54
+ activeRequests--
55
+ options.signal?.removeEventListener('abort', onAbort)
56
+ body.unpipe(req)
57
+ if (!body.destroyed) body.destroy()
58
+ if (req && !req.destroyed && (error || !req.writableFinished)) req.destroy()
59
+ callback(error, result, statusCode, headers)
60
+ }
61
+ const onAbort = () => complete(getAbortError(options.signal))
62
+
63
+ try {
64
+ req = client.request(requestOptions, res => {
65
+ markEndpointReached(requestOptions)
66
+ const chunks = []
67
+
68
+ res.setTimeout(timeout)
69
+ res.on('data', chunk => chunks.push(chunk))
70
+ res.once('aborted', () => complete(Object.assign(new Error('Response aborted'), { code: 'ECONNRESET' })))
71
+ res.once('error', complete)
72
+ res.once('timeout', () => complete(Object.assign(new Error('Response timed out'), { code: 'ETIMEDOUT' })))
73
+ res.once('end', () => {
74
+ const result = Buffer.concat(chunks).toString()
75
+ if (res.statusCode >= 200 && res.statusCode <= 299) {
76
+ complete(null, result, res.statusCode, res.headers)
77
+ } else {
78
+ complete(buildError(res, result, requestOptions), null, res.statusCode, res.headers)
79
+ }
80
+ })
81
+ })
82
+ } catch (error) {
83
+ activeRequests--
84
+ if (!body.destroyed) body.destroy()
85
+ callback(error)
86
+ return
87
+ }
88
+
89
+ req.once('error', complete)
90
+ req.setTimeout(timeout, () => complete(Object.assign(new Error('Request timed out'), { code: 'ETIMEDOUT' })))
91
+ body.once('error', error => {
92
+ error.retryable = false
93
+ complete(error)
94
+ })
95
+ options.signal?.addEventListener('abort', onAbort, { once: true })
96
+ if (options.signal?.aborted) return onAbort()
97
+ body.pipe(req)
98
+ })
99
+ }
100
+
101
+ /**
102
+ * @param {object} options
103
+ * @returns {object}
104
+ */
105
+ function getRequestOptions (options) {
106
+ const requestOptions = {
107
+ ...options,
108
+ headers: options.headers ? { ...options.headers } : {},
109
+ }
110
+
111
+ if (options.url) {
112
+ const url = parseUrl(options.url)
113
+ if (url.protocol === 'unix:') {
114
+ requestOptions.socketPath = url.pathname
115
+ } else {
116
+ requestOptions.protocol = url.protocol
117
+ requestOptions.hostname = url.hostname
118
+ requestOptions.port = url.port
119
+ requestOptions.path ??= url.path
120
+ }
121
+ }
122
+
123
+ const hasApiKey = requestOptions.headers['dd-api-key'] !== undefined ||
124
+ requestOptions.headers['DD-API-KEY'] !== undefined
125
+ if (hasApiKey && requestOptions.protocol === 'http:' && !isLoopbackHost(requestOptions.hostname)) {
126
+ log.error(
127
+ 'Not sending the Datadog API key over a non-TLS connection to %s. Configure an https intake URL.',
128
+ requestOptions.hostname
129
+ )
130
+ delete requestOptions.headers['dd-api-key']
131
+ delete requestOptions.headers['DD-API-KEY']
132
+ }
133
+ if (hasApiKey && requestOptions.protocol === 'https:') {
134
+ requestOptions.agent = getHttpsProxyAgent(requestOptions, requestOptions.agent)
135
+ }
136
+
137
+ delete requestOptions.deadline
138
+ delete requestOptions.retry
139
+ delete requestOptions.retryUntilDeadline
140
+ delete requestOptions.signal
141
+ delete requestOptions.url
142
+ return requestOptions
143
+ }
144
+
145
+ /**
146
+ * @param {AbortSignal} signal
147
+ * @returns {Error}
148
+ */
149
+ function getAbortError (signal) {
150
+ return signal?.reason || Object.assign(new Error('Request aborted'), { code: 'ABORT_ERR' })
151
+ }
152
+
153
+ /**
154
+ * @param {import('node:http').IncomingMessage} res
155
+ * @param {string} responseData
156
+ * @param {object} options
157
+ * @returns {Error}
158
+ */
159
+ function buildError (res, responseData, options) {
160
+ let errorMessage = ''
161
+ try {
162
+ const port = options.port ? `:${options.port}` : ''
163
+ const baseUrl = `${options.protocol || 'http:'}//${options.hostname || 'localhost'}${port}`
164
+ const fullUrl = new URL(options.path, baseUrl).href
165
+ errorMessage = `Error from ${fullUrl}: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}.`
166
+ } catch {
167
+ // ignore
168
+ }
169
+ if (responseData) errorMessage += ` Response from the endpoint: "${responseData}"`
170
+
171
+ const error = new log.NoTransmitError(errorMessage)
172
+ error.status = res.statusCode
173
+ return error
174
+ }
175
+
176
+ Object.defineProperty(requestVideo, 'writable', {
177
+ get () { return activeRequests < MAX_ACTIVE_REQUESTS },
178
+ })
179
+
180
+ module.exports = requestVideo
@@ -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": [
@@ -734,6 +744,7 @@
734
744
  "configurationNames": [
735
745
  "dogstatsd.port"
736
746
  ],
747
+ "allowed": "[1-9]\\d{0,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]",
737
748
  "default": "8125"
738
749
  }
739
750
  ],
@@ -1929,6 +1940,14 @@
1929
1940
  "namespace": "testOptimization"
1930
1941
  }
1931
1942
  ],
1943
+ "DD_TEST_FAILURE_VIDEOS_ENABLED": [
1944
+ {
1945
+ "implementation": "A",
1946
+ "type": "boolean",
1947
+ "default": null,
1948
+ "namespace": "testOptimization"
1949
+ }
1950
+ ],
1932
1951
  "DD_TEST_FLEET_CONFIG_PATH": [
1933
1952
  {
1934
1953
  "implementation": "A",
@@ -2010,6 +2029,7 @@
2010
2029
  "configurationNames": [
2011
2030
  "port"
2012
2031
  ],
2032
+ "allowed": "[1-9]\\d{0,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]",
2013
2033
  "default": "8126"
2014
2034
  }
2015
2035
  ],