dd-trace 6.13.0 → 6.15.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
@@ -11,13 +11,15 @@ const path = require('path')
11
11
  const satisfies = require('../../../vendor/dist/semifies')
12
12
  const { DD_MAJOR } = require('../../../version')
13
13
  const shimmer = require('../../datadog-shimmer')
14
- const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
14
+ const { getEnvironmentVariable, getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
15
15
  const log = require('../../dd-trace/src/log')
16
16
  const {
17
17
  EMPTY_EFD_RETRY_POLICY,
18
18
  getEfdRetryCountForDuration,
19
19
  hasEfdRetries,
20
20
  } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
21
+ const { FINAL_FLUSH_FALLBACK_DELAY, FINAL_FLUSH_TIMEOUT } =
22
+ require('../../dd-trace/src/ci-visibility/final-flush')
21
23
  const {
22
24
  getCoveredFilesFromCoverage,
23
25
  JEST_WORKER_TRACE_PAYLOAD_CODE,
@@ -62,6 +64,7 @@ const { addHook, channel } = require('./helpers/instrument')
62
64
  const testSessionStartCh = channel('ci:jest:session:start')
63
65
  const testSessionFinishCh = channel('ci:jest:session:finish')
64
66
  const codeCoverageReportCh = channel('ci:jest:coverage-report')
67
+ const bundlerLoadCh = channel('dd-trace:bundler:load')
65
68
 
66
69
  const testSessionConfigurationCh = channel('ci:jest:session:configuration')
67
70
 
@@ -95,10 +98,10 @@ const itrSkippedSuitesCh = channel('ci:jest:itr:skipped-suites')
95
98
  // https://github.com/jestjs/jest/blob/1d682f21c7a35da4d3ab3a1436a357b980ebd0fa/packages/jest-worker/src/types.ts#L37
96
99
  const CHILD_MESSAGE_CALL = 1
97
100
 
98
- // Maximum time we'll wait for the tracer to flush
99
- // The exporter has a 10-second bounded final-flush deadline. Leave enough time
100
- // for its completion callback before Jest's --forceExit fallback takes over.
101
- const FLUSH_TIMEOUT = 12_000
101
+ // Maximum time we'll wait for the tracer to flush.
102
+ // Let the exporter enforce its hard deadline and invoke its completion callback
103
+ // before Jest's --forceExit fallback takes over.
104
+ const FLUSH_TIMEOUT = FINAL_FLUSH_TIMEOUT + FINAL_FLUSH_FALLBACK_DELAY + 5000
102
105
  const JEST_SESSION_STATE = Symbol.for('dd-trace:jest:session')
103
106
  const JEST_BAIL_REPORTER_PATH = require.resolve('./jest/bail-reporter')
104
107
  const DD_JEST_HANDLE_TEST_EVENT_WRAPPED = Symbol('dd-trace:jest:handle-test-event-wrapped')
@@ -177,7 +180,9 @@ const wrappedJestEsmLoaders = new WeakSet()
177
180
  const wrappedJestObjects = new WeakSet()
178
181
  const wrappedWorkerInitializers = new WeakSet()
179
182
  const publishedRuntimeReferenceErrors = new WeakMap()
180
- const jestEsmBypassModulePathsByRuntime = new WeakMap()
183
+ const jestEsmLoggingModulePathsByRuntime = new WeakMap()
184
+ const jestLoggingPackagesByRuntime = new WeakMap()
185
+ const instrumentedJestLoggingModules = new WeakMap()
181
186
  const wrappedCoverageReporters = new WeakSet()
182
187
  const coverageReporterRequires = new WeakMap()
183
188
  const handledJestEvents = new WeakSet()
@@ -342,16 +347,17 @@ function getTestStats (testStatuses) {
342
347
  function formatIgnoredFailuresSummary (ignoredFailures) {
343
348
  if (!ignoredFailures?.efdFailureCount) return ''
344
349
 
345
- const items = ignoredFailures.efdNames.map(text => ({ text, suffix: 'Early Flake Detection' }))
346
-
347
- if (items.length === 0) return ''
348
-
349
- const shown = items.slice(0, MAX_IGNORED_TEST_NAMES)
350
- const more = items.length - shown.length
350
+ const shown = ignoredFailures.efdNames.slice(0, MAX_IGNORED_TEST_NAMES)
351
+ const more = ignoredFailures.efdNames.length - shown.length
351
352
  const moreSuffix = more > 0 ? `\n ... and ${more} more` : ''
352
- const formattedItems = shown
353
- .map(({ text, suffix }) => ` ${text}${suffix ? ` (${suffix})` : ''}`)
354
- .join('\n') + moreSuffix
353
+ let formattedItems = ''
354
+ let isFirstItem = true
355
+ for (const text of shown) {
356
+ if (!isFirstItem) formattedItems += '\n'
357
+ formattedItems += ` • ${text} (Early Flake Detection)`
358
+ isFirstItem = false
359
+ }
360
+ formattedItems += moreSuffix
355
361
 
356
362
  return `${ignoredFailures.efdFailureCount} test failure(s) were ignored. Exit code set to 0.\n\n${formattedItems}`
357
363
  }
@@ -764,7 +770,8 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
764
770
  }
765
771
  return test.call(this, testName, testFn, ...callArgs)
766
772
  }
767
- const eachBind = bind(eachTest).apply(this, eachArgs)
773
+ const boundTest = bind(eachTest)
774
+ const eachBind = boundTest.apply(this, eachArgs)
768
775
  return eachBind.apply(this, testArgs)
769
776
  }
