dd-trace 5.103.0 → 5.104.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 (90) hide show
  1. package/index.d.ts +25 -3
  2. package/package.json +4 -3
  3. package/packages/datadog-instrumentations/src/aws-sdk.js +2 -2
  4. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
  5. package/packages/datadog-instrumentations/src/cucumber.js +103 -30
  6. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  7. package/packages/datadog-instrumentations/src/graphql.js +0 -5
  8. package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
  9. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
  10. package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
  11. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -5
  13. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +14 -13
  14. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  15. package/packages/datadog-instrumentations/src/ioredis.js +3 -3
  16. package/packages/datadog-instrumentations/src/jest.js +33 -36
  17. package/packages/datadog-instrumentations/src/kafkajs.js +25 -6
  18. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  19. package/packages/datadog-instrumentations/src/memcached.js +2 -1
  20. package/packages/datadog-instrumentations/src/mocha/main.js +272 -91
  21. package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
  22. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  23. package/packages/datadog-instrumentations/src/mongoose.js +10 -12
  24. package/packages/datadog-instrumentations/src/mysql.js +2 -2
  25. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  26. package/packages/datadog-instrumentations/src/pg.js +1 -1
  27. package/packages/datadog-instrumentations/src/playwright.js +22 -5
  28. package/packages/datadog-instrumentations/src/router.js +4 -2
  29. package/packages/datadog-instrumentations/src/vitest.js +246 -149
  30. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +26 -19
  31. package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
  32. package/packages/datadog-plugin-graphql/src/utils.js +4 -1
  33. package/packages/datadog-plugin-kafkajs/src/producer.js +32 -0
  34. package/packages/datadog-plugin-mongodb-core/src/index.js +54 -19
  35. package/packages/datadog-plugin-redis/src/index.js +37 -2
  36. package/packages/datadog-plugin-undici/src/index.js +19 -0
  37. package/packages/datadog-plugin-vitest/src/index.js +19 -7
  38. package/packages/datadog-shimmer/src/shimmer.js +35 -0
  39. package/packages/dd-trace/src/appsec/blocking.js +2 -2
  40. package/packages/dd-trace/src/appsec/index.js +10 -3
  41. package/packages/dd-trace/src/appsec/reporter.js +19 -5
  42. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
  43. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
  44. package/packages/dd-trace/src/config/generated-config-types.d.ts +1 -0
  45. package/packages/dd-trace/src/config/supported-configurations.json +9 -0
  46. package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
  47. package/packages/dd-trace/src/datastreams/context.js +4 -2
  48. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +26 -19
  49. package/packages/dd-trace/src/exporters/common/agents.js +3 -1
  50. package/packages/dd-trace/src/exporters/common/request.js +3 -1
  51. package/packages/dd-trace/src/id.js +17 -4
  52. package/packages/dd-trace/src/lambda/handler.js +2 -4
  53. package/packages/dd-trace/src/llmobs/sdk.js +10 -0
  54. package/packages/dd-trace/src/log/writer.js +3 -1
  55. package/packages/dd-trace/src/noop/span.js +3 -1
  56. package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
  57. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
  58. package/packages/dd-trace/src/plugins/apollo.js +3 -1
  59. package/packages/dd-trace/src/plugins/ci_plugin.js +3 -13
  60. package/packages/dd-trace/src/plugins/log_plugin.js +3 -1
  61. package/packages/dd-trace/src/plugins/tracing.js +5 -3
  62. package/packages/dd-trace/src/plugins/util/git.js +3 -1
  63. package/packages/dd-trace/src/plugins/util/test.js +82 -0
  64. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  65. package/packages/dd-trace/src/scope.js +7 -5
  66. package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
  67. package/vendor/dist/opentracing/LICENSE +0 -201
  68. package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
  69. package/vendor/dist/opentracing/constants.d.ts +0 -61
  70. package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
  71. package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
  72. package/vendor/dist/opentracing/functions.d.ts +0 -20
  73. package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
  74. package/vendor/dist/opentracing/index.d.ts +0 -12
  75. package/vendor/dist/opentracing/index.js +0 -1
  76. package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
  77. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
  78. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
  79. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
  80. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
  81. package/vendor/dist/opentracing/noop.d.ts +0 -8
  82. package/vendor/dist/opentracing/reference.d.ts +0 -33
  83. package/vendor/dist/opentracing/span.d.ts +0 -147
  84. package/vendor/dist/opentracing/span_context.d.ts +0 -26
  85. package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
  86. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
  87. package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
  88. package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
  89. package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
  90. package/vendor/dist/opentracing/tracer.d.ts +0 -127
