dd-trace 6.9.0 → 6.11.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 (175) hide show
  1. package/README.md +0 -17
  2. package/ci/vitest-no-worker-init-setup.mjs +112 -10
  3. package/index.d.ts +150 -3
  4. package/initialize.mjs +28 -17
  5. package/openfeature.js +2 -2
  6. package/package.json +14 -10
  7. package/packages/datadog-esbuild/index.js +0 -34
  8. package/packages/datadog-instrumentations/src/anthropic.js +210 -15
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
  10. package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
  11. package/packages/datadog-instrumentations/src/bunyan.js +3 -16
  12. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
  13. package/packages/datadog-instrumentations/src/cucumber.js +26 -11
  14. package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
  15. package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
  16. package/packages/datadog-instrumentations/src/cypress.js +2 -0
  17. package/packages/datadog-instrumentations/src/fastify.js +2 -0
  18. package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
  20. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +634 -0
  21. package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +81 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
  26. package/packages/datadog-instrumentations/src/jest.js +26 -18
  27. package/packages/datadog-instrumentations/src/mariadb.js +278 -21
  28. package/packages/datadog-instrumentations/src/mocha/main.js +540 -56
  29. package/packages/datadog-instrumentations/src/mocha/utils.js +132 -25
  30. package/packages/datadog-instrumentations/src/mysql.js +45 -15
  31. package/packages/datadog-instrumentations/src/mysql2.js +119 -18
  32. package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
  33. package/packages/datadog-instrumentations/src/pg.js +116 -92
  34. package/packages/datadog-instrumentations/src/playwright-reporter.js +99 -0
  35. package/packages/datadog-instrumentations/src/playwright.js +149 -2
  36. package/packages/datadog-instrumentations/src/router.js +2 -0
  37. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
  38. package/packages/datadog-instrumentations/src/vitest-main.js +180 -20
  39. package/packages/datadog-instrumentations/src/vitest-util.js +64 -5
  40. package/packages/datadog-instrumentations/src/vitest-worker.js +150 -25
  41. package/packages/datadog-instrumentations/src/webdriverio.js +31 -17
  42. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
  43. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -0
  44. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
  45. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -13
  46. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
  47. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  48. package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
  49. package/packages/datadog-plugin-bunyan/src/index.js +5 -8
  50. package/packages/datadog-plugin-cucumber/src/index.js +11 -0
  51. package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
  52. package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
  53. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +82 -30
  54. package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
  55. package/packages/datadog-plugin-cypress/src/index.js +12 -6
  56. package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
  57. package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
  58. package/packages/datadog-plugin-electron/src/index.js +2 -0
  59. package/packages/datadog-plugin-fs/src/index.js +1 -1
  60. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
  61. package/packages/datadog-plugin-jest/src/index.js +11 -4
  62. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
  63. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
  64. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -2
  65. package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
  66. package/packages/datadog-plugin-mocha/src/index.js +606 -40
  67. package/packages/datadog-plugin-mysql/src/index.js +37 -0
  68. package/packages/datadog-plugin-nats/src/index.js +1 -1
  69. package/packages/datadog-plugin-next/src/index.js +1 -19
  70. package/packages/datadog-plugin-openai/src/tracing.js +41 -30
  71. package/packages/datadog-plugin-openai-agents/src/integration.js +279 -69
  72. package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
  73. package/packages/datadog-plugin-pg/src/index.js +1 -0
  74. package/packages/datadog-plugin-playwright/src/index.js +42 -13
  75. package/packages/datadog-plugin-vitest/src/index.js +14 -20
  76. package/packages/datadog-plugin-ws/src/util.js +2 -1
  77. package/packages/datadog-webpack/index.js +0 -11
  78. package/packages/dd-trace/index.js +0 -1
  79. package/packages/dd-trace/src/agent/info.js +6 -5
  80. package/packages/dd-trace/src/aiguard/client.js +100 -1
  81. package/packages/dd-trace/src/aiguard/errors.js +41 -0
  82. package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
  83. package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
  84. package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
  85. package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
  86. package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
  87. package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
  88. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
  89. package/packages/dd-trace/src/aiguard/sdk.js +22 -278
  90. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
  91. package/packages/dd-trace/src/appsec/handlers/http-request.js +13 -0
  92. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -12
  93. package/packages/dd-trace/src/carrier.js +356 -0
  94. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
  95. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +27 -3
  96. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +22 -6
  97. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +22 -6
  100. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
  101. package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
  102. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
  103. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
  104. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
  105. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
  106. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
  107. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +6 -2
  108. package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -0
  109. package/packages/dd-trace/src/config/index.js +13 -2
  110. package/packages/dd-trace/src/config/major-overrides.js +7 -0
  111. package/packages/dd-trace/src/config/supported-configurations.json +24 -0
  112. package/packages/dd-trace/src/datastreams/context.js +6 -1
  113. package/packages/dd-trace/src/datastreams/index.js +2 -0
  114. package/packages/dd-trace/src/datastreams/manager.js +14 -3
  115. package/packages/dd-trace/src/datastreams/pathway.js +23 -22
  116. package/packages/dd-trace/src/datastreams/processor.js +16 -13
  117. package/packages/dd-trace/src/datastreams/size.js +5 -0
  118. package/packages/dd-trace/src/debugger/devtools_client/index.js +3 -2
  119. package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
  120. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
  121. package/packages/dd-trace/src/exporters/common/writer.js +11 -6
  122. package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
  123. package/packages/dd-trace/src/llmobs/experiments/client.js +163 -5
  124. package/packages/dd-trace/src/llmobs/experiments/dataset.js +241 -87
  125. package/packages/dd-trace/src/llmobs/experiments/experiment.js +280 -20
  126. package/packages/dd-trace/src/llmobs/experiments/index.js +58 -59
  127. package/packages/dd-trace/src/llmobs/experiments/noop.js +71 -3
  128. package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
  129. package/packages/dd-trace/src/llmobs/experiments/util.js +41 -5
  130. package/packages/dd-trace/src/llmobs/index.js +34 -2
  131. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
  132. package/packages/dd-trace/src/llmobs/plugins/base.js +4 -2
  133. package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
  134. package/packages/dd-trace/src/llmobs/tagger.js +96 -0
  135. package/packages/dd-trace/src/llmobs/util.js +78 -0
  136. package/packages/dd-trace/src/noop/proxy.js +3 -4
  137. package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
  138. package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
  139. package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
  140. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
  141. package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
  142. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
  143. package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
  144. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
  145. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
  146. package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
  147. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
  148. package/packages/dd-trace/src/opentracing/tracer.js +5 -2
  149. package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
  150. package/packages/dd-trace/src/plugin_manager.js +5 -3
  151. package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
  152. package/packages/dd-trace/src/plugins/index.js +1 -0
  153. package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +5 -65
  154. package/packages/dd-trace/src/plugins/util/test.js +93 -14
  155. package/packages/dd-trace/src/plugins/util/web.js +56 -2
  156. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  157. package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
  158. package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
  159. package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
  160. package/packages/dd-trace/src/proxy.js +38 -29
  161. package/packages/dd-trace/src/ritm.js +9 -2
  162. package/packages/dd-trace/src/serverless.js +37 -0
  163. package/packages/dd-trace/src/span_format.js +1 -0
  164. package/packages/dd-trace/src/span_stats.js +30 -3
  165. package/packages/dd-trace/src/storage-channels.js +86 -0
  166. package/packages/dd-trace/src/tracer.js +9 -2
  167. package/packages/dd-trace/src/tracer_metadata.js +14 -1
  168. package/packages/dd-trace/src/web-tags-cache.js +132 -0
  169. package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
  170. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
  171. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
  172. package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
  173. package/packages/dd-trace/src/feature-registry.js +0 -29
  174. package/packages/dd-trace/src/openfeature/register.js +0 -35
  175. package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