770
777
  }
@@ -877,7 +884,8 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
877
884
  }
878
885
  return concurrentTest.call(this, testName, testFn, ...callArgs)
879
886
  }
880
- const eachBind = bind(concurrentEachTest, false, needsEachError).apply(this, eachArgs)
887
+ const boundTest = bind(concurrentEachTest, false, needsEachError)
888
+ const eachBind = boundTest.apply(this, eachArgs)
881
889
  return eachBind.apply(this, testArgs)
882
890
  }
883
891
  }
@@ -926,10 +934,12 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
926
934
 
927
935
  let jestEach
928
936
  try {
929
- jestEach = createRequire(path.join(this.rootDir, 'package.json'))('jest-each')
937
+ const requireFromPath = createRequire(path.join(this.rootDir, 'package.json'))
938
+ jestEach = requireFromPath('jest-each')
930
939
  } catch {
931
940
  try {
932
- jestEach = createRequire(path.join(process.cwd(), 'package.json'))('jest-each')
941
+ const requireFromPath = createRequire(path.join(process.cwd(), 'package.json'))
942
+ jestEach = requireFromPath('jest-each')
933
943
  } catch {
934
944
  jestEach = undefined
935
945
  }
@@ -3067,9 +3077,7 @@ function getCliWrapper (isNewJestVersion) {
3067
3077
  result = await runCLI.apply(this, arguments)
3068
3078
  } catch (error) {
3069
3079
  try {
3070
- await waitForTestSessionFinish(getTestSessionFinishPayload('fail', error, {
3071
- isTestSessionFinalizationError: true,
3072
- }))
3080
+ await waitForTestSessionFinish(getTestSessionFinishPayload('fail', error))
3073
3081
  } catch (finalizationError) {
3074
3082
  log.error('Jest test session finalization error: %s', finalizationError)
3075
3083
  }
@@ -3728,13 +3736,15 @@ if (DD_MAJOR < 6) {
3728
3736
  }, jestConfigSyncWrapper)
3729
3737
  }
3730
3738
 