@@ -10,17 +10,25 @@ const tracingChannelPredicate = (node) => (
10
10
  )
11
11
 
12
12
  const transforms = module.exports = {
13
- tracingChannelImport ({ dcModule, sourceType }, node) {
13
+ /**
14
+ * @param {{ dcModule: string, moduleType: 'esm' | 'cjs' }} state
15
+ * @param {import('estree').Program} node
16
+ */
17
+ tracingChannelImport ({ dcModule, moduleType }, node) {
14
18
  if (node.body.some(tracingChannelPredicate)) return
15
19
 
20
+ // The vendored matcher state exposes `moduleType` (`esm` / `cjs`), so we
21
+ // read that field directly. Naming it `sourceType` here used to silently
22
+ // pick the CJS branch for every ESM file, leaving `require()` baked into
23
+ // pure ESM modules like `@langchain/langgraph/dist/pregel/index.js`.
24
+ const isModule = moduleType === 'esm'
25
+
16
26
  const index = node.body.findIndex(child => child.directive === 'use strict')
17
- const code = isModuleSourceType(sourceType)
18
- ? `import { tracingChannel as tr_ch_apm_tracingChannel } from "${dcModule}"`
27
+ const code = isModule
28
+ ? `import tr_ch_apm_dc from "${dcModule}"; const {tracingChannel: tr_ch_apm_tracingChannel} = tr_ch_apm_dc`
19
29
  : `const {tracingChannel: tr_ch_apm_tracingChannel} = require("${dcModule}")`
20
30
 
21
- node.body.splice(index + 1, 0, parse(code, {
22
- isModule: isModuleSourceType(sourceType),
23
- }).body[0])
31
+ node.body.splice(index + 1, 0, ...parse(code, { isModule }).body)
24
32
  },
25
33
 
26
34
  tracingChannelDeclaration (state, node) {
@@ -53,13 +61,6 @@ function traceAny (state, node, _parent, ancestry) {
53
61
  }
54
62
  }
55
63
 
56
- /**
57
- * @param {string} sourceType
58
- */
59
- function isModuleSourceType (sourceType) {
60
- return sourceType === 'module' || sourceType === 'esm'
61
- }
62
-
63
64
  function traceFunction (state, node, program) {
64
65
  transforms.tracingChannelDeclaration(state, program)
65
66
 
@@ -188,8 +188,8 @@ function patch (http, methodName) {
188
188
  let finished = false
189
189
  let callback = args.callback
190
190
 
191
- if (callback) {
192
- callback = shimmer.wrapFunction(args.callback, cb => function (...args) {
191
+ if (typeof callback === 'function') {
192
+ callback = shimmer.wrapCallback(args.callback, cb => function (...args) {
193
193
  return asyncStartChannel.runStores(ctx, () => {
194
194
  return cb.apply(this, args)
195
195
  })
@@ -14,9 +14,9 @@ const connectionOptionsCache = new WeakMap()
14
14
 
15
15
  function wrapRedis (Redis) {
16
16
  shimmer.wrap(Redis.prototype, 'sendCommand', sendCommand => function (command, stream) {
17
- if (!startCh.hasSubscribers) return sendCommand.apply(this, arguments)
17
+ if (!startCh.hasSubscribers) return sendCommand.call(this, command, stream)
18
18
 
19
- if (!command || !command.promise) return sendCommand.apply(this, arguments)
19
+ if (!command?.promise) return sendCommand.call(this, command, stream)
20
20
 
21
21
  const options = this.options || {}
22
22
  let connectionOptions = connectionOptionsCache.get(this)
@@ -35,7 +35,7 @@ function wrapRedis (Redis) {
35
35
  return startCh.runStores(ctx, () => {
36
36
  command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
37
37
 
38
- return sendCommand.apply(this, arguments)
38
+ return sendCommand.call(this, command, stream)
39
39
  })
40
40
  })
41
41
  return Redis
@@ -30,6 +30,7 @@ const {
30
30
  logAttemptToFixTestExecution,
31
31
  logTestOptimizationSummary,
32
32
  getEfdRetryCount,
33
+ getTestOptimizationRequestResults,
33
34
  } = require('../../dd-trace/src/plugins/util/test')
34
35
  const {
35
36
  SEED_SUFFIX_RE,
@@ -1173,6 +1174,12 @@ function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
1173
1174
  }
1174
1175
  }
1175
1176
 
1177
+ function getChannelPromise (channelToPublishTo, payload = {}) {
1178
+ return new Promise(resolve => {
1179
+ channelToPublishTo.publish({ ...payload, onDone: resolve })
1180
+ })
1181
+ }
1182
+
1176
1183
  function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
1177
1184
  const SearchSource = searchSourcePackage.default ?? searchSourcePackage
1178
1185
 
@@ -1234,17 +1241,14 @@ function getCliWrapper (isNewJestVersion) {
1234
1241
  }
1235
1242
  return shimmer.wrap(cli, 'runCLI', runCLI => async function () {
1236
1243
  let onDone
1237
- const configurationPromise = new Promise((resolve) => {
1238
- onDone = resolve
1239
- })
1240
1244
  if (!libraryConfigurationCh.hasSubscribers) {
1241
1245
  return runCLI.apply(this, arguments)
1242
1246
  }
1243
1247
 
1244
- libraryConfigurationCh.publish({ onDone, frameworkVersion: jestVersion })
1245
-
1246
1248
  try {
1247
- const { err, libraryConfig } = await configurationPromise
1249
+ const { err, libraryConfig } = await getChannelPromise(libraryConfigurationCh, {
1250
+ frameworkVersion: jestVersion,
1251
+ })
1248
1252
  if (!err) {
1249
1253
  isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
1250
1254
  isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
@@ -1263,15 +1267,22 @@ function getCliWrapper (isNewJestVersion) {
1263
1267
  log.error('Jest library configuration error', err)
1264
1268
  }
1265
1269
 
1266
- if (isKnownTestsEnabled) {
1267
- const knownTestsPromise = new Promise((resolve) => {
1268
- onDone = resolve
1269
- })
1270
-
1271
- knownTestsCh.publish({ onDone })
1270
+ const {
1271
+ knownTestsResponse,
1272
+ testManagementTestsResponse,
1273
+ skippableSuitesResponse,
1274
+ } = await getTestOptimizationRequestResults({
1275
+ isKnownTestsEnabled,
1276
+ isTestManagementTestsEnabled,
1277
+ isSuitesSkippingEnabled,
1278
+ getKnownTests: () => getChannelPromise(knownTestsCh),
1279
+ getTestManagementTests: () => getChannelPromise(testManagementTestsCh),
1280
+ getSkippableSuites: () => getChannelPromise(skippableSuitesCh),
1281
+ })
1272
1282
 
1283
+ if (isKnownTestsEnabled) {
1273
1284
  try {
1274
- const { err, knownTests: receivedKnownTests } = await knownTestsPromise
1285
+ const { err, knownTests: receivedKnownTests } = knownTestsResponse || await getChannelPromise(knownTestsCh)
1275
1286
  if (err) {
1276
1287
  // We disable EFD if there has been an error in the known tests request
1277
1288
  isEarlyFlakeDetectionEnabled = false
@@ -1285,14 +1296,9 @@ function getCliWrapper (isNewJestVersion) {
1285
1296
  }
1286
1297
 
1287
1298
  if (isSuitesSkippingEnabled) {
1288
- const skippableSuitesPromise = new Promise((resolve) => {
1289
- onDone = resolve
1290
- })
1291
-
1292
- skippableSuitesCh.publish({ onDone })
1293
-
1294
1299
  try {
1295
- const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
1300
+ const { err, skippableSuites: receivedSkippableSuites } =
1301
+ skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
1296
1302
  if (!err) {
1297
1303
  skippableSuites = receivedSkippableSuites
1298
1304
  }
@@ -1302,14 +1308,9 @@ function getCliWrapper (isNewJestVersion) {
1302
1308
  }
1303
1309
 
1304
1310
  if (isTestManagementTestsEnabled) {
1305
- const testManagementTestsPromise = new Promise((resolve) => {
1306
- onDone = resolve
1307
- })
1308
-
1309
- testManagementTestsCh.publish({ onDone })
1310
-
1311
1311
  try {
1312
- const { err, testManagementTests: receivedTestManagementTests } = await testManagementTestsPromise
1312
+ const { err, testManagementTests: receivedTestManagementTests } =
1313
+ testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
1313
1314
  if (err) {
1314
1315
  isTestManagementTestsEnabled = false
1315
1316
  testManagementTests = {}
@@ -1323,14 +1324,8 @@ function getCliWrapper (isNewJestVersion) {
1323
1324
  }
1324
1325
 
1325
1326
  if (isImpactedTestsEnabled) {
1326
- const impactedTestsPromise = new Promise((resolve) => {
1327
- onDone = resolve
1328
- })
1329
-
1330
- modifiedFilesCh.publish({ onDone })
1331
-
1332
1327
  try {
1333
- const { err, modifiedFiles: receivedModifiedFiles } = await impactedTestsPromise
1328
+ const { err, modifiedFiles: receivedModifiedFiles } = await getChannelPromise(modifiedFilesCh)
1334
1329
  if (!err) {
1335
1330
  modifiedFiles = receivedModifiedFiles
1336
1331
  }
@@ -2047,10 +2042,12 @@ function getStaticMockedFiles (suiteFilePath) {
2047
2042
 
2048
2043
  function getMockedFiles (suiteFilePath) {
2049
2044
  const mockedFiles = testSuiteMockedFiles.get(suiteFilePath)
2045
+ const staticMockedFiles = getStaticMockedFiles(suiteFilePath)
2046
+
2050
2047
  if (mockedFiles?.length) {
2051
- return mockedFiles
2048
+ return [...new Set([...mockedFiles, ...staticMockedFiles])]
2052
2049
  }
2053
- return getStaticMockedFiles(suiteFilePath)
2050
+ return staticMockedFiles
2054
2051
  }
2055
2052
 
2056
2053
  function wrapJestObject (jestObject, suiteFilePath) {
@@ -8,6 +8,7 @@ const {
8
8
  addHook,
9
9
  } = require('./helpers/instrument')
10
10
  const {
11
+ brokerSupportsMessageHeaders,
11
12
  clientToCluster,
12
13
  cloneMessages,
13
14
  } = require('./helpers/kafka')
@@ -26,7 +27,7 @@ const batchConsumerStartCh = channel('apm:kafkajs:consume-batch:start')
26
27
  const batchConsumerFinishCh = channel('apm:kafkajs:consume-batch:finish')
27
28
  const batchConsumerErrorCh = channel('apm:kafkajs:consume-batch:error')
28
29
 
29
- const disabledHeaderWeakSet = new WeakSet()
30
+ const noop = () => {}
30
31
 
31
32
  addHook({ name: 'kafkajs', file: 'src/producer/index.js', versions: ['>=1.4'] }, (createProducer) =>
32
33
  shimmer.wrapFunction(createProducer, original => function wrappedCreateProducer (params) {
@@ -64,15 +65,26 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
64
65
  const bootstrapServers = this._brokers
65
66
  const cluster = clientToCluster.get(producer)
66
67
 
68
+ let disableHeaderInjection = false
69
+
70
+ let refreshHeaderSupport = () => {
71
+ if (!brokerSupportsMessageHeaders(cluster?.brokerPool)) {
72
+ disableHeaderInjection = true
73
+ refreshHeaderSupport = noop
74
+ log.info('kafkajs broker negotiated Produce <v3; tracer header injection disabled.')
75
+ }
76
+ }
77
+
67
78
  producer.send = function (...args) {
68
79
  if (!producerStartCh.hasSubscribers) {
69
80
  return originalSend.apply(this, args)
70
81
  }
71
82
 
72
- // Fast path: kafkajs has fetched metadata, so clusterId is already on
73
- // the broker pool.
83
+ // Fast path: kafkajs has fetched metadata, so versions and clusterId
84
+ // are already on the broker pool.
74
85
  const metadata = cluster?.brokerPool?.metadata
75
86
  if (metadata) {
87
+ refreshHeaderSupport()
76
88
  return runSend.call(this, args, metadata.clusterId)
77
89
  }
78
90
 
@@ -84,7 +96,10 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
84
96
  return runSend.call(this, args)
85
97
  }
86
98
  return cluster.refreshMetadataIfNecessary().then(
87
- () => runSend.call(this, args, cluster.brokerPool?.metadata?.clusterId),
99
+ () => {
100
+ refreshHeaderSupport()
101
+ return runSend.call(this, args, cluster.brokerPool?.metadata?.clusterId)
102
+ },
88
103
  () => runSend.call(this, args)
89
104
  )
90
105
  }
@@ -93,7 +108,6 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
93
108
  const arg0 = args[0]
94
109
  const topic = arg0?.topic
95
110
  const inputMessages = Array.isArray(arg0?.messages) ? arg0.messages : []
96
- const disableHeaderInjection = disabledHeaderWeakSet.has(producer)
97
111
 
98
112
  // Hand kafkajs and the plugin a shallow clone so injection writes to
99
113
  // tracer-owned objects instead of the caller's. With injection
@@ -125,8 +139,13 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
125
139
  (error) => {
126
140
  ctx.error = error
127
141
  if (error) {
142
+ // Safety net for mixed-version clusters where the seed
143
+ // broker advertised Produce v3+ but the leader we shipped to
144
+ // could not parse the headers, surfacing as
145
+ // KafkaJSProtocolError UNKNOWN (server error code -1).
128
146
  if (error.name === 'KafkaJSProtocolError' && error.type === 'UNKNOWN') {
129
- disabledHeaderWeakSet.add(producer)
147
+ disableHeaderInjection = true
148
+ refreshHeaderSupport = noop
130
149
  log.error(
131
150
  // eslint-disable-next-line @stylistic/max-len
132
151
  'Kafka Broker responded with UNKNOWN_SERVER_ERROR (-1). Please look at broker logs for more information. Tracer message header injection for Kafka is disabled.'
@@ -93,7 +93,7 @@ function createWrapQueryCallback (options) {
93
93
  }
94
94
 
95
95
  if (typeof cb === 'function') {
96
- arguments[arguments.length - 1] = shimmer.wrapFunction(cb, wrapper)
96
+ arguments[arguments.length - 1] = shimmer.wrapCallback(cb, wrapper)
97
97
  } else {
98
98
  arguments.length += 1
99
99
  arguments[arguments.length - 1] = wrapper()
@@ -23,7 +23,8 @@ addHook({ name: 'memcached', versions: ['>=2.2'] }, Memcached => {
23
23
 
24
24
  const ctx = { client, server, query }
25
25
  startCh.runStores(ctx, () => {
26
- query.callback = shimmer.wrapFunction(query.callback, callback => function (err) {
26
+ if (typeof query.callback !== 'function') return
27
+ query.callback = shimmer.wrapCallback(query.callback, callback => function (err) {
27
28
  if (err) {
28
29
  ctx.error = err
29
30
  errorCh.publish(ctx)