dd-trace 5.103.0 → 5.105.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 (213) hide show
  1. package/LICENSE-3rdparty.csv +90 -102
  2. package/index.d.ts +107 -6
  3. package/package.json +18 -17
  4. package/packages/datadog-core/src/storage.js +1 -1
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/ai.js +8 -7
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +15 -2
  8. package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
  10. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
  11. package/packages/datadog-instrumentations/src/cucumber.js +181 -35
  12. package/packages/datadog-instrumentations/src/dns.js +54 -18
  13. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  14. package/packages/datadog-instrumentations/src/fastify.js +142 -82
  15. package/packages/datadog-instrumentations/src/graphql.js +188 -67
  16. package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
  17. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
  18. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
  21. package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
  22. package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
  23. package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
  24. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +31 -229
  32. package/packages/datadog-instrumentations/src/hono.js +54 -3
  33. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  34. package/packages/datadog-instrumentations/src/http/server.js +9 -4
  35. package/packages/datadog-instrumentations/src/ioredis.js +3 -3
  36. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
  37. package/packages/datadog-instrumentations/src/jest.js +390 -183
  38. package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
  39. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  40. package/packages/datadog-instrumentations/src/memcached.js +2 -1
  41. package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
  42. package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
  43. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  44. package/packages/datadog-instrumentations/src/mongoose.js +10 -12
  45. package/packages/datadog-instrumentations/src/mysql.js +2 -2
  46. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  47. package/packages/datadog-instrumentations/src/nats.js +182 -0
  48. package/packages/datadog-instrumentations/src/nyc.js +38 -1
  49. package/packages/datadog-instrumentations/src/openai.js +33 -18
  50. package/packages/datadog-instrumentations/src/oracledb.js +6 -1
  51. package/packages/datadog-instrumentations/src/pg.js +1 -1
  52. package/packages/datadog-instrumentations/src/pino.js +17 -5
  53. package/packages/datadog-instrumentations/src/playwright.js +537 -297
  54. package/packages/datadog-instrumentations/src/router.js +80 -34
  55. package/packages/datadog-instrumentations/src/stripe.js +1 -1
  56. package/packages/datadog-instrumentations/src/vitest.js +246 -149
  57. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  58. package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
  59. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
  60. package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
  61. package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
  62. package/packages/datadog-plugin-bunyan/src/index.js +28 -0
  63. package/packages/datadog-plugin-cucumber/src/index.js +17 -3
  64. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +223 -45
  65. package/packages/datadog-plugin-cypress/src/support.js +69 -1
  66. package/packages/datadog-plugin-dns/src/lookup.js +8 -6
  67. package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
  68. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
  69. package/packages/datadog-plugin-graphql/src/execute.js +2 -0
  70. package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
  71. package/packages/datadog-plugin-graphql/src/utils.js +4 -1
  72. package/packages/datadog-plugin-http/src/server.js +40 -15
  73. package/packages/datadog-plugin-jest/src/index.js +11 -3
  74. package/packages/datadog-plugin-jest/src/util.js +15 -8
  75. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  76. package/packages/datadog-plugin-kafkajs/src/producer.js +35 -0
  77. package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
  78. package/packages/datadog-plugin-mocha/src/index.js +19 -4
  79. package/packages/datadog-plugin-mongodb-core/src/index.js +311 -35
  80. package/packages/datadog-plugin-nats/src/consumer.js +43 -0
  81. package/packages/datadog-plugin-nats/src/index.js +20 -0
  82. package/packages/datadog-plugin-nats/src/producer.js +62 -0
  83. package/packages/datadog-plugin-nats/src/util.js +33 -0
  84. package/packages/datadog-plugin-next/src/index.js +5 -3
  85. package/packages/datadog-plugin-openai/src/tracing.js +15 -2
  86. package/packages/datadog-plugin-oracledb/src/index.js +13 -2
  87. package/packages/datadog-plugin-pino/src/index.js +42 -0
  88. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  89. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  90. package/packages/datadog-plugin-redis/src/index.js +37 -2
  91. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  92. package/packages/datadog-plugin-router/src/index.js +33 -44
  93. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  94. package/packages/datadog-plugin-undici/src/index.js +19 -0
  95. package/packages/datadog-plugin-vitest/src/index.js +24 -20
  96. package/packages/datadog-plugin-winston/src/index.js +30 -0
  97. package/packages/datadog-shimmer/src/shimmer.js +49 -21
  98. package/packages/dd-trace/src/aiguard/index.js +1 -1
  99. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  100. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  101. package/packages/dd-trace/src/appsec/blocking.js +2 -2
  102. package/packages/dd-trace/src/appsec/index.js +11 -4
  103. package/packages/dd-trace/src/appsec/reporter.js +24 -11
  104. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  105. package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
  106. package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
  107. package/packages/dd-trace/src/baggage.js +7 -1
  108. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
  109. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
  110. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
  111. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
  112. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
  113. package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
  114. package/packages/dd-trace/src/config/supported-configurations.json +36 -8
  115. package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
  116. package/packages/dd-trace/src/datastreams/context.js +4 -2
  117. package/packages/dd-trace/src/datastreams/writer.js +2 -4
  118. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
  119. package/packages/dd-trace/src/encode/0.4.js +124 -108
  120. package/packages/dd-trace/src/encode/0.5.js +114 -26
  121. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +57 -42
  122. package/packages/dd-trace/src/encode/agentless-json.js +4 -2
  123. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
  124. package/packages/dd-trace/src/encode/span-stats.js +16 -16
  125. package/packages/dd-trace/src/encode/tags-processors.js +16 -0
  126. package/packages/dd-trace/src/exporters/common/agents.js +3 -1
  127. package/packages/dd-trace/src/exporters/common/request.js +3 -1
  128. package/packages/dd-trace/src/id.js +17 -4
  129. package/packages/dd-trace/src/lambda/handler.js +2 -4
  130. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  131. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  132. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  133. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
  134. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  135. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
  136. package/packages/dd-trace/src/llmobs/sdk.js +10 -16
  137. package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
  138. package/packages/dd-trace/src/llmobs/tagger.js +9 -1
  139. package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
  140. package/packages/dd-trace/src/llmobs/util.js +66 -3
  141. package/packages/dd-trace/src/log/index.js +1 -1
  142. package/packages/dd-trace/src/log/writer.js +3 -1
  143. package/packages/dd-trace/src/msgpack/chunk.js +394 -10
  144. package/packages/dd-trace/src/msgpack/index.js +96 -2
  145. package/packages/dd-trace/src/noop/span.js +3 -1
  146. package/packages/dd-trace/src/openfeature/encoding.js +70 -0
  147. package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
  148. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
  149. package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
  150. package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
  151. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
  152. package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
  153. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  154. package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
  155. package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
  156. package/packages/dd-trace/src/opentracing/span.js +59 -19
  157. package/packages/dd-trace/src/opentracing/span_context.js +49 -0
  158. package/packages/dd-trace/src/plugins/apollo.js +3 -1
  159. package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
  160. package/packages/dd-trace/src/plugins/database.js +7 -6
  161. package/packages/dd-trace/src/plugins/index.js +4 -0
  162. package/packages/dd-trace/src/plugins/log_injection.js +56 -0
  163. package/packages/dd-trace/src/plugins/log_plugin.js +3 -46
  164. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  165. package/packages/dd-trace/src/plugins/plugin.js +15 -17
  166. package/packages/dd-trace/src/plugins/tracing.js +48 -8
  167. package/packages/dd-trace/src/plugins/util/git.js +3 -1
  168. package/packages/dd-trace/src/plugins/util/test.js +318 -13
  169. package/packages/dd-trace/src/plugins/util/web.js +89 -64
  170. package/packages/dd-trace/src/priority_sampler.js +2 -2
  171. package/packages/dd-trace/src/profiling/profiler.js +2 -2
  172. package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
  173. package/packages/dd-trace/src/sampling_rule.js +7 -7
  174. package/packages/dd-trace/src/scope.js +7 -5
  175. package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
  176. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
  177. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  178. package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
  179. package/packages/dd-trace/src/span_format.js +190 -58
  180. package/packages/dd-trace/src/spanleak.js +1 -1
  181. package/packages/dd-trace/src/standalone/index.js +3 -3
  182. package/packages/dd-trace/src/tagger.js +0 -2
  183. package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
  184. package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
  185. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  186. package/vendor/dist/protobufjs/index.js +1 -1
  187. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  188. package/packages/dd-trace/src/msgpack/encoder.js +0 -308
  189. package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
  190. package/vendor/dist/opentracing/LICENSE +0 -201
  191. package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
  192. package/vendor/dist/opentracing/constants.d.ts +0 -61
  193. package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
  194. package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
  195. package/vendor/dist/opentracing/functions.d.ts +0 -20
  196. package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
  197. package/vendor/dist/opentracing/index.d.ts +0 -12
  198. package/vendor/dist/opentracing/index.js +0 -1
  199. package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
  200. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
  201. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
  202. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
  203. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
  204. package/vendor/dist/opentracing/noop.d.ts +0 -8
  205. package/vendor/dist/opentracing/reference.d.ts +0 -33
  206. package/vendor/dist/opentracing/span.d.ts +0 -147
  207. package/vendor/dist/opentracing/span_context.d.ts +0 -26
  208. package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
  209. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
  210. package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
  211. package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
  212. package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
  213. package/vendor/dist/opentracing/tracer.d.ts +0 -127
