dd-trace 5.67.0 → 5.69.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 (132) hide show
  1. package/LICENSE-3rdparty.csv +6 -4
  2. package/README.md +0 -2
  3. package/ci/init.js +52 -54
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +240 -3
  7. package/initialize.mjs +1 -1
  8. package/package.json +17 -11
  9. package/packages/datadog-core/src/storage.js +14 -13
  10. package/packages/datadog-esbuild/index.js +118 -26
  11. package/packages/datadog-instrumentations/src/aws-sdk.js +42 -4
  12. package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
  13. package/packages/datadog-instrumentations/src/azure-service-bus.js +1 -1
  14. package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
  15. package/packages/datadog-instrumentations/src/connect.js +6 -2
  16. package/packages/datadog-instrumentations/src/cucumber.js +31 -6
  17. package/packages/datadog-instrumentations/src/express.js +5 -6
  18. package/packages/datadog-instrumentations/src/fastify.js +3 -3
  19. package/packages/datadog-instrumentations/src/helpers/hook.js +28 -15
  20. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  21. package/packages/datadog-instrumentations/src/helpers/instrument.js +15 -5
  22. package/packages/datadog-instrumentations/src/helpers/register.js +10 -3
  23. package/packages/datadog-instrumentations/src/http2/client.js +1 -0
  24. package/packages/datadog-instrumentations/src/http2/server.js +0 -1
  25. package/packages/datadog-instrumentations/src/ioredis.js +12 -1
  26. package/packages/datadog-instrumentations/src/jest.js +48 -36
  27. package/packages/datadog-instrumentations/src/limitd-client.js +2 -1
  28. package/packages/datadog-instrumentations/src/mocha/main.js +15 -7
  29. package/packages/datadog-instrumentations/src/mocha/utils.js +3 -0
  30. package/packages/datadog-instrumentations/src/mongoose.js +2 -1
  31. package/packages/datadog-instrumentations/src/oracledb.js +19 -13
  32. package/packages/datadog-instrumentations/src/pg.js +9 -5
  33. package/packages/datadog-instrumentations/src/pino.js +18 -6
  34. package/packages/datadog-instrumentations/src/playwright.js +15 -1
  35. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  36. package/packages/datadog-instrumentations/src/vitest.js +155 -62
  37. package/packages/datadog-plugin-ai/src/tracing.js +3 -3
  38. package/packages/datadog-plugin-aws-sdk/src/base.js +23 -8
  39. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
  40. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +101 -2
  41. package/packages/datadog-plugin-aws-sdk/src/util.js +1 -1
  42. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +6 -0
  43. package/packages/datadog-plugin-cucumber/src/index.js +4 -56
  44. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -3
  45. package/packages/datadog-plugin-cypress/src/support.js +4 -0
  46. package/packages/datadog-plugin-express/src/code_origin.js +2 -2
  47. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -2
  48. package/packages/datadog-plugin-jest/src/index.js +0 -21
  49. package/packages/datadog-plugin-mocha/src/index.js +3 -57
  50. package/packages/datadog-plugin-mongodb-core/src/index.js +38 -12
  51. package/packages/datadog-plugin-playwright/src/index.js +11 -5
  52. package/packages/datadog-plugin-vitest/src/index.js +5 -1
  53. package/packages/datadog-plugin-ws/src/close.js +1 -1
  54. package/packages/datadog-plugin-ws/src/producer.js +6 -1
  55. package/packages/datadog-plugin-ws/src/receiver.js +6 -1
  56. package/packages/dd-trace/src/aiguard/client.js +25 -0
  57. package/packages/dd-trace/src/aiguard/noop.js +9 -0
  58. package/packages/dd-trace/src/aiguard/sdk.js +173 -0
  59. package/packages/dd-trace/src/aiguard/tags.js +11 -0
  60. package/packages/dd-trace/src/appsec/iast/path-line.js +21 -4
  61. package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +1 -1
  62. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +6 -3
  63. package/packages/dd-trace/src/appsec/stack_trace.js +20 -1
  64. package/packages/dd-trace/src/appsec/telemetry/waf.js +2 -2
  65. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -4
  66. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +11 -3
  67. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +10 -1
  68. package/packages/dd-trace/src/config-helper.js +8 -1
  69. package/packages/dd-trace/src/config.js +92 -304
  70. package/packages/dd-trace/src/config_defaults.js +191 -0
  71. package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -1
  72. package/packages/dd-trace/src/datastreams/fnv.js +2 -2
  73. package/packages/dd-trace/src/datastreams/index.js +23 -1
  74. package/packages/dd-trace/src/datastreams/writer.js +3 -2
  75. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
  76. package/packages/dd-trace/src/dogstatsd.js +4 -3
  77. package/packages/dd-trace/src/encode/0.4.js +1 -5
  78. package/packages/dd-trace/src/exporter.js +1 -0
  79. package/packages/dd-trace/src/exporters/agent/index.js +3 -2
  80. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  81. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +3 -2
  82. package/packages/dd-trace/src/exporters/common/request.js +2 -1
  83. package/packages/dd-trace/src/exporters/span-stats/index.js +3 -2
  84. package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
  85. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +15 -4
  86. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +20 -7
  87. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +40 -13
  88. package/packages/dd-trace/src/llmobs/plugins/openai.js +7 -1
  89. package/packages/dd-trace/src/llmobs/tagger.js +8 -0
  90. package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
  91. package/packages/dd-trace/src/log/index.js +27 -16
  92. package/packages/dd-trace/src/log/log.js +29 -5
  93. package/packages/dd-trace/src/log/writer.js +5 -5
  94. package/packages/dd-trace/src/noop/proxy.js +4 -0
  95. package/packages/dd-trace/src/noop/span.js +1 -0
  96. package/packages/dd-trace/src/opentelemetry/span.js +14 -3
  97. package/packages/dd-trace/src/opentracing/span.js +19 -5
  98. package/packages/dd-trace/src/payload-tagging/config/index.js +16 -0
  99. package/packages/dd-trace/src/payload-tagging/index.js +26 -15
  100. package/packages/dd-trace/src/payload-tagging/tagging.js +17 -8
  101. package/packages/dd-trace/src/pkg.js +3 -1
  102. package/packages/dd-trace/src/plugin_manager.js +20 -2
  103. package/packages/dd-trace/src/plugins/ci_plugin.js +97 -3
  104. package/packages/dd-trace/src/plugins/composite.js +3 -0
  105. package/packages/dd-trace/src/plugins/index.js +2 -0
  106. package/packages/dd-trace/src/plugins/plugin.js +67 -0
  107. package/packages/dd-trace/src/plugins/util/git-cache.js +129 -0
  108. package/packages/dd-trace/src/plugins/util/git.js +41 -27
  109. package/packages/dd-trace/src/plugins/util/test.js +56 -27
  110. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  111. package/packages/dd-trace/src/priority_sampler.js +70 -46
  112. package/packages/dd-trace/src/profiler.js +4 -1
  113. package/packages/dd-trace/src/profiling/config.js +73 -42
  114. package/packages/dd-trace/src/profiling/profiler.js +3 -1
  115. package/packages/dd-trace/src/profiling/profilers/events.js +3 -8
  116. package/packages/dd-trace/src/profiling/profilers/space.js +1 -0
  117. package/packages/dd-trace/src/profiling/profilers/wall.js +196 -117
  118. package/packages/dd-trace/src/proxy.js +15 -0
  119. package/packages/dd-trace/src/rate_limiter.js +26 -1
  120. package/packages/dd-trace/src/remote_config/capabilities.js +5 -0
  121. package/packages/dd-trace/src/remote_config/manager.js +3 -2
  122. package/packages/dd-trace/src/sampling_rule.js +124 -2
  123. package/packages/dd-trace/src/span_sampler.js +19 -0
  124. package/packages/dd-trace/src/standalone/product.js +9 -0
  125. package/packages/dd-trace/src/standalone/tracesource.js +16 -1
  126. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +13 -0
  127. package/packages/dd-trace/src/startup-log.js +21 -2
  128. package/packages/dd-trace/src/supported-configurations.json +9 -0
  129. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  130. package/packages/dd-trace/src/util.js +1 -1
  131. package/register.js +1 -1
  132. package/version.js +4 -2