3731
- const LOGGING_LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = new Set([
3739
+ const JEST_LOGGING_LIBRARIES = new Set([
3732
3740
  'bunyan',
3733
3741
  'pino',
3734
3742
  'winston',
3735
3743
  ])
3744
+ const disabledJestInstrumentations = new Set(
3745
+ getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS')?.split(',')
3746
+ )
3736
3747
  const LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = new Set([
3737
- ...LOGGING_LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE,
3738
3748
  'selenium-webdriver',
3739
3749
  'selenium-webdriver/chrome',
3740
3750
  'selenium-webdriver/edge',
@@ -3879,13 +3889,17 @@ function requireOutsideJestRequireEngine (runtime, moduleName) {
3879
3889
  * @param {string} moduleName
3880
3890
  * @returns {void}
3881
3891
  */
3882
- function recordJestEsmBypassModulePath (runtime, from, moduleName) {
3883
- if (typeof from !== 'string' || !LOGGING_LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) return
3892
+ function recordJestEsmLoggingModulePath (runtime, from, moduleName) {
3893
+ if (
3894
+ typeof from !== 'string' ||
3895
+ !JEST_LOGGING_LIBRARIES.has(moduleName) ||
3896
+ disabledJestInstrumentations.has(moduleName)
3897
+ ) return
3884
3898
 
3885
- let pathsByParent = jestEsmBypassModulePathsByRuntime.get(runtime)
3899
+ let pathsByParent = jestEsmLoggingModulePathsByRuntime.get(runtime)
3886
3900
  if (!pathsByParent) {
3887
3901
  pathsByParent = new Map()
3888
- jestEsmBypassModulePathsByRuntime.set(runtime, pathsByParent)
3902
+ jestEsmLoggingModulePathsByRuntime.set(runtime, pathsByParent)
3889
3903
  }
3890
3904
 
3891
3905
  let modulePaths = pathsByParent.get(from)
@@ -3906,16 +3920,15 @@ function recordJestEsmBypassModulePath (runtime, from, moduleName) {
3906
3920
  * @param {object} runtime
3907
3921
  * @param {string} from
3908
3922
  * @param {string} modulePath
3909
- * @returns {boolean}
3923
+ * @returns {string | undefined}
3910
3924
  */
3911
- function hasJestEsmBypassModulePath (runtime, from, modulePath) {
3912
- const modulePaths = jestEsmBypassModulePathsByRuntime.get(runtime)?.get(from)
3913
- if (!modulePaths) return false
3925
+ function getJestEsmLoggingModuleName (runtime, from, modulePath) {
3926
+ const modulePaths = jestEsmLoggingModulePathsByRuntime.get(runtime)?.get(from)
3927
+ if (!modulePaths) return
3914
3928
 
3915
- for (const resolvedPath of modulePaths.values()) {
3916
- if (resolvedPath === modulePath) return true
3929
+ for (const [moduleName, resolvedPath] of modulePaths) {
3930
+ if (resolvedPath === modulePath) return moduleName
3917
3931
  }
3918
- return false
3919
3932
  }
3920
3933
 
3921
3934
  /**
@@ -3929,7 +3942,7 @@ function wrapJestEsmLoader (runtime) {
3929
3942
  wrappedJestEsmLoaders.add(esmLoader)
3930
3943
  if (typeof esmLoader.resolveModule === 'function') {
3931
3944
  shimmer.wrap(esmLoader, 'resolveModule', resolveModule => function (moduleName, from) {
3932
- recordJestEsmBypassModulePath(runtime, from, moduleName)
3945
+ recordJestEsmLoggingModulePath(runtime, from, moduleName)
3933
3946
  return resolveModule.apply(this, arguments)
3934
3947
  })
3935
3948
  }
@@ -3938,7 +3951,7 @@ function wrapJestEsmLoader (runtime) {
3938
3951
  esmLoader,
3939
3952
  'resolveSpecifierForSyncGraph',
3940
3953
  resolveSpecifier => function (from, moduleName) {
3941
- recordJestEsmBypassModulePath(runtime, from, moduleName)
3954
+ recordJestEsmLoggingModulePath(runtime, from, moduleName)
3942
3955
  return resolveSpecifier.apply(this, arguments)
3943
3956
  }
3944
3957
  )
@@ -3955,11 +3968,10 @@ function getJestBypassModulePath (runtime, from, moduleName) {
3955
3968
  if (typeof from !== 'string' || typeof moduleName !== 'string') return
3956
3969
 
3957
3970
  if (!LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
3958
- // Jest passes the resolved path when a CommonJS package is imported from an ESM test.
3959
- if (path.isAbsolute(moduleName) && hasJestEsmBypassModulePath(runtime, from, moduleName)) {
3960
- return moduleName
3961
- }
3962
- return
3971
+ // Keep the native fallback for logging packages that cannot be instrumented in Jest's realm, such as a
3972
+ // package-name-preserving symlink whose target is a user wrapper rather than the package itself.
3973
+ if (path.isAbsolute(moduleName) && getJestEsmLoggingModuleName(runtime, from, moduleName)) return moduleName
3974
+ if (!JEST_LOGGING_LIBRARIES.has(moduleName) || disabledJestInstrumentations.has(moduleName)) return
3963
3975
  }
3964
3976
 
3965
3977
  try {
@@ -3978,6 +3990,113 @@ function getJestBypassModulePath (runtime, from, moduleName) {
3978
3990
  }
3979
3991
  }
3980
3992
 
3993
+ /**
3994
+ * @param {object} runtime
3995
+ * @param {string} from
3996
+ * @param {string} moduleName
3997
+ * @returns {string}
3998
+ */
3999
+ function resolveJestModulePath (runtime, from, moduleName) {
4000
+ if (path.isAbsolute(moduleName)) return moduleName
4001
+
4002
+ if (typeof runtime._resolveCjsModule === 'function') {
4003
+ return runtime._resolveCjsModule(from, moduleName)
4004
+ } else if (typeof runtime.cjsLoader?.resolution?.resolveCjs === 'function') {
4005
+ return runtime.cjsLoader.resolution.resolveCjs(from, moduleName)
4006
+ }
4007
+ return runtime._resolveModule(from, moduleName)
4008
+ }
4009
+
4010
+ /**
4011
+ * @param {object} runtime
4012
+ * @param {string} from
4013
+ * @param {string} moduleName
4014
+ * @returns {{ name: string, path: string, version: string } | undefined}
4015
+ */
4016
+ function getJestLoggingPackage (runtime, from, moduleName) {
4017
+ if (typeof from !== 'string' || typeof moduleName !== 'string') return
4018
+
4019
+ const directModuleName = JEST_LOGGING_LIBRARIES.has(moduleName) && !disabledJestInstrumentations.has(moduleName)
4020
+ ? moduleName
4021
+ : getJestEsmLoggingModuleName(runtime, from, moduleName)
4022
+ const packages = jestLoggingPackagesByRuntime.get(runtime)
4023
+ let containingPackage
4024
+ if (!directModuleName) {
4025
+ if (!packages) return
4026
+
4027
+ const normalizedFrom = from.replaceAll(path.sep, '/')
4028
+ for (const [packageRoot, loggingPackage] of packages) {
4029
+ if (normalizedFrom.startsWith(`${packageRoot}/`)) {
4030
+ containingPackage = { packageRoot, ...loggingPackage }
4031
+ break
4032
+ }
4033
+ }
4034
+ if (!containingPackage) return
4035
+ }
4036
+
4037
+ try {
4038
+ const modulePath = resolveJestModulePath(runtime, from, moduleName)
4039
+ const normalizedModulePath = modulePath.replaceAll(path.sep, '/')
4040
+
4041
+ if (directModuleName) {
4042
+ if (modulePath !== createRequire(from).resolve(directModuleName)) return
4043
+
4044
+ const nodeModulesPath = `/node_modules/${directModuleName}/`
4045
+ const packagePathIndex = normalizedModulePath.lastIndexOf(nodeModulesPath)
4046
+ if (packagePathIndex === -1) return
4047
+
4048
+ const packageRoot = normalizedModulePath.slice(0, packagePathIndex + nodeModulesPath.length - 1)
4049
+ const { version } = JSON.parse(readFileSync(`${packageRoot}/package.json`, 'utf8'))
4050
+ if (typeof version !== 'string') return
4051
+
4052
+ let runtimePackages = packages
4053
+ if (!runtimePackages) {
4054
+ runtimePackages = new Map()
4055
+ jestLoggingPackagesByRuntime.set(runtime, runtimePackages)
4056
+ }
4057
+ runtimePackages.set(packageRoot, { name: directModuleName, version })
4058
+ return { name: directModuleName, path: directModuleName, version }
4059
+ }
4060
+
4061
+ const { packageRoot, name, version } = containingPackage
4062
+ if (!normalizedModulePath.startsWith(`${packageRoot}/`)) return
4063
+
4064
+ const modulePathWithinPackage = normalizedModulePath.slice(packageRoot.length + 1)
4065
+ return { name, path: `${name}/${modulePathWithinPackage}`, version }
4066
+ } catch {
4067
+ // Let Jest load unresolved, resolver-only, or virtual modules without instrumentation.
4068
+ }
4069
+ }
4070
+
4071
+ /**
4072
+ * @param {unknown} moduleExports
4073
+ * @param {{ name: string, path: string, version: string } | undefined} loggingPackage
4074
+ * @returns {unknown}
4075
+ */
4076
+ function instrumentJestLoggingModule (moduleExports, loggingPackage) {
4077
+ if (!loggingPackage || (typeof moduleExports !== 'object' && typeof moduleExports !== 'function')) {
4078
+ return moduleExports
4079
+ }
4080
+ if (moduleExports === null) return moduleExports
4081
+
4082
+ const instrumentedModule = instrumentedJestLoggingModules.get(moduleExports)
4083
+ if (instrumentedModule) return instrumentedModule
4084
+
4085
+ const payload = {
4086
+ module: moduleExports,
4087
+ package: loggingPackage.name,
4088
+ path: loggingPackage.path,
4089
+ version: loggingPackage.version,
4090
+ }
4091
+ // Apply the regular instrumentation after Jest has evaluated the module so its built-ins stay in Jest's realm.
4092
+ bundlerLoadCh.publish(payload)
4093
+ instrumentedJestLoggingModules.set(moduleExports, payload.module)
4094
+ if (payload.module && (typeof payload.module === 'object' || typeof payload.module === 'function')) {
4095
+ instrumentedJestLoggingModules.set(payload.module, payload.module)
4096
+ }
4097
+ return payload.module
4098
+ }
4099
+
3981
4100
  function formatDefaultStackTrace (error, structuredStackTrace) {
3982
4101
  const errorString = Error.prototype.toString.call(error)
3983
4102
  if (structuredStackTrace.length === 0) return errorString
@@ -4004,7 +4123,7 @@ addHook({
4004
4123
  // Jest 28 through 30.3 keeps ESM dependency resolution on Runtime itself.
4005
4124
  if (typeof Runtime.prototype.resolveModule === 'function') {
4006
4125
  shimmer.wrap(Runtime.prototype, 'resolveModule', resolveModule => function (moduleName, from) {
4007
- recordJestEsmBypassModulePath(this, from, moduleName)
4126
+ recordJestEsmLoggingModulePath(this, from, moduleName)
4008
4127
  return resolveModule.apply(this, arguments)
4009
4128
  })
4010
4129
  }
@@ -4019,11 +4138,13 @@ addHook({
4019
4138
  shimmer.wrap(Runtime.prototype, 'requireModule', requireModule => function (from, moduleName) {
4020
4139
  wrapJestGlobalsForRuntime(this)
4021
4140
  try {
4141
+ const loggingPackage = getJestLoggingPackage(this, from, moduleName)
4022
4142
  // Jest calls requireModule only after deciding that the module should not be mocked.
4023
- const bypassModulePath = getJestBypassModulePath(this, from, moduleName)
4024
- const returnedValue = bypassModulePath
4143
+ const bypassModulePath = loggingPackage ? undefined : getJestBypassModulePath(this, from, moduleName)
4144
+ let returnedValue = bypassModulePath
4025
4145
  ? requireOutsideJestRequireEngine(this, bypassModulePath)
4026
4146
  : requireModule.apply(this, arguments)
4147
+ returnedValue = instrumentJestLoggingModule(returnedValue, loggingPackage)
4027
4148
  if (moduleName === '@jest/globals') {
4028
4149
  wrapConcurrentJestGlobalsForRuntime(this, returnedValue)
4029
4150
  }
@@ -3,6 +3,11 @@
3
3
  const shimmer = require('../../datadog-shimmer')
4
4
  const { addHook, channel } = require('./helpers/instrument')
5
5
  const { wrapThen } = require('./helpers/promise')
6
+ const {
7
+ wrapPoolRelease,
8
+ wrapPromisePoolAcquire,
9
+ wrapPromisePoolQueryMethod,
10
+ } = require('./helpers/pool-acquire')
6
11
 
7
12
  const startRawQueryCh = channel('datadog:knex:raw:start')
8
13
  const rawQuerySubscribes = channel('datadog:knex:raw:subscribes')
@@ -32,6 +37,14 @@ addHook({
32
37
  versions: ['>=2'],
33
38
  file: 'lib/knex-builder/Knex.js',
34
39
  }, Knex => {
40
+ shimmer.wrap(Knex.Client.prototype, 'acquireConnection', acquireConnection => wrapPromisePoolAcquire(
41
+ acquireConnection,
42
+ resolveKnexDriver,
43
+ resolveKnexConfig,
44
+ knexHasIdleConnection
45
+ ))
46
+ shimmer.wrap(Knex.Client.prototype, 'releaseConnection', wrapPoolRelease)
47
+
35
48
  shimmer.wrap(Knex.Client.prototype, 'raw', raw => function (...args) {
36
49
  if (!startRawQueryCh.hasSubscribers) {
37
50
  return raw.apply(this, args)
@@ -77,6 +90,34 @@ addHook({
77
90
  return Knex
78
91
  })
79
92
 
93
+ addHook({
94
+ name: 'knex',
95
+ versions: ['>=2'],
96
+ file: 'lib/execution/runner.js',
97
+ }, Runner => {
98
+ shimmer.wrap(Runner.prototype, 'ensureConnection', ensureConnection => wrapPromisePoolQueryMethod(
99
+ ensureConnection,
100
+ runner => runner.connection || runner.builder?._connection ? undefined : runner.client,
101
+ runner => resolveKnexDriver(runner.client)
102
+ ))
103
+
104
+ return Runner
105
+ })
106
+
107
+ addHook({
108
+ name: 'knex',
109
+ versions: ['>=2'],
110
+ file: 'lib/execution/transaction.js',
111
+ }, Transaction => {
112
+ shimmer.wrap(Transaction.prototype, 'acquireConnection', acquireConnection => wrapPromisePoolQueryMethod(
113
+ acquireConnection,
114
+ (transaction, args) => args[0]?.connection ? undefined : transaction.client,
115
+ transaction => resolveKnexDriver(transaction.client)
116
+ ))
117
+
118
+ return Transaction
119
+ })
120
+
80
121
  function wrapCallbackWithFinish (callback, finish, context) {
81
122
  if (typeof callback !== 'function') return callback
82
123
 
@@ -84,3 +125,38 @@ function wrapCallbackWithFinish (callback, finish, context) {
84
125
  finish(context, () => callback.apply(this, args))
85
126
  })
86
127
  }
128
+
129
+ /**
130
+ * @param {{ pool?: { numFree?: () => number, numPendingAcquires?: () => number } }} client
131
+ * @returns {boolean}
132
+ */
133
+ function knexHasIdleConnection (client) {
134
+ const pool = client.pool
135
+ if (typeof pool?.numFree !== 'function') return false
136
+ return pool.numFree() > pool.numPendingAcquires()
137
+ }
138
+
139
+ /**
140
+ * @param {{ driverName?: string }|undefined} client
141
+ * @returns {'mysql'|'mysql2'|'pg'|undefined}
142
+ */
143
+ function resolveKnexDriver (client) {
144
+ switch (client?.driverName) {
145
+ case 'mysql':
146
+ return 'mysql'
147
+ case 'mysql2':
148
+ return 'mysql2'
149
+ case 'pg':
150
+ case 'cockroachdb':
151
+ case 'pg-redshift':
152
+ return 'pg'
153
+ }
154
+ }
155
+
156
+ /**
157
+ * @param {{ connectionSettings?: Record<string, unknown> }} client
158
+ * @returns {Record<string, unknown>}
159
+ */
160
+ function resolveKnexConfig (client) {
161
+ return client.connectionSettings ?? {}
162
+ }
@@ -11,6 +11,7 @@ const {
11
11
  runOutsidePoolQueryAcquire,
12
12
  runPoolAcquireError,
13
13
  runWithPoolWait,
14
+ setPromisePoolConnectionConfig,
14
15
  takePoolWaitTime,
15
16
  wrapPoolQueryMethod,
16
17
  } = require('./helpers/pool-acquire')
@@ -97,6 +98,8 @@ function createWrapQuery (options) {
97
98
  if (!startCh.hasSubscribers) return query.apply(this, arguments)
98
99
 
99
100
  const ctx = { sql, conf: options }
101
+ const poolWaitTime = takePoolWaitTime(this)
102
+ if (poolWaitTime !== undefined) ctx.poolWaitTime = poolWaitTime
100
103
 
101
104
  return startCh.runStores(ctx, query, this, ...arguments)
102
105
  .then(result => {
@@ -146,8 +149,11 @@ function createWrapQueryCallback (options) {
146
149
  function wrapConnection (promiseMethod, Connection) {
147
150
  return function (options) {
148
151
  Connection.apply(this, arguments)
152
+ setPromisePoolConnectionConfig(this, options)
149
153
 
154
+ const query = this[promiseMethod]
150
155
  shimmer.wrap(this, promiseMethod, createWrapQuery(options))
156
+ if (this.query === query) this.query = this[promiseMethod]
151
157
  shimmer.wrap(this, '_queryCallback', createWrapQueryCallback(options))
152
158
  }
153
159
  }
@@ -11,6 +11,60 @@ const MINIMUM_MOCHA_VERSION = DD_MAJOR >= 6 ? '>=8.0.0' : '>=5.2.0'
11
11
  const parameterizedTestCh = channel('ci:mocha:test:parameterize')
12
12
  const patched = new WeakSet()
13
13
 
14
+ /**
15
+ * Registers every Mocha package view that can expose the constructor.
16
+ *
17
+ * @param {string[]} versions
18
+ * @param {(Mocha: Function, frameworkVersion: string) => Function} wrapMochaRun
19
+ * @returns {void}
20
+ */
21
+ function addMochaRunHooks (versions, wrapMochaRun) {
22
+ const patchedMochaConstructors = new WeakSet()
23
+
24
+ /**
25
+ * @param {Function} Mocha
26
+ * @param {string} frameworkVersion
27
+ * @returns {Function}
28
+ */
29
+ function wrapMochaOnce (Mocha, frameworkVersion) {
30
+ if (patchedMochaConstructors.has(Mocha)) return Mocha
31
+ patchedMochaConstructors.add(Mocha)
32
+ return wrapMochaRun(Mocha, frameworkVersion)
33
+ }
34
+
35
+ /**
36
+ * @param {object|Function} MochaPackage
37
+ * @param {string} frameworkVersion
38
+ * @returns {object|Function}
39
+ */
40
+ function wrapMochaPackage (MochaPackage, frameworkVersion) {
41
+ wrapMochaOnce(MochaPackage.default ?? MochaPackage, frameworkVersion)
42
+ return MochaPackage
43
+ }
44
+
45
+ addHook({
46
+ name: 'mocha',
47
+ versions,
48
+ filePattern: String.raw`lib/mocha\.(?:c?js)$`,
49
+ }, wrapMochaOnce)
50
+
51
+ // Mocha 12's ESM package root can load lib/mocha.cjs before the CJS hook observes it. ESM imports report the
52
+ // package root while synchronous require reports index.js, so hook both views. Keeping the namespace intact makes
53
+ // the ESM hook skip its separate default-export callback, and wrapMochaOnce deduplicates loaders exposing both.
54
+ addHook({
55
+ name: 'mocha',
56
+ versions: ['>=12.0.0'],
57
+ patchDefault: false,
58
+ }, wrapMochaPackage)
59
+
60
+ addHook({
61
+ name: 'mocha',
62
+ versions: ['>=12.0.0'],
63
+ file: 'index.js',
64
+ patchDefault: false,
65
+ }, wrapMochaPackage)
66
+ }
67
+
14
68
  // mocha-each support
15
69
  addHook({
16
70
  name: 'mocha-each',
@@ -38,7 +92,8 @@ addHook({
38
92
  name: 'mocha',
39
93
  versions: [MINIMUM_MOCHA_VERSION],
40
94
  file: 'lib/suite.js',
41
- }, (Suite) => {
95
+ }, (SuitePackage) => {
96
+ const Suite = SuitePackage.Suite ?? SuitePackage
42
97
  shimmer.wrap(Suite.prototype, 'addTest', addTest => function (test) {
43
98
  const callSites = getCallSites()
44
99
  const testCallSite = callSites.find(site => site.getFileName() === test.file)
@@ -47,5 +102,7 @@ addHook({
47
102
  }
48
103
  return addTest.apply(this, arguments)
49
104
  })
50
- return Suite
105
+ return SuitePackage
51
106
  })
107
+
108
+ module.exports = { addMochaRunHooks }