@@ -0,0 +1,356 @@
1
+ 'use strict'
2
+
3
+ /** @typedef {Record<string, unknown>} Carrier */
4
+ /** @typedef {string | Buffer} PathwayValue */
5
+
6
+ const FIELD_READ = 1
7
+ const FIELD_WRITE = 2
8
+ const FIELD_HAS = 4
9
+ const FIELD_DELETE = 8
10
+ const FIELD_NAME_LENGTH = 16
11
+
12
+ /** @type {Record<string, unknown>} */
13
+ const carrierOperations = {}
14
+
15
+ /**
16
+ * @typedef {object} CarrierCapability
17
+ * @property {unknown} [read]
18
+ * @property {unknown} [write]
19
+ * @property {unknown} [has]
20
+ * @property {unknown} [delete]
21
+ * @property {unknown} [nameLength]
22
+ */
23
+
24
+ /**
25
+ * @template Value
26
+ * @typedef {object} CarrierField
27
+ * @property {(carrier: Carrier) => Value | undefined} read
28
+ * @property {(carrier: Carrier, value: Value) => void} write
29
+ * @property {(carrier: Carrier) => boolean} has
30
+ * @property {(carrier: Carrier) => void} delete
31
+ * @property {(carrier: Carrier, target: Carrier) => void} copy
32
+ * @property {number} nameLength
33
+ */
34
+
35
+ /**
36
+ * @template {CarrierCapability} Capability
37
+ * @param {string} name
38
+ * @param {number} operations
39
+ * @param {Capability} capability
40
+ * @returns {Capability}
41
+ */
42
+ function defineCapability (name, operations, capability) {
43
+ const suffix = name[0].toUpperCase() + name.slice(1)
44
+ if (operations & FIELD_READ) carrierOperations[`read${suffix}`] = capability.read
45
+ if (operations & FIELD_WRITE) carrierOperations[`write${suffix}`] = capability.write
46
+ if (operations & FIELD_HAS) carrierOperations[`has${suffix}`] = capability.has
47
+ if (operations & FIELD_DELETE) carrierOperations[`delete${suffix}`] = capability.delete
48
+ if (operations & FIELD_NAME_LENGTH) carrierOperations[`${name}NameLength`] = capability.nameLength
49
+ return capability
50
+ }
51
+
52
+ /**
53
+ * @template Value
54
+ * @param {string} fieldName
55
+ * @param {string} headerName
56
+ * @param {(value: unknown) => Value | undefined} resolve
57
+ * @param {number} operations
58
+ * @returns {CarrierField<Value>}
59
+ */
60
+ function defineField (fieldName, headerName, resolve, operations) {
61
+ return defineCapability(fieldName, operations, {
62
+ /**
63
+ * @param {Carrier} carrier
64
+ * @returns {Value | undefined}
65
+ */
66
+ read (carrier) {
67
+ return resolve(carrier[headerName])
68
+ },
69
+
70
+ /**
71
+ * @param {Carrier} carrier
72
+ * @param {Value} value
73
+ * @returns {void}
74
+ */
75
+ write (carrier, value) {
76
+ carrier[headerName] = value
77
+ },
78
+
79
+ /**
80
+ * @param {Carrier} carrier
81
+ * @returns {boolean}
82
+ */
83
+ has (carrier) {
84
+ return headerName in carrier
85
+ },
86
+
87
+ /**
88
+ * @param {Carrier} carrier
89
+ * @returns {void}
90
+ */
91
+ delete (carrier) {
92
+ delete carrier[headerName]
93
+ },
94
+
95
+ /**
96
+ * @param {Carrier} carrier
97
+ * @param {Carrier} target
98
+ * @returns {void}
99
+ */
100
+ copy (carrier, target) {
101
+ if (Object.hasOwn(carrier, headerName)) target[headerName] = carrier[headerName]
102
+ },
103
+
104
+ nameLength: headerName.length,
105
+ })
106
+ }
107
+
108
+ /**
109
+ * Skipping non-strings keeps a Symbol or a throwing `toString` from aborting
110
+ * extraction, which discards the whole context rather than one field.
111
+ *
112
+ * @param {unknown} value
113
+ * @returns {string | undefined}
114
+ */
115
+ function readListText (value) {
116
+ if (typeof value === 'string') return value
117
+ if (!Array.isArray(value)) return
118
+
119
+ let joined = ''
120
+ let first = true
121
+
122
+ for (const item of value) {
123
+ if (typeof item !== 'string') continue
124
+ if (first) {
125
+ joined = item
126
+ first = false
127
+ } else {
128
+ joined += `,${item}`
129
+ }
130
+ }
131
+
132
+ return joined
133
+ }
134
+
135
+ /**
136
+ * @param {unknown} value
137
+ * @returns {string | undefined}
138
+ */
139
+ function readLastText (value) {
140
+ if (typeof value === 'string') return value
141
+ if (!Array.isArray(value)) return
142
+
143
+ let result
144
+ for (let i = value.length - 1; i >= 0; i--) {
145
+ if (typeof value[i] === 'string') {
146
+ result = value[i]
147
+ break
148
+ }
149
+ }
150
+ return result
151
+ }
152
+
153
+ /**
154
+ * @param {unknown} value
155
+ * @returns {string | undefined}
156
+ */
157
+ function readUniqueText (value) {
158
+ let result
159
+ if (typeof value === 'string') {
160
+ result = value
161
+ } else if (Array.isArray(value) && value.length === 1 && typeof value[0] === 'string') {
162
+ result = value[0]
163
+ }
164
+ return result
165
+ }
166
+
167
+ /**
168
+ * @param {unknown} value
169
+ * @returns {PathwayValue | undefined}
170
+ */
171
+ function readLastPathway (value) {
172
+ if (typeof value === 'string' || Buffer.isBuffer(value)) return value
173
+ if (!Array.isArray(value)) return
174
+
175
+ let result
176
+ for (let i = value.length - 1; i >= 0; i--) {
177
+ const item = value[i]
178
+ if (typeof item === 'string' || Buffer.isBuffer(item)) {
179
+ result = item
180
+ break
181
+ }
182
+ }
183
+ return result
184
+ }
185
+
186
+ const datadogTraceId = defineField(
187
+ 'datadogTraceId',
188
+ 'x-datadog-trace-id',
189
+ readLastText,
190
+ FIELD_READ | FIELD_WRITE
191
+ )
192
+ const datadogParentId = defineField(
193
+ 'datadogParentId',
194
+ 'x-datadog-parent-id',
195
+ readLastText,
196
+ FIELD_READ | FIELD_WRITE | FIELD_DELETE
197
+ )
198
+ const datadogOrigin = defineField(
199
+ 'datadogOrigin',
200
+ 'x-datadog-origin',
201
+ readLastText,
202
+ FIELD_READ | FIELD_WRITE
203
+ )
204
+ const datadogSamplingPriority = defineField(
205
+ 'datadogSamplingPriority',
206
+ 'x-datadog-sampling-priority',
207
+ readLastText,
208
+ FIELD_READ | FIELD_WRITE
209
+ )
210
+ defineField('datadogTags', 'x-datadog-tags', readListText, FIELD_READ | FIELD_WRITE)
211
+ defineField('baggage', 'baggage', readListText, FIELD_READ | FIELD_WRITE)
212
+ const b3TraceId = defineField('b3TraceId', 'x-b3-traceid', readLastText, FIELD_READ | FIELD_WRITE)
213
+ const b3SpanId = defineField('b3SpanId', 'x-b3-spanid', readLastText, FIELD_READ | FIELD_WRITE)
214
+ const b3ParentId = defineField('b3ParentId', 'x-b3-parentspanid', readLastText, FIELD_WRITE)
215
+ const b3Sampled = defineField('b3Sampled', 'x-b3-sampled', readLastText, FIELD_READ | FIELD_WRITE)
216
+ const b3Flags = defineField('b3Flags', 'x-b3-flags', readLastText, FIELD_READ | FIELD_WRITE)
217
+ const b3 = defineField('b3', 'b3', readLastText, FIELD_READ | FIELD_WRITE)
218
+ defineField('sqsd', 'x-aws-sqsd-attr-_datadog', readLastText, FIELD_READ)
219
+ const traceparent = defineField('traceparent', 'traceparent', readUniqueText, FIELD_READ | FIELD_WRITE)
220
+ const tracestate = defineField('tracestate', 'tracestate', readListText, FIELD_READ | FIELD_WRITE)
221
+ const dsmBase64 = defineField(
222
+ 'dsmBase64',
223
+ 'dd-pathway-ctx-base64',
224
+ readLastPathway,
225
+ FIELD_READ | FIELD_WRITE | FIELD_HAS | FIELD_NAME_LENGTH
226
+ )
227
+ const dsmBinary = defineField('dsmBinary', 'dd-pathway-ctx', readLastPathway, FIELD_READ | FIELD_HAS)
228
+
229
+ const legacyBaggagePrefix = 'ot-baggage-'
230
+ // RFC 7230 `token`, compatible with Node.js header-name validation.
231
+ const httpHeaderNameExpr = /^[0-9A-Za-z!#$%&'*+\-.^_`|~]+$/
232
+
233
+ defineCapability('legacyBaggage', FIELD_READ | FIELD_WRITE, {
234
+ /**
235
+ * @param {Record<string, string> | undefined} carrier
236
+ * @param {string} key
237
+ * @param {string} value
238
+ * @returns {Record<string, string> | undefined}
239
+ */
240
+ write (carrier, key, value) {
241
+ const name = legacyBaggagePrefix + key
242
+ if (!httpHeaderNameExpr.test(name)) return
243
+
244
+ carrier ??= {}
245
+ carrier[name] = value
246
+ return carrier
247
+ },
248
+
249
+ /**
250
+ * @param {Carrier} carrier
251
+ * @param {Record<string, string>} target
252
+ * @returns {void}
253
+ */
254
+ read (carrier, target) {
255
+ for (const name of Object.keys(carrier)) {
256
+ if (!name.startsWith(legacyBaggagePrefix)) continue
257
+ const key = name.slice(legacyBaggagePrefix.length)
258
+ if (!key) continue
259
+ const value = readLastText(carrier[name])
260
+ if (value !== undefined) target[key] = value
261
+ }
262
+ },
263
+ })
264
+
265
+ const textMapLogFields = [
266
+ datadogTraceId,
267
+ datadogParentId,
268
+ datadogSamplingPriority,
269
+ datadogOrigin,
270
+ b3TraceId,
271
+ b3SpanId,
272
+ b3ParentId,
273
+ b3Sampled,
274
+ b3Flags,
275
+ b3,
276
+ traceparent,
277
+ tracestate,
278
+ ]
279
+ const dsmLogFields = [dsmBinary, dsmBase64]
280
+
281
+ /**
282
+ * @param {Carrier} carrier
283
+ * @param {Array<Pick<CarrierField<unknown>, 'copy'>>} selectedFields
284
+ * @returns {Carrier}
285
+ */
286
+ function pick (carrier, selectedFields) {
287
+ /** @type {Carrier} */
288
+ const result = {}
289
+ for (const field of selectedFields) field.copy(carrier, result)
290
+ return result
291
+ }
292
+
293
+ /**
294
+ * @param {Carrier} carrier
295
+ * @returns {Carrier}
296
+ */
297
+ function pickTextMap (carrier) {
298
+ return pick(carrier, textMapLogFields)
299
+ }
300
+
301
+ /**
302
+ * @param {Carrier} carrier
303
+ * @returns {Carrier}
304
+ */
305
+ function pickDsm (carrier) {
306
+ return pick(carrier, dsmLogFields)
307
+ }
308
+
309
+ /**
310
+ * @typedef {object} CarrierOperations
311
+ * @property {typeof datadogParentId.delete} deleteDatadogParentId
312
+ * @property {typeof dsmBase64.nameLength} dsmBase64NameLength
313
+ * @property {typeof dsmBase64.has} hasDsmBase64
314
+ * @property {typeof dsmBinary.has} hasDsmBinary
315
+ * @property {typeof pickDsm} pickDsm
316
+ * @property {typeof pickTextMap} pickTextMap
317
+ * @property {(carrier: Carrier) => string | undefined} readBaggage
318
+ * @property {typeof b3.read} readB3
319
+ * @property {typeof b3Flags.read} readB3Flags
320
+ * @property {typeof b3Sampled.read} readB3Sampled
321
+ * @property {typeof b3SpanId.read} readB3SpanId
322
+ * @property {typeof b3TraceId.read} readB3TraceId
323
+ * @property {typeof datadogOrigin.read} readDatadogOrigin
324
+ * @property {typeof datadogParentId.read} readDatadogParentId
325
+ * @property {typeof datadogSamplingPriority.read} readDatadogSamplingPriority
326
+ * @property {(carrier: Carrier) => string | undefined} readDatadogTags
327
+ * @property {typeof datadogTraceId.read} readDatadogTraceId
328
+ * @property {typeof dsmBase64.read} readDsmBase64
329
+ * @property {typeof dsmBinary.read} readDsmBinary
330
+ * @property {(carrier: Carrier, target: Record<string, string>) => void} readLegacyBaggage
331
+ * @property {(carrier: Carrier) => string | undefined} readSqsd
332
+ * @property {typeof traceparent.read} readTraceparent
333
+ * @property {typeof tracestate.read} readTracestate
334
+ * @property {(carrier: Carrier, value: string) => void} writeBaggage
335
+ * @property {typeof b3.write} writeB3
336
+ * @property {typeof b3Flags.write} writeB3Flags
337
+ * @property {typeof b3ParentId.write} writeB3ParentId
338
+ * @property {typeof b3Sampled.write} writeB3Sampled
339
+ * @property {typeof b3SpanId.write} writeB3SpanId
340
+ * @property {typeof b3TraceId.write} writeB3TraceId
341
+ * @property {typeof datadogOrigin.write} writeDatadogOrigin
342
+ * @property {typeof datadogParentId.write} writeDatadogParentId
343
+ * @property {typeof datadogSamplingPriority.write} writeDatadogSamplingPriority
344
+ * @property {(carrier: Carrier, value: string) => void} writeDatadogTags
345
+ * @property {typeof datadogTraceId.write} writeDatadogTraceId
346
+ * @property {typeof dsmBase64.write} writeDsmBase64
347
+ * @property {(carrier: Record<string, string> | undefined, key: string, value: string) =>
348
+ * Record<string, string> | undefined} writeLegacyBaggage
349
+ * @property {typeof traceparent.write} writeTraceparent
350
+ * @property {typeof tracestate.write} writeTracestate
351
+ */
352
+
353
+ carrierOperations.pickDsm = pickDsm
354
+ carrierOperations.pickTextMap = pickTextMap
355
+
356
+ module.exports = /** @type {CarrierOperations} */ (carrierOperations)
@@ -92,6 +92,7 @@ function removeEmptyCaptureProperties (value) {
92
92
  if (current.fields === null || (
93
93
  current.fields &&
94
94
  typeof current.fields === 'object' &&
95
+ // eslint-disable-next-line no-restricted-syntax -- snapshot field names are user variables; no key to probe
95
96
  Object.keys(current.fields).length === 0
96
97
  )) {
97
98
  delete current.fields
@@ -4,6 +4,7 @@ const AgentWriter = require('../../../exporters/agent/writer')
4
4
  const AgentlessWriter = require('../agentless/writer')
5
5
  const CoverageWriter = require('../agentless/coverage-writer')
6
6
  const CiVisibilityExporter = require('../ci-visibility-exporter')
7
+ const request = require('../request')
7
8
  const { fetchAgentInfo } = require('../../../agent/info')
8
9
  const { DEBUGGER_INPUT_V1 } = require('../../../debugger/constants')
9
10
 
@@ -43,9 +44,21 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
43
44
  testOptimization,
44
45
  } = config
45
46
 
47
+ const initializationController = new AbortController()
48
+ const initializationOptions = { signal: initializationController.signal }
49
+ this._initializationRequest = {
50
+ controller: initializationController,
51
+ options: initializationOptions,
52
+ }
53
+
46
54
  fetchAgentInfo(this._url, (err, agentInfo) => {
55
+ const initializationFinalFlush = this._initializationRequest?.finalFlush
56
+ this._initializationRequest = undefined
57
+ const initializationAborted = initializationController.signal.aborted
58
+ const agentInfoError = err || (initializationAborted ? initializationController.signal.reason : undefined)
59
+
47
60
  this._isInitialized = true
48
- let latestEvpProxyVersion = getLatestEvpProxyVersion(err, agentInfo)
61
+ let latestEvpProxyVersion = getLatestEvpProxyVersion(agentInfoError, agentInfo)
49
62
  const isEvpCompatible = latestEvpProxyVersion >= 2
50
63
  this._isGzipCompatible = latestEvpProxyVersion >= 4
51
64
 
@@ -72,7 +85,7 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
72
85
  // path with evpProxyPrefix and sets X-Datadog-EVP-Subdomain: api (see uploadTestScreenshot).
73
86
  this._testScreenshotUploadUrl = this._url
74
87
  if (testOptimization.DD_TEST_FAILED_TEST_REPLAY_ENABLED) {
75
- const canFowardLogs = getCanForwardDebuggerLogs(err, agentInfo)
88
+ const canFowardLogs = getCanForwardDebuggerLogs(agentInfoError, agentInfo)
76
89
  if (canFowardLogs) {
77
90
  const DynamicInstrumentationLogsWriter = require('../agentless/di-logs-writer')
78
91
  this._logsWriter = new DynamicInstrumentationLogsWriter({
@@ -89,14 +102,25 @@ class AgentProxyCiVisibilityExporter extends CiVisibilityExporter {
89
102
  lookup,
90
103
  protocolVersion,
91
104
  headers,
105
+ isTestOptimization: true,
92
106
  })
93
107
  // coverages will never be used, so we discard them
94
108
  this._coverageBuffer = []
95
109
  }
96
110
  this._resolveCanUseCiVisProtocol(isEvpCompatible)
111
+ if (initializationAborted) {
112
+ this.resetUncodedTraces()
113
+ this.resetDeferredTestSuiteSpans()
114
+ return
115
+ }
116
+ if (isEvpCompatible) {
117
+ if (initializationFinalFlush) this.exportDeferredTestSuiteSpans()
118
+ } else {
119
+ this.resetDeferredTestSuiteSpans()
120
+ }
97
121
  this.exportUncodedTraces()
98
122
  this.exportUncodedCoverages()
99
- })
123
+ }, initializationOptions, request)
100
124
  }
101
125
 
102
126
  setUrl (url, coverageUrl) {
@@ -1,11 +1,8 @@
1
1
  'use strict'
2
2
  const getConfig = require('../../../config')
3
- const request = require('../../../exporters/common/request')
4
3
  const log = require('../../../log')
5
4
  const { safeJSONStringify } = require('../../../exporters/common/util')
6
5
 
7
- const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
8
- const BaseWriter = require('../../../exporters/common/writer')
9
6
  const {
10
7
  incrementCountMetric,
11
8
  distributionMetric,
@@ -15,16 +12,34 @@ const {
15
12
  TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
16
13
  TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
17
14
  } = require('../../../ci-visibility/telemetry')
15
+ const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
16
+ const BaseWriter = require('../../../exporters/common/writer')
17
+ const request = require('../request')
18
+ const TestOptimizationRequestTracker = require('./request-tracker')
18
19
 
19
20
  class Writer extends BaseWriter {
21
+ #requestTracker
22
+
20
23
  constructor ({ url, evpProxyPrefix = '' }) {
21
24
  super(...arguments)
25
+ this.#requestTracker = new TestOptimizationRequestTracker(this)
22
26
  this._url = url
23
27
  this._encoder = new CoverageCIVisibilityEncoder(this)
24
28
  this._evpProxyPrefix = evpProxyPrefix
25
29
  }
26
30
 
27
- _sendPayload (form, _, done) {
31
+ /**
32
+ * Flushes buffered coverage, waiting for tracked requests during finalization.
33
+ *
34
+ * @param {(error?: Error) => void} [done]
35
+ * @param {{ deadline?: number }} [options]
36
+ * @returns {void}
37
+ */
38
+ flush (done, options) {
39
+ this.#requestTracker.flush(done, options)
40
+ }
41
+
42
+ _sendPayload (form, _, done, flushOptions) {
28
43
  const options = {
29
44
  path: '/api/v2/citestcov',
30
45
  method: 'POST',
@@ -34,6 +49,7 @@ class Writer extends BaseWriter {
34
49
  },
35
50
  timeout: 15_000,
36
51
  url: this._url,
52
+ deadline: flushOptions?.deadline,
37
53
  }
38
54
 
39
55
  if (this._evpProxyPrefix) {
@@ -50,7 +66,7 @@ class Writer extends BaseWriter {
50
66
  incrementCountMetric(TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS, { endpoint: 'code_coverage' })
51
67
  distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_BYTES, { endpoint: 'code_coverage' }, form.size())
52
68
 
53
- request(form, options, (err, res, statusCode) => {
69
+ this.#requestTracker.send(request, form, options, (err, res, statusCode) => {
54
70
  distributionMetric(
55
71
  TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
56
72
  { endpoint: 'code_coverage' },
@@ -66,7 +82,7 @@ class Writer extends BaseWriter {
66
82
  { endpoint: 'code_coverage' }
67
83
  )
68
84
  log.error('Error sending CI coverage payload', err)
69
- done()
85
+ done(err)
70
86
  return
71
87
  }
72
88
  log.debug('Response from the intake:', res)
@@ -1,27 +1,42 @@
1
1
  'use strict'
2
2
  const getConfig = require('../../../config')
3
- const request = require('../../../exporters/common/request')
4
3
  const log = require('../../../log')
5
4
  const { safeJSONStringify } = require('../../../exporters/common/util')
6
5
  const { JSONEncoder } = require('../../encode/json-encoder')
7
6
  const { DEBUGGER_INPUT_V1 } = require('../../../debugger/constants')
8
-
9
7
  const BaseWriter = require('../../../exporters/common/writer')
10
8
 
9
+ const request = require('../request')
10
+ const TestOptimizationRequestTracker = require('./request-tracker')
11
+
11
12
  // Writer used by the integration between Dynamic Instrumentation and Test Visibility
12
13
  // It is used to encode and send logs to both the logs intake directly and the
13
14
  // `/debugger/v1/input` endpoint in the agent, which is a proxy to the logs intake.
14
15
  class DynamicInstrumentationLogsWriter extends BaseWriter {
16
+ #requestTracker
17
+
15
18
  // TODO: what's a good value for timeout for the logs intake?
16
19
  constructor ({ url, timeout = 15_000, isAgentProxy = false }) {
17
20
  super(...arguments)
21
+ this.#requestTracker = new TestOptimizationRequestTracker(this)
18
22
  this._url = url
19
23
  this._encoder = new JSONEncoder()
20
24
  this._isAgentProxy = isAgentProxy
21
25
  this.timeout = timeout
22
26
  }
23
27
 
24
- _sendPayload (data, _, done) {
28
+ /**
29
+ * Flushes buffered logs, waiting for tracked requests during finalization.
30
+ *
31
+ * @param {(error?: Error) => void} [done]
32
+ * @param {{ deadline?: number }} [options]
33
+ * @returns {void}
34
+ */
35
+ flush (done, options) {
36
+ this.#requestTracker.flush(done, options)
37
+ }
38
+
39
+ _sendPayload (data, _, done, flushOptions) {
25
40
  const options = {
26
41
  path: '/api/v2/logs',
27
42
  method: 'POST',
@@ -31,6 +46,7 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
31
46
  },
32
47
  timeout: this.timeout,
33
48
  url: this._url,
49
+ deadline: flushOptions?.deadline,
34
50
  }
35
51
 
36
52
  if (this._isAgentProxy) {
@@ -41,10 +57,10 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
41
57
  // eslint-disable-next-line eslint-rules/eslint-log-printf-style
42
58
  log.debug(() => `Request to the logs intake: ${safeJSONStringify(options)}`)
43
59
 
44
- request(data, options, (err, res) => {
60
+ this.#requestTracker.send(request, data, options, (err, res) => {
45
61
  if (err) {
46
62
  log.error('Error sending DI logs payload', err)
47
- done()
63
+ done(err)
48
64
  return
49
65
  }
50
66
  log.debug('Response from the logs intake:', res)