@@ -13,14 +13,24 @@ exports.channel = function (name) {
13
13
  return ch
14
14
  }
15
15
 
16
+ const tracingChannelMap = {}
17
+ exports.tracingChannel = function (name) {
18
+ const maybe = tracingChannelMap[name]
19
+ if (maybe) return maybe
20
+ const tc = dc.tracingChannel(name)
21
+ tracingChannelMap[name] = tc
22
+ return tc
23
+ }
24
+
16
25
  /**
17
- * @param {string} args.name module name
26
+ * @param {object} args
27
+ * @param {string|string[]} args.name module name
18
28
  * @param {string[]} args.versions array of semver range strings
19
- * @param {string} args.file path to file within package to instrument
20
- * @param {string} args.filePattern pattern to match files within package to instrument
29
+ * @param {string} [args.file='index.js'] path to file within package to instrument
30
+ * @param {string} [args.filePattern] pattern to match files within package to instrument
21
31
  * @param Function hook
22
32
  */
23
- exports.addHook = function addHook ({ name, versions, file, filePattern }, hook) {
33
+ exports.addHook = function addHook ({ name, versions, file, filePattern, patchDefault }, hook) {
24
34
  if (typeof name === 'string') {
25
35
  name = [name]
26
36
  }
@@ -29,7 +39,7 @@ exports.addHook = function addHook ({ name, versions, file, filePattern }, hook)
29
39
  if (!instrumentations[val]) {
30
40
  instrumentations[val] = []
31
41
  }
32
- instrumentations[val].push({ name: val, versions, file, filePattern, hook })
42
+ instrumentations[val].push({ name: val, versions, file, filePattern, hook, patchDefault })
33
43
  }
34
44
  }