@@ -289,7 +289,7 @@ function onExpressSession ({ req, res, sessionId, abortController }) {
289
289
  return
290
290
  }
291
291
 
292
- const isSdkCalled = rootSpan.context()._tags['usr.session_id']
292
+ const isSdkCalled = rootSpan.context().getTag('usr.session_id')
293
293
  if (isSdkCalled) return
294
294
 
295
295
  const results = waf.run({
@@ -350,8 +350,15 @@ function onResponseBody ({ req, res, body }) {
350
350
  }
351
351
 
352
352
  function onResponseWriteHead ({ req, res, abortController, statusCode, responseHeaders }) {
353
- if (!isEmpty(responseHeaders)) {
354
- storedResponseHeaders.set(req, responseHeaders)
353
+ // Normalize header names to lowercase so downstream consumers see the same shape
354
+ // regardless of how the caller wrote them.
355
+ const normalizedResponseHeaders = {}
356
+ for (const [key, value] of Object.entries(responseHeaders)) {
357
+ normalizedResponseHeaders[key.toLowerCase()] = value
358
+ }
359
+
360
+ if (!isEmpty(normalizedResponseHeaders)) {
361
+ storedResponseHeaders.set(req, normalizedResponseHeaders)
355
362
  }
356
363
 
357
364
  // TODO: do not call waf if inside block()
@@ -376,7 +383,7 @@ function onResponseWriteHead ({ req, res, abortController, statusCode, responseH
376
383
  const results = waf.run({
377
384
  persistent: {
378
385
  [addresses.HTTP_INCOMING_RESPONSE_CODE]: String(statusCode),
379
- [addresses.HTTP_INCOMING_RESPONSE_HEADERS]: copyHeadersOmitting(responseHeaders, 'set-cookie'),
386
+ [addresses.HTTP_INCOMING_RESPONSE_HEADERS]: copyHeadersOmitting(normalizedResponseHeaders, 'set-cookie'),
380
387
  },
381
388
  }, req)
382
389
 
@@ -50,6 +50,11 @@ const contentHeaderList = [
50
50
  'content-language',
51
51
  ]
52
52
 
53
+ const mandatoryResponseHeaderList = [
54
+ 'content-type',
55
+ 'content-length',
56
+ ]
57
+
53
58
  const responseHeaderList = [
54
59
  ...contentHeaderList,
55
60
  'content-type',
@@ -102,6 +107,8 @@ const EVENT_HEADERS_MAP = mapHeaderAndTags(eventHeadersList, REQUEST_HEADER_TAG_
102
107
 
103
108
  const RESPONSE_HEADERS_MAP = mapHeaderAndTags(responseHeaderList, RESPONSE_HEADER_TAG_PREFIX)
104
109
 
110
+ const MANDATORY_RESPONSE_HEADERS_MAP = mapHeaderAndTags(mandatoryResponseHeaderList, RESPONSE_HEADER_TAG_PREFIX)
111
+
105
112
  const NON_EXTENDED_REQUEST_HEADERS = new Set([...requestHeadersList, ...eventHeadersList])
106
113
  const NON_EXTENDED_RESPONSE_HEADERS = new Set(responseHeaderList)
107
114
  const REDACTED_HEADERS = new Set(redactedHeadersList)
@@ -168,14 +175,21 @@ function getCollectedHeaders (req, res, shouldCollectEventHeaders, storedRespons
168
175
  // Mandatory
169
176
  const mandatoryCollectedHeaders = filterHeaders(req.headers, REQUEST_HEADERS_MAP)
170
177
 
171
- // Basic collection
172
- if (!shouldCollectEventHeaders) return mandatoryCollectedHeaders
173
-
174
178
  // Skip the spread when the stored side is empty -- common during the early
175
179
  // request lifecycle when no upstream response headers have been captured.
180
+ const liveResponseHeaders = res?.getHeaders?.()
176
181
  const responseHeaders = isEmpty(storedResponseHeaders)
177
- ? res.getHeaders()
178
- : { ...storedResponseHeaders, ...res.getHeaders() }
182
+ ? (liveResponseHeaders ?? {})
183
+ : (liveResponseHeaders ? { ...storedResponseHeaders, ...liveResponseHeaders } : storedResponseHeaders)
184
+
185
+ // content-type and content-length are always reported when appsec is enabled,
186
+ // even without a security event.
187
+ if (!shouldCollectEventHeaders) {
188
+ return Object.assign(
189
+ mandatoryCollectedHeaders,
190
+ filterHeaders(responseHeaders, MANDATORY_RESPONSE_HEADERS_MAP)
191
+ )
192
+ }
179
193
 
180
194
  const requestEventCollectedHeaders = filterHeaders(req.headers, EVENT_HEADERS_MAP)
181
195
  const responseEventCollectedHeaders = filterHeaders(responseHeaders, RESPONSE_HEADERS_MAP)
@@ -347,18 +361,18 @@ function reportAttack ({ events: attackData, actions }, req) {
347
361
  const rootSpan = web.root(req)
348
362
  if (!rootSpan) return
349
363
 
350
- const currentTags = rootSpan.context()._tags
364
+ const spanContext = rootSpan.context()
351
365
 
352
366
  const newTags = {
353
367
  'appsec.event': 'true',
354
368
  }
355
369
 
356
370
  // TODO: maybe add this to format.js later (to take decision as late as possible)
357
- if (!currentTags['_dd.origin']) {
371
+ if (!spanContext.getTag('_dd.origin')) {
358
372
  newTags['_dd.origin'] = 'appsec'
359
373
  }
360
374
 
361
- const currentJson = currentTags['_dd.appsec.json']
375
+ const currentJson = spanContext.getTag('_dd.appsec.json')
362
376
 
363
377
  // merge JSON arrays without parsing them
364
378
  const attackDataStr = JSON.stringify(attackData)
@@ -455,8 +469,7 @@ function reportRequestBody (rootSpan, requestBody, comesFromRaspAction = false)
455
469
 
456
470
  if (rootSpan.meta_struct['http.request.body']) {
457
471
  // If the rasp.exceed metric exists, set also the same for the new tag
458
- const currentTags = rootSpan.context()._tags
459
- const sizeExceedTagValue = currentTags['_dd.appsec.rasp.request_body_size.exceeded']
472
+ const sizeExceedTagValue = rootSpan.context().getTag('_dd.appsec.rasp.request_body_size.exceeded')
460
473
 
461
474
  if (sizeExceedTagValue) {
462
475
  rootSpan.setTag('_dd.appsec.request_body_size.exceeded', sizeExceedTagValue)
@@ -558,7 +571,7 @@ function finishRequest (req, res, storedResponseHeaders, requestBody) {
558
571
 
559
572
  incrementWafRequestsMetric(req)
560
573
 
561
- const tags = rootSpan.context()._tags
574
+ const tags = rootSpan.context().getTags()
562
575
 
563
576
  const extendedDataCollection = extendedDataCollectionRequest.get(req)
564
577
  const newTags = getCollectedHeaders(
@@ -22,7 +22,7 @@ function checkUserAndSetUser (tracer, user) {
22
22
 
23
23
  const rootSpan = getRootSpan()
24
24
  if (rootSpan) {
25
- if (!rootSpan.context()._tags['usr.id']) {
25
+ if (!rootSpan.context().getTag('usr.id')) {
26
26
  setUserTags(user, rootSpan)
27
27
  }
28
28
  } else {
@@ -18,7 +18,7 @@ function getRootSpan () {
18
18
 
19
19
  parentId = pContext._parentId
20
20
 
21
- if (!pContext._tags?._inferred_span) {
21
+ if (!pContext.getTag('_inferred_span')) {
22
22
  span = parent
23
23
  }
24
24
  }
@@ -91,12 +91,13 @@ function trackLogin (framework, login, user, success, rootSpan) {
91
91
  [addresses.USER_LOGIN]: login,
92
92
  }
93
93
 
94
- const currentTags = rootSpan.context()._tags
95
- const isSdkCalled = currentTags[`_dd.appsec.events.users.login.${success ? 'success' : 'failure'}.sdk`] === 'true'
94
+ const spanContext = rootSpan.context()
95
+ const sdkTag = `_dd.appsec.events.users.login.${success ? 'success' : 'failure'}.sdk`
96
+ const isSdkCalled = spanContext.getTag(sdkTag) === 'true'
96
97
 
97
98
  // used to not overwrite tags set by SDK
98
99
  function shouldSetTag (tag) {
99
- return !(isSdkCalled && currentTags[tag])
100
+ return !(isSdkCalled && spanContext.getTag(tag))
100
101
  }
101
102
 
102
103
  if (success) {
@@ -167,7 +168,7 @@ function trackUser (user, rootSpan) {
167
168
 
168
169
  rootSpan.setTag('_dd.appsec.usr.id', userId)
169
170
 
170
- const isSdkCalled = rootSpan.context()._tags['_dd.appsec.user.collection_mode'] === 'sdk'
171
+ const isSdkCalled = rootSpan.context().getTag('_dd.appsec.user.collection_mode') === 'sdk'
171
172
  // do not override SDK
172
173
  if (!isSdkCalled) {
173
174
  rootSpan.addTags({
@@ -62,7 +62,13 @@ function removeBaggageItem (keyToRemove) {
62
62
  }
63
63
 
64
64
  function removeAllBaggageItems () {
65
- baggageStorage.enterWith(EMPTY_STORE)
65
+ // Skip `enterWith` (a real ALS frame switch) when the store is already
66
+ // the empty sentinel. Entry-point services without active baggage hit this
67
+ // on every extract.
68
+ const store = baggageStorage.getStore()
69
+ if (store !== undefined && store !== EMPTY_STORE) {
70
+ baggageStorage.enterWith(EMPTY_STORE)
71
+ }
66
72
  return EMPTY_STORE
67
73
  }
68
74
 
@@ -236,7 +236,6 @@ class CiVisibilityExporter extends BufferingExporter {
236
236
  testManagementAttemptToFixRetries ?? this._config.testManagementAttemptToFixRetries,
237
237
  isImpactedTestsEnabled: isImpactedTestsEnabled && this._config.isImpactedTestsEnabled,
238
238
  isCoverageReportUploadEnabled,
239
- DD_TEST_TIA_KEEP_COV_CONFIG: this._config.DD_TEST_TIA_KEEP_COV_CONFIG,
240
239
  }
241
240
  }
242
241
 
@@ -31,10 +31,11 @@ function getSkippableSuites ({
31
31
  runtimeVersion,
32
32
  custom,
33
33
  testLevel = 'suite',
34
+ isCoverageReportUploadEnabled = false,
34
35
  }, done) {
35
36
  const cacheKey = buildCacheKey('skippable', [
36
37
  sha, service, env, repositoryUrl, osPlatform, osVersion, osArchitecture,
37
- runtimeName, runtimeVersion, testLevel, custom,
38
+ runtimeName, runtimeVersion, testLevel, custom, isCoverageReportUploadEnabled,
38
39
  ])
39
40
 
40
41
  withCache(cacheKey, (activeCacheKey, cb) => {
@@ -54,11 +55,12 @@ function getSkippableSuites ({
54
55
  runtimeVersion,
55
56
  custom,
56
57
  testLevel,
58
+ isCoverageReportUploadEnabled,
57
59
  cacheKey: activeCacheKey,
58
60
  }, cb)
59
61
  }, (err, data) => {
60
62
  if (err) return done(err)
61
- done(null, data.skippableSuites, data.correlationId)
63
+ done(null, data.skippableSuites, data.correlationId, data.coverage)
62
64
  })
63
65
  }
64
66
 
@@ -81,6 +83,7 @@ function getSkippableSuites ({
81
83
  * @param {string} params.runtimeVersion
82
84
  * @param {object} [params.custom]
83
85
  * @param {string} [params.testLevel]
86
+ * @param {boolean} [params.isCoverageReportUploadEnabled]
84
87
  * @param {string | null} params.cacheKey
85
88
  * @param {Function} done
86
89
  */
@@ -100,6 +103,7 @@ function fetchFromApi ({
100
103
  runtimeVersion,
101
104
  custom,
102
105
  testLevel,
106
+ isCoverageReportUploadEnabled,
103
107
  cacheKey,
104
108
  }, done) {
105
109
  const options = {
@@ -148,7 +152,6 @@ function fetchFromApi ({
148
152
  },
149
153
  },
150
154
  })
151
-
152
155
  incrementCountMetric(TELEMETRY_ITR_SKIPPABLE_TESTS)
153
156
 
154
157
  const startTime = Date.now()
@@ -161,27 +164,36 @@ function fetchFromApi ({
161
164
  } else {
162
165
  try {
163
166
  const parsedResponse = JSON.parse(res)
164
- const skippableSuites = parsedResponse
167
+ const coverage = parsedResponse.meta?.coverage || {}
168
+
169
+ const skippableItems = parsedResponse
165
170
  .data
166
171
  .filter(({ type }) => type === testLevel)
167
- .map(({ attributes: { suite, name } }) => {
168
- if (testLevel === 'suite') {
169
- return suite
170
- }
171
- return { suite, name }
172
- })
173
- const { meta: { correlation_id: correlationId } } = parsedResponse
172
+ const skippableSuites = []
173
+ for (const {
174
+ attributes: {
175
+ suite,
176
+ name,
177
+ _is_missing_line_code_coverage: isMissingLineCodeCoverage,
178
+ },
179
+ } of skippableItems) {
180
+ // Only reject candidates without backend line coverage when we need that coverage to backfill reports.
181
+ if (isCoverageReportUploadEnabled && isMissingLineCodeCoverage) continue
182
+
183
+ skippableSuites.push(testLevel === 'suite' ? suite : { suite, name })
184
+ }
185
+ const correlationId = parsedResponse.meta?.correlation_id
174
186
  incrementCountMetric(
175
187
  testLevel === 'test'
176
188
  ? TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS
177
189
  : TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_SUITES,
178
190
  {},
179
- skippableSuites.length
191
+ skippableItems.length
180
192
  )
181
193
  distributionMetric(TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES, {}, res.length)
182
194
  log.debug('Number of received skippable %ss:', testLevel, skippableSuites.length)
183
195
 
184
- const result = { skippableSuites, correlationId }
196
+ const result = { skippableSuites, correlationId, coverage }
185
197
  writeToCache(cacheKey, result)
186
198
 
187
199
  done(null, result)
@@ -14,6 +14,8 @@ const {
14
14
  } = require('../../exporters/common/retry')
15
15
  const { urlToHttpOptions } = require('../../exporters/common/url-to-http-options-polyfill')
16
16
 
17
+ const legacyStorage = storage('legacy')
18
+
17
19
  function parseUrl (urlObjOrString) {
18
20
  if (urlObjOrString !== null && typeof urlObjOrString === 'object') {
19
21
  return urlToHttpOptions(urlObjOrString)
@@ -75,7 +77,7 @@ function request (data, options, callback) {
75
77
  let firstStatusCode = null
76
78
 
77
79
  const makeRequest = () => {
78
- storage('legacy').run({ noop: true }, () => {
80
+ legacyStorage.run({ noop: true }, () => {
79
81
  const req = client.request(opts, (res) => {
80
82
  // Capture non-2xx status code as soon as we see it so telemetry preserves it if the retry
81
83
  // fails with a network error (no HTTP response) before 'end' fires
@@ -8,6 +8,8 @@ const {
8
8
  } = require('../../plugins/util/test')
9
9
  const { storage } = require('../../../../datadog-core')
10
10
 
11
+ const legacyStorage = storage('legacy')
12
+
11
13
  class TestApiManualPlugin extends CiPlugin {
12
14
  static id = 'test-api-manual'
13
15
 
@@ -17,13 +19,13 @@ class TestApiManualPlugin extends CiPlugin {
17
19
  this.sourceRoot = process.cwd()
18
20
 
19
21
  this.unconfiguredAddSub('dd-trace:ci:manual:test:start', ({ testName, testSuite }) => {
20
- const store = storage('legacy').getStore()
22
+ const store = legacyStorage.getStore()
21
23
  const testSuiteRelative = getTestSuitePath(testSuite, this.sourceRoot)
22
24
  const testSpan = this.startTestSpan(testName, testSuiteRelative)
23
25
  this.enter(testSpan, store)
24
26
  })
25
27
  this.unconfiguredAddSub('dd-trace:ci:manual:test:finish', ({ status, error }) => {
26
- const store = storage('legacy').getStore()
28
+ const store = legacyStorage.getStore()
27
29
  const testSpan = store && store.span
28
30
  if (testSpan) {
29
31
  testSpan.setTag(TEST_STATUS, status)
@@ -35,7 +37,7 @@ class TestApiManualPlugin extends CiPlugin {
35
37
  }
36
38
  })
37
39
  this.unconfiguredAddSub('dd-trace:ci:manual:test:addTags', (tags) => {
38
- const store = storage('legacy').getStore()
40
+ const store = legacyStorage.getStore()
39
41
  const testSpan = store && store.span
40
42
  if (testSpan) {
41
43
  testSpan.addTags(tags)
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { writeFileSync } = require('node:fs')
3
+ const { existsSync, readFileSync, writeFileSync } = require('node:fs')
4
4
  const { tmpdir } = require('node:os')
5
5
  const { randomUUID } = require('node:crypto')
6
6
  const path = require('node:path')
@@ -8,6 +8,9 @@ const path = require('node:path')
8
8
  const { getValueFromEnvSources } = require('../config/helper')
9
9
  const log = require('../log')
10
10
 
11
+ const COVERAGE_BACKFILL_KEY = '_ddCoverageBackfill'
12
+ const COVERAGE_BACKFILL_ROOT_DIR_KEY = '_ddCoverageBackfillRootDir'
13
+
11
14
  /**
12
15
  * Gets the test optimization settings cache file path from the env var.
13
16
  * @returns {string|undefined} The cache file path, or undefined if not set.
@@ -36,26 +39,87 @@ function setupSettingsCachePath () {
36
39
  }
37
40
 
38
41
  /**
39
- * Writes the settings to the cache file specified by DD_EXPERIMENTAL_TEST_OPT_SETTINGS_CACHE.
40
- * Does nothing if the env var is not set.
41
- * @param {object} settings - The settings object to cache.
42
+ * Reads the shared test optimization cache file.
43
+ * @returns {object} Cached settings and metadata.
42
44
  */
43
- function writeSettingsToCache (settings) {
45
+ function readCacheFile () {
46
+ const settingsCachePath = getSettingsCachePath()
47
+ if (!settingsCachePath || !existsSync(settingsCachePath)) {
48
+ return {}
49
+ }
50
+
51
+ try {
52
+ return JSON.parse(readFileSync(settingsCachePath, 'utf8'))
53
+ } catch (err) {
54
+ log.debug('Failed to read settings cache: %s', err.message)
55
+ return {}
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Writes the shared test optimization cache file.
61
+ * @param {object} cache - Cached settings and metadata.
62
+ */
63
+ function writeCacheFile (cache) {
44
64
  const settingsCachePath = getSettingsCachePath()
45
65
  if (!settingsCachePath) {
46
66
  return
47
67
  }
48
68
 
49
69
  try {
50
- writeFileSync(settingsCachePath, JSON.stringify(settings), 'utf8')
70
+ writeFileSync(settingsCachePath, JSON.stringify(cache), 'utf8')
51
71
  log.debug('Settings written to %s', settingsCachePath)
52
72
  } catch (err) {
53
73
  log.error('Failed to write settings to cache file', err)
54
74
  }
55
75
  }
56
76
 
77
+ /**
78
+ * Writes the settings to the cache file specified by DD_EXPERIMENTAL_TEST_OPT_SETTINGS_CACHE.
79
+ * Does nothing if the env var is not set.
80
+ * @param {object} settings - The settings object to cache.
81
+ */
82
+ function writeSettingsToCache (settings) {
83
+ writeCacheFile({
84
+ ...readCacheFile(),
85
+ ...settings,
86
+ })
87
+ }
88
+
89
+ /**
90
+ * Writes TIA coverage backfill to the shared nyc settings cache.
91
+ * @param {object} coverage - Repository-relative coverage bitmaps by filename.
92
+ * @param {string} [rootDir] - Root directory that coverage filenames are relative to.
93
+ */
94
+ function writeCoverageBackfillToCache (coverage, rootDir) {
95
+ writeCacheFile({
96
+ ...readCacheFile(),
97
+ [COVERAGE_BACKFILL_KEY]: coverage,
98
+ [COVERAGE_BACKFILL_ROOT_DIR_KEY]: rootDir,
99
+ })
100
+ }
101
+
102
+ /**
103
+ * Reads TIA coverage backfill from the shared nyc settings cache.
104
+ * @returns {object|undefined} Repository-relative coverage bitmaps by filename.
105
+ */
106
+ function readCoverageBackfillFromCache () {
107
+ return readCacheFile()[COVERAGE_BACKFILL_KEY]
108
+ }
109
+
110
+ /**
111
+ * Reads TIA coverage backfill root directory from the shared nyc settings cache.
112
+ * @returns {string|undefined} Root directory that cached coverage filenames are relative to.
113
+ */
114
+ function readCoverageBackfillRootDirFromCache () {
115
+ return readCacheFile()[COVERAGE_BACKFILL_ROOT_DIR_KEY]
116
+ }
117
+
57
118
  module.exports = {
58
119
  getSettingsCachePath,
120
+ readCoverageBackfillFromCache,
121
+ readCoverageBackfillRootDirFromCache,
59
122
  setupSettingsCachePath,
123
+ writeCoverageBackfillToCache,
60
124
  writeSettingsToCache,
61
125
  }
@@ -65,7 +65,7 @@ export interface GeneratedConfig {
65
65
  dbm: {
66
66
  injectSqlBaseHash: boolean;
67
67
  };
68
- dbmPropagationMode: string;
68
+ dbmPropagationMode: "disabled" | "service" | "full" | "dynamic_service";
69
69
  DD_ACTION_EXECUTION_ID: string | undefined;
70
70
  DD_AGENTLESS_LOG_SUBMISSION_ENABLED: boolean;
71
71
  DD_AGENTLESS_LOG_SUBMISSION_URL: string | undefined;
@@ -162,7 +162,6 @@ export interface GeneratedConfig {
162
162
  DD_TEST_FLEET_CONFIG_PATH: string | undefined;
163
163
  DD_TEST_LOCAL_CONFIG_PATH: string | undefined;
164
164
  DD_TEST_SESSION_NAME: string | undefined;
165
- DD_TEST_TIA_KEEP_COV_CONFIG: boolean;
166
165
  DD_TRACE_AEROSPIKE_ENABLED: boolean;
167
166
  DD_TRACE_AI_ENABLED: boolean;
168
167
  DD_TRACE_AMQP10_ENABLED: boolean;
@@ -211,6 +210,7 @@ export interface GeneratedConfig {
211
210
  DD_TRACE_AWS_SDK_STEPFUNCTIONS_BATCH_PROPAGATION_ENABLED: boolean;
212
211
  DD_TRACE_AWS_SDK_STEPFUNCTIONS_ENABLED: boolean;
213
212
  DD_TRACE_AXIOS_ENABLED: boolean;
213
+ DD_TRACE_AZURE_COSMOS_ENABLED: boolean;
214
214
  DD_TRACE_AZURE_DURABLE_FUNCTIONS_ENABLED: boolean;
215
215
  DD_TRACE_AZURE_EVENT_HUBS_ENABLED: boolean;
216
216
  DD_TRACE_AZURE_EVENTHUBS_BATCH_LINKS_ENABLED: boolean;
@@ -324,12 +324,14 @@ export interface GeneratedConfig {
324
324
  DD_TRACE_MONGODB_CORE_ENABLED: boolean;
325
325
  DD_TRACE_MONGODB_ENABLED: boolean;
326
326
  DD_TRACE_MONGODB_HEARTBEAT_ENABLED: boolean;
327
+ DD_TRACE_MONGODB_OBFUSCATE_QUERY: "none" | "types" | "redact";
327
328
  DD_TRACE_MONGOOSE_ENABLED: boolean;
328
329
  DD_TRACE_MQUERY_ENABLED: boolean;
329
330
  DD_TRACE_MULTER_ENABLED: boolean;
330
331
  DD_TRACE_MYSQL_ENABLED: boolean;
331
332
  DD_TRACE_MYSQL2_ENABLED: boolean;
332
333
  DD_TRACE_NATIVE_SPAN_EVENTS: boolean;
334
+ DD_TRACE_NATS_ENABLED: boolean;
333
335
  DD_TRACE_NET_ENABLED: boolean;
334
336
  DD_TRACE_NEXT_ENABLED: boolean;
335
337
  DD_TRACE_NODE_CHILD_PROCESS_ENABLED: boolean;
@@ -427,6 +429,9 @@ export interface GeneratedConfig {
427
429
  flaggingProvider: {
428
430
  enabled: boolean;
429
431
  initializationTimeoutMs: number;
432
+ spanEnrichment: {
433
+ enabled: boolean;
434
+ };
430
435
  };
431
436
  };
432
437
  flakyTestRetriesCount: number;
@@ -640,7 +640,9 @@
640
640
  "configurationNames": [
641
641
  "dbmPropagationMode"
642
642
  ],
643
- "default": "disabled"
643
+ "default": "disabled",
644
+ "allowed": "disabled|service|full|dynamic_service",
645
+ "transform": "toLowerCase"
644
646
  }
645
647
  ],
646
648
  "DD_DOGSTATSD_HOST": [
@@ -773,6 +775,16 @@
773
775
  "default": "false"
774
776
  }
775
777
  ],
778
+ "DD_EXPERIMENTAL_FLAGGING_PROVIDER_SPAN_ENRICHMENT_ENABLED": [
779
+ {
780
+ "implementation": "A",
781
+ "type": "boolean",
782
+ "configurationNames": [
783
+ "experimental.flaggingProvider.spanEnrichment.enabled"
784
+ ],
785
+ "default": "false"
786
+ }
787
+ ],
776
788
  "DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED": [
777
789
  {
778
790
  "implementation": "B",
@@ -1773,13 +1785,6 @@
1773
1785
  "internalPropertyName": "isTestManagementEnabled"
1774
1786
  }
1775
1787
  ],
1776
- "DD_TEST_TIA_KEEP_COV_CONFIG": [
1777
- {
1778
- "implementation": "A",
1779
- "type": "boolean",
1780
- "default": "false"
1781
- }
1782
- ],
1783
1788
  "DD_TEST_SESSION_NAME": [
1784
1789
  {
1785
1790
  "implementation": "A",
@@ -2176,6 +2181,13 @@
2176
2181
  "default": "true"
2177
2182
  }
2178
2183
  ],
2184
+ "DD_TRACE_AZURE_COSMOS_ENABLED": [
2185
+ {
2186
+ "implementation": "A",
2187
+ "type": "boolean",
2188
+ "default": "true"
2189
+ }
2190
+ ],
2179
2191
  "DD_TRACE_AZURE_DURABLE_FUNCTIONS_ENABLED": [
2180
2192
  {
2181
2193
  "implementation": "B",
@@ -3133,6 +3145,15 @@
3133
3145
  "default": "true"
3134
3146
  }
3135
3147
  ],
3148
+ "DD_TRACE_MONGODB_OBFUSCATE_QUERY": [
3149
+ {
3150
+ "implementation": "A",
3151
+ "type": "string",
3152
+ "default": "none",
3153
+ "allowed": "none|types|redact",
3154
+ "transform": "toLowerCase"
3155
+ }
3156
+ ],
3136
3157
  "DD_TRACE_MONGOOSE_ENABLED": [
3137
3158
  {
3138
3159
  "implementation": "A",
@@ -3175,6 +3196,13 @@
3175
3196
  "default": "false"
3176
3197
  }
3177
3198
  ],
3199
+ "DD_TRACE_NATS_ENABLED": [
3200
+ {
3201
+ "implementation": "A",
3202
+ "type": "boolean",
3203
+ "default": "false"
3204
+ }
3205
+ ],
3178
3206
  "DD_TRACE_NET_ENABLED": [
3179
3207
  {
3180
3208
  "implementation": "A",
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { EOL } = require('node:os')
4
+
3
5
  // Load binding first to not import other modules if it throws
4
6
  const libdatadog = require('@datadog/libdatadog')
5
7
  const binding = libdatadog.load('crashtracker')
@@ -29,19 +31,29 @@ class Crashtracker {
29
31
  start (config) {
30
32
  if (this.#started) return this.configure(config)
31
33
 
32
- this.#started = true
33
-
34
34
  try {
35
35
  binding.init(
36
36
  this.#getConfig(config),
37
37
  this.#getReceiverConfig(),
38
38
  this.#getMetadata(config)
39
39
  )
40
+ this.#started = true
41
+ this.#trackUnhandledExceptions()
40
42
  } catch (e) {
41
43
  log.error('Error initializing crashtracker', e)
42
44
  }
43
45
  }
44
46
 
47
+ #trackUnhandledExceptions () {
48
+ process.once('uncaughtExceptionMonitor', (error, origin) => {
49
+ try {
50
+ binding.reportUncaughtExceptionMonitor(error, origin)
51
+ } catch (e) {
52
+ process.stderr.write(`Error reporting uncaught exception to crashtracker: ${e.toString()}${EOL}`)
53
+ }
54
+ })
55
+ }
56
+
45
57
  withProfilerSerializing (f) {
46
58
  binding.beginProfilerSerializing()
47
59
  try {
@@ -58,7 +70,7 @@ class Crashtracker {
58
70
  #getConfig (config) {
59
71
  const url = getAgentUrl(config)
60
72
 
61
- // Out-of-process symbolication currently (crashtracker 27.0.0) works on
73
+ // Out-of-process symbolication currently works on
62
74
  // Linux only, does not work on Mac.
63
75
  const resolveMode = require('os').platform === 'linux'
64
76
  ? 'EnabledWithSymbolsInReceiver'
@@ -3,15 +3,17 @@
3
3
  const { storage } = require('../../../datadog-core')
4
4
  const log = require('../log')
5
5
 
6
+ const legacyStorage = storage('legacy')
7
+
6
8
  function getDataStreamsContext () {
7
- const store = storage('legacy').getStore()
9
+ const store = legacyStorage.getStore()
8
10
  return (store && store.dataStreamsContext) || null
9
11
  }
10
12
 
11
13
  function setDataStreamsContext (dataStreamsContext) {
12
14
  log.debug('Setting new DSM Context: %j.', dataStreamsContext)
13
15
 
14
- if (dataStreamsContext) storage('legacy').enterWith({ ...(storage('legacy').getStore()), dataStreamsContext })
16
+ if (dataStreamsContext) legacyStorage.enterWith({ ...legacyStorage.getStore(), dataStreamsContext })
15
17
  }
16
18
 
17
19
  module.exports = {