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,170 @@
1
+ 'use strict'
2
+
3
+ const { AgentEncoder } = require('./0.4')
4
+
5
+ const CROSS_PAYLOAD_CACHE_LIMIT = 256
6
+ const CROSS_PAYLOAD_CANDIDATE_LIMIT = 512
7
+ const CROSS_PAYLOAD_LEARNING_PAYLOAD_LIMIT = 8
8
+ const CROSS_PAYLOAD_MISS_LIMIT = 32
9
+ const CROSS_PAYLOAD_STRING_LIMIT = 256
10
+
11
+ class CrossPayloadAgentEncoder extends AgentEncoder {
12
+ #disableCrossPayloadCache
13
+ #crossPayloadState = createCrossPayloadState()
14
+
15
+ /**
16
+ * @param {{ flush: () => void }} writer
17
+ * @param {() => void} disableCrossPayloadCache
18
+ */
19
+ constructor (writer, disableCrossPayloadCache) {
20
+ super(writer)
21
+ this.#disableCrossPayloadCache = disableCrossPayloadCache
22
+ }
23
+
24
+ /**
25
+ * @param {string} value
26
+ * @param {boolean} [stable]
27
+ * @returns {Buffer}
28
+ */
29
+ _cacheString (value, stable = false) {
30
+ if (!stable) return super._cacheString(value)
31
+
32
+ const crossPayloadState = this.#crossPayloadState
33
+ if (crossPayloadState === undefined || value.length === 0 || value.length > CROSS_PAYLOAD_STRING_LIMIT) {
34
+ return super._cacheString(value)
35
+ }
36
+
37
+ const learning = crossPayloadState.learningPayloadCount < CROSS_PAYLOAD_LEARNING_PAYLOAD_LIMIT
38
+ if (learning) markPayloadString(crossPayloadState, value)
39
+ const retainedEntry = crossPayloadState.stringMap?.[value]
40
+ if (retainedEntry !== undefined) {
41
+ if (!learning && crossPayloadState.hitCount < CROSS_PAYLOAD_MISS_LIMIT) {
42
+ crossPayloadState.hitCount++
43
+ }
44
+ const start = this._stringBytes.length
45
+ this._stringBytes.set(retainedEntry)
46
+ const entry = this._stringBytes.buffer.subarray(start, start + retainedEntry.length)
47
+ this._stringMap[value] = entry
48
+ return entry
49
+ }
50
+ if (!learning && crossPayloadState.missCount < CROSS_PAYLOAD_MISS_LIMIT) {
51
+ crossPayloadState.missCount++
52
+ }
53
+ if (!learning || crossPayloadState.payloadStableStrings?.[value] !== true) {
54
+ return super._cacheString(value)
55
+ }
56
+
57
+ let entry = super._cacheString(value)
58
+ if (entry.length > CROSS_PAYLOAD_STRING_LIMIT) return entry
59
+
60
+ const previousPayloadStrings = crossPayloadState.previousPayloadStrings
61
+ if (previousPayloadStrings?.[value] !== undefined &&
62
+ crossPayloadState.stringCount < CROSS_PAYLOAD_CACHE_LIMIT) {
63
+ entry = Buffer.from(entry)
64
+ crossPayloadState.stringMap ??= Object.create(null)
65
+ crossPayloadState.stringMap[value] = entry
66
+ crossPayloadState.stringCount++
67
+ }
68
+ return entry
69
+ }
70
+
71
+ /** @returns {Buffer} */
72
+ makePayload () {
73
+ this.#prepareReset()
74
+ return super.makePayload()
75
+ }
76
+
77
+ /** @returns {void} */
78
+ reset () {
79
+ this.#prepareReset()
80
+ super.reset()
81
+ }
82
+
83
+ /** @returns {void} */
84
+ #prepareReset () {
85
+ const crossPayloadState = this.#crossPayloadState
86
+ if (crossPayloadState !== undefined && !prepareCrossPayloadReset(crossPayloadState)) {
87
+ this.#crossPayloadState = undefined
88
+ this.#disableCrossPayloadCache()
89
+ }
90
+ }
91
+ }
92
+
93
+ /**
94
+ * @param {{ flush: () => void }} writer
95
+ * @param {() => void} disableCrossPayloadCache
96
+ * @returns {AgentEncoder}
97
+ */
98
+ function createAgentEncoder (writer, disableCrossPayloadCache) {
99
+ return new CrossPayloadAgentEncoder(writer, disableCrossPayloadCache)
100
+ }
101
+
102
+ function createCrossPayloadState () {
103
+ return {
104
+ hitCount: 0,
105
+ learningPayloadCount: 0,
106
+ lowUseCount: 0,
107
+ missCount: 0,
108
+ payloadStableStringCount: 0,
109
+ payloadStableStrings: undefined,
110
+ previousPayloadStrings: undefined,
111
+ stringCount: 0,
112
+ stringMap: undefined,
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @param {ReturnType<typeof createCrossPayloadState>} crossPayloadState
118
+ * @param {string} value
119
+ */
120
+ function markPayloadString (crossPayloadState, value) {
121
+ if (crossPayloadState.payloadStableStringCount >= CROSS_PAYLOAD_CANDIDATE_LIMIT ||
122
+ crossPayloadState.payloadStableStrings?.[value] !== undefined) {
123
+ return
124
+ }
125
+ crossPayloadState.payloadStableStrings ??= Object.create(null)
126
+ crossPayloadState.payloadStableStrings[value] = true
127
+ crossPayloadState.payloadStableStringCount++
128
+ }
129
+
130
+ /**
131
+ * @param {ReturnType<typeof createCrossPayloadState>} crossPayloadState
132
+ * @returns {boolean}
133
+ */
134
+ function prepareCrossPayloadReset (crossPayloadState) {
135
+ const learning = crossPayloadState.learningPayloadCount < CROSS_PAYLOAD_LEARNING_PAYLOAD_LIMIT
136
+ const lowUse = !learning && crossPayloadState.hitCount < crossPayloadState.missCount
137
+ if (lowUse) {
138
+ crossPayloadState.lowUseCount++
139
+ if (crossPayloadState.lowUseCount >= 2) return false
140
+ crossPayloadState.learningPayloadCount = 0
141
+ crossPayloadState.stringCount = 0
142
+ crossPayloadState.stringMap = undefined
143
+ crossPayloadState.payloadStableStrings = undefined
144
+ crossPayloadState.payloadStableStringCount = 0
145
+ crossPayloadState.previousPayloadStrings = undefined
146
+ crossPayloadState.hitCount = 0
147
+ crossPayloadState.missCount = 0
148
+ return true
149
+ }
150
+ if (!learning && crossPayloadState.hitCount > 0) {
151
+ crossPayloadState.lowUseCount = 0
152
+ }
153
+
154
+ if (learning) {
155
+ crossPayloadState.learningPayloadCount++
156
+ if (crossPayloadState.learningPayloadCount < CROSS_PAYLOAD_LEARNING_PAYLOAD_LIMIT) {
157
+ crossPayloadState.previousPayloadStrings = crossPayloadState.payloadStableStrings
158
+ } else {
159
+ crossPayloadState.previousPayloadStrings = undefined
160
+ if (crossPayloadState.stringMap === undefined) return false
161
+ }
162
+ }
163
+ crossPayloadState.payloadStableStrings = undefined
164
+ crossPayloadState.payloadStableStringCount = 0
165
+ crossPayloadState.hitCount = 0
166
+ crossPayloadState.missCount = 0
167
+ return true
168
+ }
169
+
170
+ module.exports = { createAgentEncoder }
@@ -339,11 +339,11 @@ class AgentEncoder {
339
339
  // Replaces up to ten separate `bytes.reserve` calls per span with one.
340
340
  let typeEntry
341
341
  if (span.type) {
342
- typeEntry = stringMap[span.type] ?? this._cacheString(span.type)
342
+ typeEntry = stringMap[span.type] ?? this._cacheString(span.type, true)
343
343
  }
344
- const nameEntry = stringMap[span.name] ?? this._cacheString(span.name)
345
- const resourceEntry = stringMap[span.resource] ?? this._cacheString(span.resource)
346
- const serviceEntry = stringMap[span.service] ?? this._cacheString(span.service)
344
+ const nameEntry = stringMap[span.name] ?? this._cacheString(span.name, true)
345
+ const resourceEntry = stringMap[span.resource] ?? this._cacheString(span.resource, true)
346
+ const serviceEntry = stringMap[span.service] ?? this._cacheString(span.service, true)
347
347
  const nameLen = nameEntry.length
348
348
  const resourceLen = resourceEntry.length
349
349
  const serviceLen = serviceEntry.length
@@ -589,7 +589,7 @@ class AgentEncoder {
589
589
  const entryValue = value[key]
590
590
  if (typeof entryValue !== 'string' && typeof entryValue !== 'number') continue
591
591
 
592
- const keyEntry = stringMap[key] ?? this._cacheString(key)
592
+ const keyEntry = stringMap[key] ?? this._cacheString(key, true)
593
593
  const keyEntryLen = keyEntry.length
594
594
  const writeOffset = bytes.length
595
595
 
@@ -69,11 +69,11 @@ function truncateTestLevelMetadataTags (tags) {
69
69
  }
70
70
 
71
71
  class AgentlessCiVisibilityEncoder extends AgentEncoder {
72
- constructor (writer, { runtimeId, service, env }) {
72
+ constructor (writer, { tags }) {
73
73
  super(writer, INTAKE_SOFT_LIMIT)
74
- this.runtimeId = runtimeId
75
- this.service = service
76
- this.env = env
74
+ // Holds a reference to the live `tags` object (instead of copying `env`/`runtime-id` out of it)
75
+ // so a later change (e.g. a MicroVM clone resume) is picked up at flush time.
76
+ this.tags = tags
77
77
 
78
78
  // Used to keep track of the number of encoded events to update the
79
79
  // length of `payload.events` when calling `makePayload`
@@ -406,11 +406,12 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
406
406
  events: [],
407
407
  }
408
408
 
409
- if (this.env) {
410
- payload.metadata['*'].env = this.env
409
+ if (this.tags.env) {
410
+ payload.metadata['*'].env = this.tags.env
411
411
  }
412
- if (this.runtimeId) {
413
- payload.metadata['*']['runtime-id'] = this.runtimeId
412
+ const runtimeId = this.tags['runtime-id']
413
+ if (runtimeId) {
414
+ payload.metadata['*']['runtime-id'] = runtimeId
414
415
  }
415
416
 
416
417
  bytes.writeMapPrefix(Object.keys(payload).length)
@@ -1,9 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { format } = require('node:url')
4
-
5
- const { HttpsProxyAgent } = require('../../../../vendor/dist/https-proxy-agent')
6
- const { getProxyForUrl } = require('../../../../vendor/dist/proxy-from-env')
3
+ const { createSiteUrl } = require('../exporters/common/url')
7
4
  const log = require('../log')
8
5
 
9
6
  /**
@@ -11,7 +8,6 @@ const log = require('../log')
11
8
  * @property {URL} url - Direct intake URL
12
9
  * @property {string} basePath - Direct intake base path
13
10
  * @property {object} headers - Direct intake authentication headers
14
- * @property {import('node:https').Agent} [agent] - Optional HTTPS proxy agent
15
11
  */
16
12
 
17
13
  /**
@@ -28,25 +24,8 @@ function createDirectEVPRoute (config, intake) {
28
24
  if (!apiKey || !config.site) return
29
25
 
30
26
  try {
31
- const hostname = `${intake}.${config.site}`.toLowerCase()
32
- const url = new URL(format({
33
- protocol: 'https:',
34
- hostname,
35
- }))
36
- if (
37
- url.hostname !== hostname ||
38
- url.username ||
39
- url.password ||
40
- url.port ||
41
- url.pathname !== '/' ||
42
- url.search ||
43
- url.hash
44
- ) {
45
- throw new Error('Invalid direct EVP intake URL')
46
- }
47
-
48
- const proxyUrl = getProxyForUrl(url.href)
49
- const agent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : undefined
27
+ const url = createSiteUrl(config.site, intake)
28
+ if (url === undefined) throw new Error('Invalid direct EVP intake URL')
50
29
 
51
30
  return {
52
31
  url,
@@ -54,7 +33,6 @@ function createDirectEVPRoute (config, intake) {
54
33
  headers: {
55
34
  'DD-API-KEY': apiKey,
56
35
  },
57
- ...(agent && { agent }),
58
36
  }
59
37
  } catch (error) {
60
38
  log.debug('Unable to configure direct EVP intake: %s', error.message)
@@ -12,7 +12,7 @@ class AgentExporter {
12
12
  constructor (config, prioritySampler) {
13
13
  this.#serverlessDeliveryTracker = createServerlessDeliveryTracker()
14
14
  this._config = config
15
- const { lookup, protocolVersion, stats = {}, apmTracingEnabled } = config
15
+ const { lookup, protocolVersion, stats = {}, apmTracingEnabled, flushInterval } = config
16
16
  this._url = config.url
17
17
 
18
18
  const headers = {}
@@ -25,6 +25,7 @@ class AgentExporter {
25
25
  prioritySampler,
26
26
  lookup,
27
27
  protocolVersion,
28
+ flushInterval,
28
29
  headers,
29
30
  deliveryTracker: this.#serverlessDeliveryTracker,
30
31
  })
@@ -19,18 +19,19 @@ class AgentWriter extends BaseWriter {
19
19
  #requestTracker
20
20
 
21
21
  constructor (...args) {
22
+ const { isTestOptimization } = args[0]
22
23
  super({
23
24
  ...args[0],
24
25
  beforeFirstFlush: () => firstFlushChannel.publish(),
26
+ retainOnBackpressure: isTestOptimization,
25
27
  })
26
- const { prioritySampler, lookup, protocolVersion, headers, isTestOptimization } = args[0]
27
- const AgentEncoder = getEncoder(protocolVersion)
28
+ const { prioritySampler, lookup, protocolVersion, flushInterval, headers } = args[0]
28
29
 
29
30
  this._prioritySampler = prioritySampler
30
31
  this._lookup = lookup
31
32
  this._protocolVersion = protocolVersion
32
33
  this._headers = headers
33
- this._encoder = new AgentEncoder(this)
34
+ this._encoder = createEncoder(protocolVersion, flushInterval, this)
34
35
  if (isTestOptimization) {
35
36
  this.#request = require('../../ci-visibility/exporters/request')
36
37
  const TestOptimizationRequestTracker = require('../../ci-visibility/exporters/agentless/request-tracker')
@@ -113,10 +114,26 @@ class AgentWriter extends BaseWriter {
113
114
  }
114
115
  }
115
116
 
116
- function getEncoder (protocolVersion) {
117
- return protocolVersion === '0.5'
118
- ? require('../../encode/0.5').AgentEncoder
119
- : require('../../encode/0.4').AgentEncoder
117
+ /**
118
+ * @param {string} protocolVersion
119
+ * @param {number | undefined} flushInterval
120
+ * @param {AgentWriter} writer
121
+ * @returns {import('../../encode/0.4').AgentEncoder}
122
+ */
123
+ function createEncoder (protocolVersion, flushInterval, writer) {
124
+ if (protocolVersion === '0.5') {
125
+ const { AgentEncoder } = require('../../encode/0.5')
126
+ return new AgentEncoder(writer)
127
+ }
128
+ if (flushInterval === 0) {
129
+ const { createAgentEncoder } = require('../../encode/0.4-cross-payload')
130
+ const disableCrossPayloadCache = () => {
131
+ writer._encoder = createEncoder('0.4', undefined, writer)
132
+ }
133
+ return createAgentEncoder(writer, disableCrossPayloadCache)
134
+ }
135
+ const { AgentEncoder } = require('../../encode/0.4')
136
+ return new AgentEncoder(writer)
120
137
  }
121
138
 
122
139
  function makeRequest (version, data, count, url, headers, lookup, flushOptions, request, requestTracker, cb) {
@@ -4,8 +4,7 @@ const { URL } = require('node:url')
4
4
  const os = require('node:os')
5
5
 
6
6
  const log = require('../../log')
7
- const { entityId } = require('../common/docker')
8
- const tracerVersion = require('../../../../../package.json').version
7
+ const { containerId } = require('../common/docker')
9
8
  const Writer = require('./writer')
10
9
  const { computeIntakeUrl } = require('./intake')
11
10
 
@@ -23,7 +22,7 @@ class AgentlessExporter {
23
22
  * @param {string} [config.site] - The Datadog site. Defaults to 'datadoghq.com'.
24
23
  * @param {number} [config.flushInterval] - Batch flush interval in ms
25
24
  * @param {string} [config.env] - Environment name
26
- * @param {object} [config.tags] - Tags including runtime-id
25
+ * @param {object} config.tags - Tags including runtime-id
27
26
  */
28
27
  constructor (config) {
29
28
  this.#config = config
@@ -40,13 +39,12 @@ class AgentlessExporter {
40
39
 
41
40
  const metadata = {
42
41
  hostname: os.hostname(),
43
- env: config.env,
44
- languageName: 'nodejs',
45
- languageVersion: process.version,
46
- tracerVersion,
47
- runtimeID: config.tags?.['runtime-id'],
48
- ...(entityId ? { containerID: entityId } : {}),
42
+ // Read live off `config` (instead of copying the value) so a later change
43
+ // (e.g. a MicroVM clone resume) is picked up by the next data-pipeline export.
44
+ get env () { return config.env },
45
+ get runtimeID () { return config.tags['runtime-id'] },
49
46
  }
47
+ if (containerId) metadata.containerId = containerId
50
48
 
51
49
  this._writer = new Writer({
52
50
  url: this._url,
@@ -1,42 +1,56 @@
1
1
  'use strict'
2
2
 
3
+ const { createAgentlessExporter } = require('@datadog/libdatadog')
4
+
5
+ const { storage } = require('../../../../datadog-core')
3
6
  const getConfig = require('../../config')
4
7
  const log = require('../../log')
5
- const request = require('../common/request')
6
8
  const tracerVersion = require('../../../../../package.json').version
7
9
 
10
+ const { canSendApiKey } = require('../common/url')
11
+ const { getHttpsProxyAgent } = require('../common/proxy')
8
12
  const BaseWriter = require('../common/writer')
9
- const { AgentlessJSONEncoder } = require('../../encode/agentless-json')
13
+ const { AgentEncoder } = require('../../encode/0.4')
10
14
  const { computeIntakeUrl, INTAKE_PATH } = require('./intake')
11
15
 
16
+ const legacyStorage = storage('legacy')
17
+
12
18
  /**
13
19
  * Writer for agentless APM trace intake.
14
- * Sends traces directly to the Datadog intake endpoint without an agent.
20
+ * Encodes traces as v0.4 MessagePack and delegates transformation and delivery
21
+ * to the APM data pipeline.
15
22
  */
16
23
  class AgentlessWriter extends BaseWriter {
17
24
  #apiKeyMissing = false
25
+ #apiKeyUnsafeReceiver = false
26
+ #exporter
27
+ #exporterApiKey
28
+ #exporterEnv
29
+ #exporterRuntimeId
30
+ #metadata
18
31
  #urlMissing = false
19
32
 
20
33
  /**
21
34
  * @param {object} options - Writer options
22
35
  * @param {URL} [options.url] - The intake URL. If not provided, constructed from site.
23
36
  * @param {string} [options.site] - The Datadog site
24
- * @param {object} [options.metadata] - Metadata to pass to the encoder (hostname, env, etc.)
37
+ * @param {object} [options.metadata] - Metadata to pass to the data pipeline
25
38
  */
26
39
  constructor ({ url, site = 'datadoghq.com', metadata = {} }) {
27
40
  super({ url })
28
- this._encoder = new AgentlessJSONEncoder(this, metadata)
41
+ this.#metadata = metadata
42
+ this._encoder = new AgentEncoder(this)
29
43
 
30
44
  if (!url) {
31
45
  try {
32
46
  this._url = new URL(computeIntakeUrl(site))
33
- } catch (err) {
47
+ } catch (error) {
34
48
  log.error(
35
49
  'Invalid site value for agentless intake: %s. Cannot construct URL. Error: %s',
36
50
  site,
37
- err.message
51
+ error.message
38
52
  )
39
- this._url = null
53
+ this._url = undefined
40
54
  }
41
55
  }
42
56
 
@@ -46,59 +60,23 @@ class AgentlessWriter extends BaseWriter {
46
60
  }
47
61
  }
48
62
 
63
+ /**
64
+ * @param {URL} url - The new intake URL.
65
+ */
49
66
  setUrl (url) {
50
67
  super.setUrl(url)
68
+ this.#closeExporter()
51
69
  if (url) {
52
70
  this.#urlMissing = false
53
71
  }
54
72
  }
55
73
 
56
74
  /**
57
- * Flushes accumulated traces to the intake as a single request.
58
- * @param {Function} [done] - Callback when send completes
59
- */
60
- flush (done = () => {}) {
61
- if (!request.writable) {
62
- const count = this._encoder.count()
63
- if (count > 0) {
64
- log.error('Maximum number of active requests reached. Dropping %d trace(s).', count)
65
- }
66
- this._encoder.reset()
67
- done()
68
- return
69
- }
70
-
71
- const count = this._encoder.count()
72
-
73
- if (count === 0) {
74
- done()
75
- return
76
- }
77
-
78
- const payload = this._encoder.makePayload()
79
-
80
- if (payload.length === 0) {
81
- log.debug('Skipping send of empty payload')
82
- done()
83
- return
84
- }
85
-
86
- this._sendPayload(payload, count, done)
87
- }
88
-
89
- /**
90
- * Sends the encoded payload to the intake endpoint.
91
- * @param {Buffer} data - The encoded JSON payload
92
- * @param {number} count - Number of traces in the payload
93
- * @param {Function} done - Callback when complete
75
+ * @param {Buffer} data - v0.4 MessagePack payload.
76
+ * @param {number} count - Number of traces in the payload.
77
+ * @param {() => void} done - Callback invoked after delivery completes or fails.
94
78
  */
95
79
  _sendPayload (data, count, done) {
96
- if (!data || data.length === 0) {
97
- log.debug('Skipping send of empty payload')
98
- done()
99
- return
100
- }
101
-
102
80
  if (!this._url) {
103
81
  if (!this.#urlMissing) {
104
82
  this.#urlMissing = true
@@ -121,81 +99,87 @@ class AgentlessWriter extends BaseWriter {
121
99
  }
122
100
  this.#apiKeyMissing = false
123
101
 
124
- const options = {
125
- path: INTAKE_PATH,
126
- method: 'POST',
127
- headers: {
128
- 'Content-Type': 'application/json',
129
- 'dd-api-key': DD_API_KEY,
130
- 'X-Datadog-Trace-Count': String(count),
131
- 'Datadog-Meta-Lang': 'nodejs',
132
- 'Datadog-Meta-Lang-Version': process.version,
133
- 'Datadog-Meta-Lang-Interpreter': process.versions.bun ? 'JavaScriptCore' : 'v8',
134
- 'Datadog-Meta-Tracer-Version': tracerVersion,
135
- },
136
- timeout: 15_000,
137
- url: this._url,
102
+ // The WASM transport performs its HTTP request in JavaScript. Keep that
103
+ // internal request out of the instrumented application's traces.
104
+ try {
105
+ legacyStorage.run({ noop: true }, () => {
106
+ const exporter = this.#applyConfiguration(DD_API_KEY)
107
+ if (exporter) {
108
+ exporter.sendV04(data, done, log)
109
+ } else {
110
+ done()
111
+ }
112
+ })
113
+ } catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error)
115
+ log.error('Failed to send %d trace(s) to the agentless intake: %s', count, message)
116
+ done()
138
117
  }
118
+ }
139
119
 
140
- log.debug('Request to the agentless intake: %j', options)
141
-
142
- request(data, options, (err, res, statusCode) => {
143
- if (err) {
144
- this.#logRequestError(err, statusCode, count)
145
- done()
146
- return
147
- }
148
-
149
- log.debug('Response from the agentless intake: %s', res)
150
- done()
151
- })
120
+ /**
121
+ * @returns {string} The full agentless intake endpoint.
122
+ */
123
+ #endpoint () {
124
+ const endpoint = new URL(this._url)
125
+ endpoint.pathname = INTAKE_PATH
126
+ endpoint.search = ''
127
+ endpoint.hash = ''
128
+ return endpoint.href
152
129
  }
153
130
 
154
131
  /**
155
- * Logs request errors with status-specific guidance.
156
- * @param {Error} err - The error object
157
- * @param {number} statusCode - HTTP status code (if available)
158
- * @param {number} count - Number of traces that were being sent
132
+ * @param {string} apiKey - Datadog API key.
133
+ * @returns {import('@datadog/libdatadog').AgentlessExporter|undefined}
159
134
  */
160
- #logRequestError (err, statusCode, count) {
161
- if (statusCode === 401 || statusCode === 403) {
162
- log.error(
163
- 'Authentication failed sending %d trace(s) (status %s). Verify DD_API_KEY is valid.',
164
- count,
165
- statusCode
166
- )
167
- } else if (statusCode === 404) {
168
- log.error(
169
- 'Trace intake endpoint not found (status %s). Verify DD_SITE is correctly configured. %d trace(s) dropped.',
170
- statusCode,
171
- count
172
- )
173
- } else if (statusCode === 429) {
174
- log.error(
175
- 'Rate limited by trace intake (status 429). %d trace(s) dropped.',
176
- count
177
- )
178
- } else if (statusCode >= 500) {
179
- log.error(
180
- 'Trace intake server error (status %s). %d trace(s) dropped. This may be transient.',
181
- statusCode,
182
- count
183
- )
184
- } else if (statusCode) {
185
- log.error(
186
- 'Error sending agentless payload (status %s): %s. %d trace(s) dropped.',
187
- statusCode,
188
- err.message,
189
- count
190
- )
191
- } else {
192
- log.error(
193
- 'Network error sending %d trace(s) to %s: %s',
194
- count,
195
- this._url?.hostname || 'unknown',
196
- err.message
197
- )
135
+ #applyConfiguration (apiKey) {
136
+ if (!canSendApiKey(this._url.protocol, this._url.hostname)) {
137
+ if (!this.#apiKeyUnsafeReceiver) {
138
+ this.#apiKeyUnsafeReceiver = true
139
+ log.warn('DD_API_KEY will not be sent because the configured receiver is neither HTTPS nor loopback.')
140
+ }
141
+ return
142
+ }
143
+ this.#apiKeyUnsafeReceiver = false
144
+
145
+ const { env, runtimeID } = this.#metadata
146
+ if (
147
+ this.#exporter &&
148
+ this.#exporterApiKey === apiKey &&
149
+ this.#exporterEnv === env &&
150
+ this.#exporterRuntimeId === runtimeID
151
+ ) {
152
+ return this.#exporter
198
153
  }
154
+
155
+ this.#closeExporter()
156
+ const config = getConfig()
157
+ const agent = this._url.protocol === 'https:' ? getHttpsProxyAgent(this._url) : undefined
158
+ this.#exporter = createAgentlessExporter({
159
+ endpoint: this.#endpoint(),
160
+ apiKey,
161
+ hostname: this.#metadata.hostname,
162
+ env,
163
+ service: config.service,
164
+ version: config.version,
165
+ runtimeId: runtimeID,
166
+ containerId: this.#metadata.containerId,
167
+ tracerVersion,
168
+ languageVersion: process.version,
169
+ languageInterpreter: process.versions.bun ? 'JavaScriptCore' : 'v8',
170
+ }, { agent })
171
+ this.#exporterApiKey = apiKey
172
+ this.#exporterEnv = env
173
+ this.#exporterRuntimeId = runtimeID
174
+ return this.#exporter
175
+ }
176
+
177
+ #closeExporter () {
178
+ this.#exporter?.close()
179
+ this.#exporter = undefined
180
+ this.#exporterApiKey = undefined
181
+ this.#exporterEnv = undefined
182
+ this.#exporterRuntimeId = undefined
199
183
  }
200
184
  }
201
185