35
45
 
@@ -66,7 +66,7 @@ for (const packageName of names) {
66
66
  // get the instrumentation file name to save all hooked versions
67
67
  const instrumentationFileName = parseHookInstrumentationFileName(packageName)
68
68
 
69
- Hook([packageName], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion) => {
69
+ Hook([packageName], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm) => {
70
70
  moduleName = moduleName.replace(pathSepExpr, '/')
71
71
 
72
72
  // This executes the integration file thus adding its entries to `instrumentations`
@@ -77,7 +77,13 @@ for (const packageName of names) {
77
77
  }
78
78
 
79
79
  const namesAndSuccesses = {}
80
- for (const { name, file, versions, hook, filePattern } of instrumentations[packageName]) {
80
+ for (const { name, file, versions, hook, filePattern, patchDefault } of instrumentations[packageName]) {
81
+ if (patchDefault === false && !moduleExports.default && isIitm) {
82
+ return moduleExports
83
+ } else if (patchDefault === true && moduleExports.default && isIitm) {
84
+ moduleExports = moduleExports.default
85
+ }
86
+
81
87
  let fullFilePattern = filePattern
82
88
  const fullFilename = filename(name, file)
83
89
  if (fullFilePattern) {
@@ -137,7 +143,8 @@ for (const packageName of names) {
137
143
  // picked up due to the unification. Check what modules actually use the name.
138
144
  // TODO(BridgeAR): Only replace moduleExports if the hook returns a new value.
139
145
  // This allows to reduce the instrumentation code (no return needed).
140
- moduleExports = hook(moduleExports, version, name) ?? moduleExports
146
+
147
+ moduleExports = hook(moduleExports, version, name, isIitm) ?? moduleExports
141
148
  // Set the moduleExports in the hooks WeakSet
142
149
  hook[HOOK_SYMBOL].add(moduleExports)
143
150
  } catch (e) {
@@ -70,6 +70,7 @@ function wrapConnect (connect) {
70
70
 
71
71
  addHook({ name: names }, http2 => {
72
72
  shimmer.wrap(http2, 'connect', wrapConnect)
73
+ if (http2.default) http2.default.connect = http2.connect
73
74
 
74
75
  return http2
75
76
  })
@@ -18,7 +18,6 @@ const names = ['http2', 'node:http2']
18
18
  addHook({ name: names }, http2 => {
19
19
  shimmer.wrap(http2, 'createSecureServer', wrapCreateServer)
20
20
  shimmer.wrap(http2, 'createServer', wrapCreateServer)
21
- return http2
22
21
  })
23
22
 
24
23
  function wrapCreateServer (createServer) {
@@ -10,7 +10,7 @@ const startCh = channel('apm:ioredis:command:start')
10
10
  const finishCh = channel('apm:ioredis:command:finish')
11
11
  const errorCh = channel('apm:ioredis:command:error')
12
12
 
13
- addHook({ name: 'ioredis', versions: ['>=2'] }, Redis => {
13
+ function wrapRedis (Redis) {
14
14
  shimmer.wrap(Redis.prototype, 'sendCommand', sendCommand => function (command, stream) {
15
15
  if (!startCh.hasSubscribers) return sendCommand.apply(this, arguments)
16
16
 
@@ -35,8 +35,19 @@ addHook({ name: 'ioredis', versions: ['>=2'] }, Redis => {
35
35
  })
36
36
  })
37
37
  return Redis
38
+ }
39
+
40
+ addHook({ name: 'ioredis', versions: ['>=2 <4'], file: 'lib/redis.js' }, wrapRedis)
41
+
42
+ addHook({ name: 'ioredis', versions: ['>=4 <4.11.0'], file: 'built/redis.js' }, wrapRedis)
43
+
44
+ addHook({ name: 'ioredis', versions: ['>=4.11.0 <5'], file: 'built/redis/index.js' }, (exports) => {
45
+ wrapRedis(exports.default)
46
+ return exports
38
47
  })
39
48
 
49
+ addHook({ name: 'ioredis', versions: ['>=5'] }, wrapRedis)
50
+
40
51
  function finish (finishCh, errorCh, ctx, error) {
41
52
  if (error) {
42
53
  ctx.error = error
@@ -160,15 +160,15 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
160
160
  this.isImpactedTestsEnabled = this.testEnvironmentOptions._ddIsImpactedTestsEnabled
161
161
 
162
162
  if (this.isKnownTestsEnabled) {
163
+ earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
163
164
  try {
164
- const hasKnownTests = !!knownTests?.jest
165
- earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
166
- this.knownTestsForThisSuite = hasKnownTests
167
- ? (knownTests?.jest?.[this.testSuite] || [])
168
- : this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests)
169
- log.debug(`this.knownTestsForThisSuite is an array: ${Array.isArray(this.knownTestsForThisSuite)}`)
170
- log.debug(`this.knownTestsForThisSuite is null: ${this.knownTestsForThisSuite === null}`)
171
- log.debug(`this.knownTestsForThisSuite is undefined: ${this.knownTestsForThisSuite === undefined}`)
165
+ this.knownTestsForThisSuite = this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests)
166
+
167
+ if (!Array.isArray(this.knownTestsForThisSuite)) {
168
+ log.warn('this.knownTestsForThisSuite is not an array so new test and Early Flake detection is disabled.')
169
+ this.isEarlyFlakeDetectionEnabled = false
170
+ this.isKnownTestsEnabled = false
171
+ }
172
172
  } catch {
173
173
  // If there has been an error parsing the tests, we'll disable Early Flake Deteciton
174
174
  this.isEarlyFlakeDetectionEnabled = false
@@ -224,19 +224,20 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
224
224
  return hasSnapshotTests
225
225
  }
226
226
 
227
- // Function that receives a list of known tests for a test service and
228
- // returns the ones that belong to the current suite
229
- getKnownTestsForSuite (knownTests) {
230
- if (this.knownTestsForThisSuite) {
231
- return this.knownTestsForThisSuite
227
+ // This function returns an array if the known tests are valid and null otherwise.
228
+ getKnownTestsForSuite (suiteKnownTests) {
229
+ // `suiteKnownTests` is `this.testEnvironmentOptions._ddKnownTests`,
230
+ // which is only set if jest is configured to run in parallel.
231
+ if (suiteKnownTests) {
232
+ return suiteKnownTests
232
233
  }
233
- let knownTestsForSuite = knownTests
234
- // If jest is using workers, known tests are serialized to json.
235
- // If jest runs in band, they are not.
236
- if (typeof knownTestsForSuite === 'string') {
237
- knownTestsForSuite = JSON.parse(knownTestsForSuite)
234
+ // Global variable `knownTests` is set only in the main process.
235
+ // If jest is configured to run serially, the tests run in the same process, so `knownTests` is set.
236
+ // The assumption is that if the key `jest` is defined in the dictionary, the response is valid.
237
+ if (knownTests?.jest) {
238
+ return knownTests.jest[this.testSuite] || []
238
239
  }
239
- return knownTestsForSuite
240
+ return null
240
241
  }
241
242
 
242
243
  getTestManagementTestsForSuite (testManagementTests) {
@@ -472,10 +473,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
472
473
  }
473
474
  }
474
475
  if (this.isKnownTestsEnabled) {
475
- // Check if knownTestsForThisSuite is an array, since the worker may not have provided this information.
476
- // If it's null or undefined, we can't determine if the test is new.
477
- const isNew = Array.isArray(this.knownTestsForThisSuite) &&
478
- !this.knownTestsForThisSuite.includes(originalTestName)
476
+ const isNew = !this.knownTestsForThisSuite.includes(originalTestName)
479
477
  if (isNew && !isSkipped && !retriedTestsToNumAttempts.has(originalTestName)) {
480
478
  retriedTestsToNumAttempts.set(originalTestName, 0)
481
479
  if (this.isEarlyFlakeDetectionEnabled) {
@@ -623,9 +621,17 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
623
621
  function getTestEnvironment (pkg, jestVersion) {
624
622
  if (pkg.default) {
625
623
  const wrappedTestEnvironment = getWrappedEnvironment(pkg.default, jestVersion)
626
- pkg.default = wrappedTestEnvironment
627
- pkg.TestEnvironment = wrappedTestEnvironment
628
- return pkg
624
+ return new Proxy(pkg, {
625
+ get (target, prop) {
626
+ if (prop === 'default') {
627
+ return wrappedTestEnvironment
628
+ }
629
+ if (prop === 'TestEnvironment') {
630
+ return wrappedTestEnvironment
631
+ }
632
+ return target[prop]
633
+ }
634
+ })
629
635
  }
630
636
  return getWrappedEnvironment(pkg, jestVersion)
631
637
  }
@@ -657,6 +663,11 @@ addHook({
657
663
  versions: ['>=24.8.0']
658
664
  }, getTestEnvironment)
659
665
 
666
+ addHook({
667
+ name: '@happy-dom/jest-environment',
668
+ versions: ['>=10.0.0']
669
+ }, getTestEnvironment)
670
+
660
671
  function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
661
672
  // `scheduleTests` is an async function
662
673
  return function (tests) {
@@ -681,8 +692,11 @@ function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
681
692
 
682
693
  if (isKnownTestsEnabled) {
683
694
  const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
684
- const isFaulty =
685
- getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
695
+
696
+ // If the `jest` key does not exist in the known tests response, we consider the Early Flake detection faulty.
697
+ const isFaulty = !knownTests?.jest ||
698
+ getIsFaultyEarlyFlakeDetection(projectSuites, knownTests.jest, earlyFlakeDetectionFaultyThreshold)
699
+
686
700
  if (isFaulty) {
687
701
  log.error('Early flake detection is disabled because the number of new suites is too high.')
688
702
  isEarlyFlakeDetectionEnabled = false
@@ -1266,12 +1280,6 @@ const LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = new Set([
1266
1280
  'winston'
1267
1281
  ])
1268
1282
 
1269
- function shouldBypassJestRequireEngine (moduleName) {
1270
- return (
1271
- LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)
1272
- )
1273
- }
1274
-
1275
1283
  addHook({
1276
1284
  name: 'jest-runtime',
1277
1285
  versions: ['>=24.8.0']
@@ -1283,6 +1291,10 @@ addHook({
1283
1291
  const suiteFilePath = this._testPath
1284
1292
 
1285
1293
  shimmer.wrap(result, 'mock', mock => function (moduleName) {
1294
+ // If the library is mocked with `jest.mock`, we don't want to bypass jest's own require engine
1295
+ if (LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
1296
+ LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.delete(moduleName)
1297
+ }
1286
1298
  if (suiteFilePath) {
1287
1299
  const existingMockedFiles = testSuiteMockedFiles.get(suiteFilePath) || []
1288
1300
  const suiteDir = path.dirname(suiteFilePath)
@@ -1297,7 +1309,7 @@ addHook({
1297
1309
 
1298
1310
  shimmer.wrap(Runtime.prototype, 'requireModuleOrMock', requireModuleOrMock => function (from, moduleName) {
1299
1311
  // TODO: do this for every library that we instrument
1300
- if (shouldBypassJestRequireEngine(moduleName)) {
1312
+ if (LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
1301
1313
  // To bypass jest's own require engine
1302
1314
  return this._requireCoreModule(moduleName)
1303
1315
  }
@@ -1336,7 +1348,7 @@ function sendWrapper (send) {
1336
1348
  // https://github.com/jestjs/jest/blob/1d682f21c7a35da4d3ab3a1436a357b980ebd0fa/packages/jest-worker/src/workers/ChildProcessWorker.ts#L424
1337
1349
  if (type === CHILD_MESSAGE_CALL) {
1338
1350
  // This is the message that the main process sends to the worker to run a test suite (=test file).
1339
- // In here we modify the config.testEnvironmentOptions to include the known tests for the suite.
1351
+ // In here we modify the `config.testEnvironmentOptions` to include the known tests for the suite.
1340
1352
  // This way the suite only knows about the tests that are part of it.
1341
1353
  const args = request.at(-1)
1342
1354
  if (args.length > 1) {
@@ -13,7 +13,8 @@ function wrapRequest (original) {
13
13
 
14
14
  addHook({
15
15
  name: 'limitd-client',
16
- versions: ['>=2.8']
16
+ versions: ['>=2.8'],
17
+ file: ['client.js']
17
18
  }, LimitdClient => {
18
19
  shimmer.wrap(LimitdClient.prototype, '_directRequest', wrapRequest)
19
20
  shimmer.wrap(LimitdClient.prototype, '_retriedRequest', wrapRequest)
@@ -663,14 +663,22 @@ addHook({
663
663
  const newWorkerArgs = { ...workerArgs }
664
664
 
665
665
  if (config.isKnownTestsEnabled) {
666
- const testSuiteKnownTests = config.knownTests.mocha?.[testPath] || []
667
- newWorkerArgs._ddEfdNumRetries = config.earlyFlakeDetectionNumRetries
668
- newWorkerArgs._ddIsEfdEnabled = config.isEarlyFlakeDetectionEnabled
669
- newWorkerArgs._ddIsKnownTestsEnabled = true
670
- newWorkerArgs._ddKnownTests = {
671
- mocha: {
672
- [testPath]: testSuiteKnownTests
666
+ if (config.knownTests?.mocha) {
667
+ const testSuiteKnownTests = config.knownTests.mocha[testPath] || []
668
+ newWorkerArgs._ddEfdNumRetries = config.earlyFlakeDetectionNumRetries
669
+ newWorkerArgs._ddIsEfdEnabled = config.isEarlyFlakeDetectionEnabled
670
+ newWorkerArgs._ddIsKnownTestsEnabled = true
671
+ newWorkerArgs._ddKnownTests = {
672
+ mocha: {
673
+ [testPath]: testSuiteKnownTests
674
+ }
673
675
  }
676
+ } else {
677
+ config.isEarlyFlakeDetectionEnabled = false
678
+ config.isKnownTestsEnabled = false
679
+ newWorkerArgs._ddIsKnownTestsEnabled = false
680
+ newWorkerArgs._ddIsEfdEnabled = false
681
+ newWorkerArgs._ddKnownTests = {}
674
682
  }
675
683
  }
676
684
  if (config.isTestManagementTestsEnabled) {
@@ -56,6 +56,9 @@ function getTestProperties (test, testManagementTests) {
56
56
  }
57
57
 
58
58
  function isNewTest (test, knownTests) {
59
+ if (!knownTests?.mocha) { // invalid response, so we won't consider it as new
60
+ return false
61
+ }
59
62
  const testSuite = getTestSuitePath(test.file, process.cwd())
60
63
  const testName = removeEfdStringFromTestName(test.fullTitle())
61
64
  const testsForSuite = knownTests.mocha?.[testSuite] || []
@@ -24,7 +24,8 @@ function wrapAddQueue (addQueue) {
24
24
 
25
25
  addHook({
26
26
  name: 'mongoose',
27
- versions: ['>=4.6.4 <5', '5', '6', '>=7']
27
+ versions: ['>=4.6.4 <5', '5', '6', '>=7'],
28
+ file: 'lib/index.js'
28
29
  }, mongoose => {
29
30
  // As of Mongoose 7, custom promise libraries are no longer supported and mongoose.Promise may be undefined
30
31
  if (mongoose.Promise && mongoose.Promise !== global.Promise) {
@@ -20,7 +20,7 @@ function finish (ctx) {
20
20
  finishChannel.publish(ctx)
21
21
  }
22
22
 
23
- addHook({ name: 'oracledb', versions: ['>=5'] }, oracledb => {
23
+ addHook({ name: 'oracledb', versions: ['>=5'], file: 'lib/oracledb.js' }, oracledb => {
24
24
  shimmer.wrap(oracledb.Connection.prototype, 'execute', execute => {
25
25
  return function wrappedExecute (dbQuery, ...args) {
26
26
  if (!startChannel.hasSubscribers) {
@@ -40,22 +40,28 @@ addHook({ name: 'oracledb', versions: ['>=5'] }, oracledb => {
40
40
  })
41
41
  }
42
42
 
43
- // The connAttrs are used to pass through the argument to the potential
44
- // serviceName method a user might have passed through as well as parsing
45
- // the connection string in v5.
46
- const connAttrs = connectionAttributes.get(this)
47
-
48
- const details = typeof this.hostName === 'string' ? this : this._impl
49
-
50
43
  let hostname
51
44
  let port
52
45
  let dbInstance
53
46
 
54
- if (details) {
55
- dbInstance = details.serviceName
56
- hostname = details.hostName ?? details.nscon?.ntAdapter?.hostName
57
- port = String(details.port ?? details.nscon?.ntAdapter?.port ?? '')
58
- }
47
+ try {
48
+ if (this.thin) {
49
+ const details = this._impl ?? this
50
+ // Prefer public getters when available (v6), fallback to nscon in v5.
51
+ dbInstance = this.serviceName ?? details.serviceName
52
+ hostname = this.hostName ?? details.nscon?.ntAdapter?.hostName
53
+ const p = this.port ?? details.nscon?.ntAdapter?.port
54
+ if (p != null) port = String(p)
55
+ } else {
56
+ // Avoid host/port getters in thick mode, as they may throw.
57
+ dbInstance = this.serviceName
58
+ }
59
+ } catch {}
60
+
61
+ // The connAttrs are used to pass through the argument to the potential
62
+ // serviceName method a user might have passed through as well as parsing
63
+ // the connection string in v5 as well as in thick mode.
64
+ const connAttrs = connectionAttributes.get(this)
59
65
 
60
66
  const ctx = {
61
67
  dbInstance,
@@ -15,17 +15,21 @@ const finishPoolQueryCh = channel('datadog:pg:pool:query:finish')
15
15
 
16
16
  const { errorMonitor } = require('node:events')
17
17
 
18
- addHook({ name: 'pg', versions: ['>=8.0.3'] }, pg => {
19
- shimmer.wrap(pg.Client.prototype, 'query', query => wrapQuery(query))
20
- shimmer.wrap(pg.Pool.prototype, 'query', query => wrapPoolQuery(query))
21
- return pg
18
+ addHook({ name: 'pg', versions: ['>=8.0.3'], file: 'lib/native/client.js' }, Client => {
19
+ shimmer.wrap(Client.prototype, 'query', query => wrapQuery(query))
20
+ return Client
22
21
  })
23
22
 
24
- addHook({ name: 'pg', file: 'lib/native/index.js', versions: ['>=8.0.3'] }, Client => {
23
+ addHook({ name: 'pg', versions: ['>=8.0.3 <8.15.0', '>=8.15.0 <9'], file: 'lib/client.js' }, Client => {
25
24
  shimmer.wrap(Client.prototype, 'query', query => wrapQuery(query))
26
25
  return Client
27
26
  })
28
27
 
28
+ addHook({ name: 'pg', versions: ['>=8.0.3'] }, pg => {
29
+ shimmer.wrap(pg.Pool.prototype, 'query', query => wrapPoolQuery(query))
30
+ return pg
31
+ })
32
+
29
33
  function wrapQuery (query) {
30
34
  return function () {
31
35
  if (!startCh.hasSubscribers) {
@@ -73,19 +73,31 @@ function wrapPrettyFactory (prettyFactory) {
73
73
  }
74
74
  }
75
75
 
76
- addHook({ name: 'pino', versions: ['2 - 3', '4', '>=5 <5.14.0'] }, pino => {
76
+ addHook({ name: 'pino', versions: ['2 - 3', '4'], patchDefault: true }, (pino) => {
77
77
  const asJsonSym = (pino.symbols && pino.symbols.asJsonSym) || 'asJson'
78
78
 
79
- return shimmer.wrapFunction(pino, pino => wrapPino(asJsonSym, wrapAsJson, pino))
79
+ const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(asJsonSym, wrapAsJson, pino))
80
+
81
+ return wrapped
80
82
  })
81
83
 
82
- addHook({ name: 'pino', versions: ['>=5.14.0 <6.8.0'] }, pino => {
83
- const mixinSym = pino.symbols.mixinSym
84
+ addHook({ name: 'pino', versions: ['>=5 <5.14.0'], patchDefault: true }, (pino) => {
85
+ const asJsonSym = ((pino.default || pino)?.symbols.asJsonSym) || 'asJson'
86
+
87
+ const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(asJsonSym, wrapAsJson, pino))
88
+
89
+ return wrapped
90
+ })
91
+
92
+ addHook({ name: 'pino', versions: ['>=5.14.0 <6.8.0'] }, (pino) => {
93
+ const mixinSym = (pino.default || pino).symbols.mixinSym
84
94
 
85
- return shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino))
95
+ const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino.default || pino))
96
+
97
+ return wrapped
86
98
  })
87
99
 
88
- addHook({ name: 'pino', versions: ['>=6.8.0'] }, pino => {
100
+ addHook({ name: 'pino', versions: ['>=6.8.0'], patchDefault: false }, (pino, _1, _2, isIitm) => {
89
101
  const mixinSym = pino.symbols.mixinSym
90
102
 
91
103
  const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino))
@@ -51,6 +51,7 @@ let remainingTestsByFile = {}
51
51
  let isKnownTestsEnabled = false
52
52
  let isEarlyFlakeDetectionEnabled = false
53
53
  let earlyFlakeDetectionNumRetries = 0
54
+ let isEarlyFlakeDetectionFaulty = false
54
55
  let isFlakyTestRetriesEnabled = false
55
56
  let flakyTestRetriesCount = 0
56
57
  let knownTests = {}
@@ -64,6 +65,10 @@ let quarantinedButNotAttemptToFixFqns = new Set()
64
65
  let rootDir = ''
65
66
  const MINIMUM_SUPPORTED_VERSION_RANGE_EFD = '>=1.38.0' // TODO: remove this once we drop support for v5
66
67
 
68
+ function isValidKnownTests (receivedKnownTests) {
69
+ return !!receivedKnownTests.playwright
70
+ }
71
+
67
72
  function getTestFullyQualifiedName (test) {
68
73
  const fullname = getTestFullname(test)
69
74
  return `${test._requireFile} ${fullname}`
@@ -79,8 +84,11 @@ function getTestProperties (test) {
79
84
  }
80
85
 
81
86
  function isNewTest (test) {
87
+ if (!isValidKnownTests(knownTests)) {
88
+ return false
89
+ }
82
90
  const testSuite = getTestSuitePath(test._requireFile, rootDir)
83
- const testsForSuite = knownTests?.playwright?.[testSuite] || []
91
+ const testsForSuite = knownTests.playwright[testSuite] || []
84
92
 
85
93
  return !testsForSuite.includes(getTestFullname(test))
86
94
  }
@@ -557,6 +565,11 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
557
565
  } else {
558
566
  knownTests = receivedKnownTests
559
567
  }
568
+ if (!isValidKnownTests(receivedKnownTests)) {
569
+ isEarlyFlakeDetectionFaulty = true
570
+ isEarlyFlakeDetectionEnabled = false
571
+ isKnownTestsEnabled = false
572
+ }
560
573
  } catch (err) {
561
574
  isEarlyFlakeDetectionEnabled = false
562
575
  isKnownTestsEnabled = false
@@ -652,6 +665,7 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
652
665
  testSessionFinishCh.publish({
653
666
  status: STATUS_TO_TEST_STATUS[sessionStatus],
654
667
  isEarlyFlakeDetectionEnabled,
668
+ isEarlyFlakeDetectionFaulty,
655
669
  isTestManagementTestsEnabled,
656
670
  onDone
657
671
  })
@@ -7,7 +7,7 @@ const {
7
7
 
8
8
  const shimmer = require('../../datadog-shimmer')
9
9
 
10
- addHook({ name: 'sequelize', versions: ['>=4'] }, Sequelize => {
10
+ addHook({ name: 'sequelize', versions: ['>=4'], file: ['lib/sequelize.js'] }, Sequelize => {
11
11
  const startCh = channel('datadog:sequelize:query:start')
12
12
  const finishCh = channel('datadog:sequelize:query:finish')
13
13