dd-trace 5.101.0 → 5.102.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 (140) hide show
  1. package/package.json +9 -7
  2. package/packages/datadog-instrumentations/src/aerospike.js +2 -2
  3. package/packages/datadog-instrumentations/src/ai.js +8 -8
  4. package/packages/datadog-instrumentations/src/amqplib.js +6 -7
  5. package/packages/datadog-instrumentations/src/anthropic.js +10 -10
  6. package/packages/datadog-instrumentations/src/apollo-server-core.js +3 -3
  7. package/packages/datadog-instrumentations/src/apollo-server.js +5 -5
  8. package/packages/datadog-instrumentations/src/avsc.js +6 -6
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +151 -67
  10. package/packages/datadog-instrumentations/src/azure-durable-functions.js +8 -8
  11. package/packages/datadog-instrumentations/src/bluebird.js +2 -2
  12. package/packages/datadog-instrumentations/src/body-parser.js +2 -2
  13. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  14. package/packages/datadog-instrumentations/src/child_process.js +12 -12
  15. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +9 -9
  16. package/packages/datadog-instrumentations/src/connect.js +7 -7
  17. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  18. package/packages/datadog-instrumentations/src/cookie.js +2 -2
  19. package/packages/datadog-instrumentations/src/couchbase.js +16 -30
  20. package/packages/datadog-instrumentations/src/crypto.js +4 -4
  21. package/packages/datadog-instrumentations/src/cucumber.js +77 -16
  22. package/packages/datadog-instrumentations/src/dns.js +0 -3
  23. package/packages/datadog-instrumentations/src/elasticsearch.js +8 -11
  24. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +6 -6
  25. package/packages/datadog-instrumentations/src/express-session.js +4 -4
  26. package/packages/datadog-instrumentations/src/express.js +10 -11
  27. package/packages/datadog-instrumentations/src/fastify.js +2 -2
  28. package/packages/datadog-instrumentations/src/fs.js +14 -14
  29. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +5 -7
  30. package/packages/datadog-instrumentations/src/google-genai.js +4 -4
  31. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  32. package/packages/datadog-instrumentations/src/hapi.js +2 -2
  33. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +8 -8
  34. package/packages/datadog-instrumentations/src/helpers/promise.js +2 -2
  35. package/packages/datadog-instrumentations/src/hono.js +2 -2
  36. package/packages/datadog-instrumentations/src/http/client.js +6 -6
  37. package/packages/datadog-instrumentations/src/http/server.js +9 -9
  38. package/packages/datadog-instrumentations/src/jest.js +31 -31
  39. package/packages/datadog-instrumentations/src/kafkajs.js +9 -9
  40. package/packages/datadog-instrumentations/src/knex.js +17 -17
  41. package/packages/datadog-instrumentations/src/koa.js +12 -12
  42. package/packages/datadog-instrumentations/src/ldapjs.js +5 -5
  43. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  44. package/packages/datadog-instrumentations/src/limitd-client.js +4 -4
  45. package/packages/datadog-instrumentations/src/lodash.js +4 -4
  46. package/packages/datadog-instrumentations/src/mariadb.js +13 -13
  47. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  48. package/packages/datadog-instrumentations/src/microgateway-core.js +2 -2
  49. package/packages/datadog-instrumentations/src/mocha/common.js +3 -3
  50. package/packages/datadog-instrumentations/src/mocha/main.js +12 -10
  51. package/packages/datadog-instrumentations/src/mocha/utils.js +133 -16
  52. package/packages/datadog-instrumentations/src/mocha/worker.js +7 -5
  53. package/packages/datadog-instrumentations/src/mongodb-core.js +9 -22
  54. package/packages/datadog-instrumentations/src/mongodb.js +5 -5
  55. package/packages/datadog-instrumentations/src/mongoose.js +21 -21
  56. package/packages/datadog-instrumentations/src/mquery.js +5 -5
  57. package/packages/datadog-instrumentations/src/multer.js +4 -4
  58. package/packages/datadog-instrumentations/src/mysql.js +16 -16
  59. package/packages/datadog-instrumentations/src/mysql2.js +4 -4
  60. package/packages/datadog-instrumentations/src/net.js +14 -8
  61. package/packages/datadog-instrumentations/src/nyc.js +5 -5
  62. package/packages/datadog-instrumentations/src/openai.js +19 -19
  63. package/packages/datadog-instrumentations/src/oracledb.js +6 -6
  64. package/packages/datadog-instrumentations/src/passport-utils.js +5 -5
  65. package/packages/datadog-instrumentations/src/pg.js +15 -15
  66. package/packages/datadog-instrumentations/src/pino.js +6 -10
  67. package/packages/datadog-instrumentations/src/playwright.js +20 -15
  68. package/packages/datadog-instrumentations/src/protobufjs.js +16 -16
  69. package/packages/datadog-instrumentations/src/redis.js +1 -2
  70. package/packages/datadog-instrumentations/src/restify.js +2 -2
  71. package/packages/datadog-instrumentations/src/router.js +12 -12
  72. package/packages/datadog-instrumentations/src/stripe.js +12 -12
  73. package/packages/datadog-instrumentations/src/vitest.js +107 -26
  74. package/packages/datadog-instrumentations/src/winston.js +4 -4
  75. package/packages/datadog-instrumentations/src/ws.js +7 -7
  76. package/packages/datadog-plugin-aws-sdk/src/base.js +52 -4
  77. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +19 -12
  78. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +45 -35
  79. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +33 -22
  80. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +12 -13
  81. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +73 -54
  82. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +19 -17
  83. package/packages/datadog-plugin-aws-sdk/src/util.js +22 -0
  84. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -6
  85. package/packages/datadog-plugin-cucumber/src/index.js +4 -0
  86. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -4
  87. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -5
  88. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +3 -1
  89. package/packages/datadog-plugin-http/src/client.js +1 -5
  90. package/packages/datadog-plugin-jest/src/util.js +1 -2
  91. package/packages/datadog-plugin-mocha/src/index.js +4 -0
  92. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -1
  93. package/packages/datadog-plugin-openai/src/tracing.js +12 -23
  94. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  95. package/packages/datadog-plugin-vitest/src/index.js +8 -1
  96. package/packages/datadog-shimmer/src/shimmer.js +7 -1
  97. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  98. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +81 -81
  99. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  100. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  101. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  102. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -2
  103. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  104. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -3
  105. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +83 -48
  106. package/packages/dd-trace/src/appsec/index.js +21 -24
  107. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  108. package/packages/dd-trace/src/appsec/rule_manager.js +4 -2
  109. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +31 -16
  110. package/packages/dd-trace/src/config/git_properties.js +2 -2
  111. package/packages/dd-trace/src/datastreams/index.js +2 -1
  112. package/packages/dd-trace/src/datastreams/processor.js +1 -2
  113. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +1 -0
  114. package/packages/dd-trace/src/encode/0.4.js +757 -232
  115. package/packages/dd-trace/src/encode/0.5.js +13 -7
  116. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -2
  117. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +6 -3
  118. package/packages/dd-trace/src/llmobs/sdk.js +24 -26
  119. package/packages/dd-trace/src/llmobs/span_processor.js +25 -5
  120. package/packages/dd-trace/src/llmobs/util.js +1 -0
  121. package/packages/dd-trace/src/msgpack/chunk.js +6 -3
  122. package/packages/dd-trace/src/openfeature/noop.js +40 -36
  123. package/packages/dd-trace/src/openfeature/writers/exposures.js +33 -52
  124. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +1 -2
  125. package/packages/dd-trace/src/opentelemetry/tracer.js +0 -22
  126. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +2 -11
  127. package/packages/dd-trace/src/plugins/util/ci.js +1 -1
  128. package/packages/dd-trace/src/plugins/util/git-cache.js +3 -5
  129. package/packages/dd-trace/src/plugins/util/test.js +19 -7
  130. package/packages/dd-trace/src/plugins/util/url.js +1 -3
  131. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  132. package/packages/dd-trace/src/plugins/util/web.js +5 -7
  133. package/packages/dd-trace/src/profiling/profilers/events.js +3 -23
  134. package/packages/dd-trace/src/profiling/profilers/wall.js +4 -5
  135. package/packages/dd-trace/src/runtime_metrics/index.js +2 -2
  136. package/packages/dd-trace/src/scope.js +3 -10
  137. package/packages/dd-trace/src/serverless.js +1 -4
  138. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +7 -1
  139. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +4 -0
  140. package/packages/dd-trace/src/tracer.js +7 -7
@@ -6,8 +6,8 @@ const { wrapThen } = require('./helpers/promise')
6
6
 
7
7
  function createGetNewLibraryCopyWrap (originalLib) {
8
8
  return function wrapGetNewLibraryCopy (getNewLibraryCopy) {
9
- return function getNewLibraryCopyWithTrace () {
10
- const libraryCopy = getNewLibraryCopy.apply(this, arguments)
9
+ return function getNewLibraryCopyWithTrace (...args) {
10
+ const libraryCopy = getNewLibraryCopy.apply(this, args)
11
11
  shimmer.wrap(libraryCopy.prototype, '_then', wrapThen)
12
12
  shimmer.wrap(libraryCopy, 'getNewLibraryCopy', createGetNewLibraryCopyWrap(originalLib))
13
13
  return libraryCopy
@@ -6,7 +6,7 @@ const { channel, addHook, AsyncResource } = require('./helpers/instrument')
6
6
  const bodyParserReadCh = channel('datadog:body-parser:read:finish')
7
7
 
8
8
  function publishRequestBodyAndNext (req, res, next) {
9
- return shimmer.wrapFunction(next, next => function () {
9
+ return shimmer.wrapFunction(next, next => function (...args) {
10
10
  if (bodyParserReadCh.hasSubscribers && req) {
11
11
  const abortController = new AbortController()
12
12
  const body = req.body
@@ -16,7 +16,7 @@ function publishRequestBodyAndNext (req, res, next) {
16
16
  if (abortController.signal.aborted) return
17
17
  }
18
18
 
19
- return next.apply(this, arguments)
19
+ return next.apply(this, args)
20
20
  })
21
21
  }
22
22
 
@@ -100,13 +100,13 @@ addHook({ name: 'cassandra-driver', versions: ['3 - 4.3'], patchDefault: false }
100
100
  })
101
101
 
102
102
  addHook({ name: 'cassandra-driver', versions: ['>=3.3'], file: 'lib/request-execution.js' }, RequestExecution => {
103
- shimmer.wrap(RequestExecution.prototype, '_sendOnConnection', _sendOnConnection => function () {
103
+ shimmer.wrap(RequestExecution.prototype, '_sendOnConnection', _sendOnConnection => function (...args) {
104
104
  if (!startCh.hasSubscribers) {
105
- return _sendOnConnection.apply(this, arguments)
105
+ return _sendOnConnection.apply(this, args)
106
106
  }
107
107
  startCtx = { hostname: this._connection.address, port: this._connection.port, ...startCtx }
108
108
  connectCh.publish(startCtx)
109
- return _sendOnConnection.apply(this, arguments)
109
+ return _sendOnConnection.apply(this, args)
110
110
  })
111
111
  return RequestExecution
112
112
  })
@@ -122,9 +122,9 @@ addHook({ name: 'cassandra-driver', versions: ['3.3 - 4.3'], file: 'lib/request-
122
122
  return start.apply(this, arguments)
123
123
  }
124
124
 
125
- arguments[0] = function () {
125
+ arguments[0] = function (...args) {
126
126
  startCtx = { hostname: execution._connection.address, port: execution._connection.port, ...startCtx }
127
- return connectCh.runStores(startCtx, getHostCallback, this, ...arguments)
127
+ return connectCh.runStores(startCtx, getHostCallback, this, ...args)
128
128
  }
129
129
 
130
130
  return start.apply(this, arguments)
@@ -143,9 +143,9 @@ addHook({ name: 'cassandra-driver', versions: ['3 - 3.2'], file: 'lib/request-ha
143
143
  return send.apply(this, arguments)
144
144
  }
145
145
 
146
- arguments[2] = function () {
146
+ arguments[2] = function (...args) {
147
147
  startCtx = { hostname: handler.connection.address, port: handler.connection.port, ...startCtx }
148
- return connectCh.runStores(startCtx, callback, this, ...arguments)
148
+ return connectCh.runStores(startCtx, callback, this, ...args)
149
149
  }
150
150
 
151
151
  return send.apply(this, arguments)
@@ -82,12 +82,12 @@ function createContextFromChildProcessInfo (childProcessInfo) {
82
82
 
83
83
  function wrapChildProcessSyncMethod (returnError, shell = false) {
84
84
  return function wrapMethod (childProcessMethod) {
85
- return function () {
86
- if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
87
- return childProcessMethod.apply(this, arguments)
85
+ return function (...args) {
86
+ if (!childProcessChannel.start.hasSubscribers || args.length === 0) {
87
+ return childProcessMethod.apply(this, args)
88
88
  }
89
89
 
90
- const callArgs = [...arguments]
90
+ const callArgs = [...args]
91
91
  const childProcessInfo = normalizeArgs(callArgs, shell)
92
92
  const context = createContextFromChildProcessInfo(childProcessInfo)
93
93
  context.callArgs = callArgs
@@ -118,12 +118,12 @@ function wrapChildProcessSyncMethod (returnError, shell = false) {
118
118
  }
119
119
 
120
120
  function wrapChildProcessCustomPromisifyMethod (customPromisifyMethod, shell) {
121
- return function () {
122
- if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
123
- return customPromisifyMethod.apply(this, arguments)
121
+ return function (...args) {
122
+ if (!childProcessChannel.start.hasSubscribers || args.length === 0) {
123
+ return customPromisifyMethod.apply(this, args)
124
124
  }
125
125
 
126
- const callArgs = [...arguments]
126
+ const callArgs = [...args]
127
127
  const childProcessInfo = normalizeArgs(callArgs, shell)
128
128
 
129
129
  const context = createContextFromChildProcessInfo(childProcessInfo)
@@ -170,12 +170,12 @@ function wrapChildProcessCustomPromisifyMethod (customPromisifyMethod, shell) {
170
170
 
171
171
  function wrapChildProcessAsyncMethod (ChildProcess, shell = false) {
172
172
  return function wrapMethod (childProcessMethod) {
173
- function wrappedChildProcessMethod () {
174
- if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
175
- return childProcessMethod.apply(this, arguments)
173
+ function wrappedChildProcessMethod (...args) {
174
+ if (!childProcessChannel.start.hasSubscribers || args.length === 0) {
175
+ return childProcessMethod.apply(this, args)
176
176
  }
177
177
 
178
- const callArgs = [...arguments]
178
+ const callArgs = [...args]
179
179
  const childProcessInfo = normalizeArgs(callArgs, shell)
180
180
 
181
181
  const context = createContextFromChildProcessInfo(childProcessInfo)
@@ -47,8 +47,8 @@ function instrumentBaseModule (module) {
47
47
  // Helper function to wrap producer classes
48
48
  function wrapProducerClass (ProducerClass, className) {
49
49
  return shimmer.wrap(module, className, function wrapProducer (Original) {
50
- return function wrappedProducer () {
51
- const producer = new Original(...arguments)
50
+ return function wrappedProducer (...args) {
51
+ const producer = new Original(...args)
52
52
 
53
53
  // Hook the produce method
54
54
  if (typeof producer?.produce === 'function') {
@@ -94,9 +94,9 @@ function instrumentBaseModule (module) {
94
94
  // Helper function to wrap consumer classes
95
95
  function wrapConsumerClass (ConsumerClass, className) {
96
96
  return shimmer.wrap(module, className, function wrapConsumer (Original) {
97
- return function wrappedConsumer () {
98
- const consumer = new Original(...arguments)
99
- const groupId = this.groupId || (arguments[0]?.['group.id'])
97
+ return function wrappedConsumer (...args) {
98
+ const consumer = new Original(...args)
99
+ const groupId = this.groupId || (args[0]?.['group.id'])
100
100
 
101
101
  // Wrap the consume method
102
102
  if (typeof consumer?.consume === 'function') {
@@ -196,11 +196,11 @@ function instrumentKafkaJS (kafkaJS) {
196
196
  // Wrap the producer method if it exists
197
197
  if (typeof kafka?.producer === 'function') {
198
198
  shimmer.wrap(kafka, 'producer', function wrapProducerMethod (producerMethod) {
199
- return function wrappedProducerMethod () {
200
- const producer = producerMethod.apply(this, arguments)
199
+ return function wrappedProducerMethod (...args) {
200
+ const producer = producerMethod.apply(this, args)
201
201
 
202
- if (!brokers && arguments?.[0]?.['bootstrap.servers']) {
203
- kafka._ddBrokers = arguments[0]['bootstrap.servers']
202
+ if (!brokers && args?.[0]?.['bootstrap.servers']) {
203
+ kafka._ddBrokers = args[0]['bootstrap.servers']
204
204
  }
205
205
 
206
206
  // Wrap the send method of the producer
@@ -59,16 +59,16 @@ function wrapLayerHandle (layer) {
59
59
 
60
60
  const original = layer.handle
61
61
 
62
- return shimmer.wrapFunction(original, original => function () {
63
- if (!enterChannel.hasSubscribers) return original.apply(this, arguments)
62
+ return shimmer.wrapFunction(original, original => function (...args) {
63
+ if (!enterChannel.hasSubscribers) return original.apply(this, args)
64
64
 
65
- const lastIndex = arguments.length - 1
65
+ const lastIndex = args.length - 1
66
66
  const name = original._name || original.name
67
- const req = arguments[arguments.length > 3 ? 1 : 0]
68
- const next = arguments[lastIndex]
67
+ const req = args[args.length > 3 ? 1 : 0]
68
+ const next = args[lastIndex]
69
69
 
70
70
  if (typeof next === 'function') {
71
- arguments[lastIndex] = wrapNext(req, next)
71
+ args[lastIndex] = wrapNext(req, next)
72
72
  }
73
73
 
74
74
  const route = layer.route
@@ -76,7 +76,7 @@ function wrapLayerHandle (layer) {
76
76
  enterChannel.publish({ name, req, route })
77
77
 
78
78
  try {
79
- return original.apply(this, arguments)
79
+ return original.apply(this, args)
80
80
  } catch (error) {
81
81
  errorChannel.publish({ req, error })
82
82
  nextChannel.publish({ req })
@@ -6,7 +6,7 @@ const { channel, addHook } = require('./helpers/instrument')
6
6
  const cookieParserReadCh = channel('datadog:cookie-parser:read:finish')
7
7
 
8
8
  function publishRequestCookieAndNext (req, res, next) {
9
- return shimmer.wrapFunction(next, next => function cookieParserWrapper () {
9
+ return shimmer.wrapFunction(next, next => function cookieParserWrapper (...args) {
10
10
  if (cookieParserReadCh.hasSubscribers && req) {
11
11
  const abortController = new AbortController()
12
12
 
@@ -17,7 +17,7 @@ function publishRequestCookieAndNext (req, res, next) {
17
17
  if (abortController.signal.aborted) return
18
18
  }
19
19
 
20
- return next.apply(this, arguments)
20
+ return next.apply(this, args)
21
21
  })
22
22
  }
23
23
 
@@ -25,8 +25,8 @@ addHook({
25
25
  name: 'cookie-parser',
26
26
  versions: ['>=1.0.0'],
27
27
  }, cookieParser => {
28
- return shimmer.wrapFunction(cookieParser, cookieParser => function () {
29
- const cookieMiddleware = cookieParser.apply(this, arguments)
28
+ return shimmer.wrapFunction(cookieParser, cookieParser => function (...args) {
29
+ const cookieMiddleware = cookieParser.apply(this, args)
30
30
 
31
31
  return shimmer.wrapFunction(cookieMiddleware, cookieMiddleware => function (req, res, next) {
32
32
  arguments[2] = publishRequestCookieAndNext(req, res, next)
@@ -6,8 +6,8 @@ const { channel, addHook } = require('./helpers/instrument')
6
6
  const cookieParseCh = channel('datadog:cookie:parse:finish')
7
7
 
8
8
  function wrapParse (originalParse) {
9
- return function () {
10
- const cookies = originalParse.apply(this, arguments)
9
+ return function (...args) {
10
+ const cookies = originalParse.apply(this, args)
11
11
  if (cookieParseCh.hasSubscribers && cookies) {
12
12
  cookieParseCh.publish({ cookies })
13
13
  }
@@ -77,25 +77,25 @@ function wrap (prefix, fn) {
77
77
  const finishCh = channel(prefix + ':finish')
78
78
  const errorCh = channel(prefix + ':error')
79
79
 
80
- const wrapped = function () {
80
+ return function (...args) {
81
81
  if (!startCh.hasSubscribers) {
82
- return fn.apply(this, arguments)
82
+ return fn.apply(this, args)
83
83
  }
84
84
 
85
- const callbackIndex = findCallbackIndex(arguments, 1)
85
+ const callbackIndex = findCallbackIndex(args, 1)
86
86
 
87
- if (callbackIndex < 0) return fn.apply(this, arguments)
87
+ if (callbackIndex < 0) return fn.apply(this, args)
88
88
 
89
89
  const ctx = { bucket: { name: this.name || this._name }, seedNodes: this._dd_hosts }
90
90
  return startCh.runStores(ctx, () => {
91
- const cb = arguments[callbackIndex]
91
+ const cb = args[callbackIndex]
92
92
 
93
- arguments[callbackIndex] = shimmer.wrapFunction(cb, (cb) => {
94
- return wrapCallbackFinish(cb, this, arguments, errorCh, finishCh, ctx, prefix)
93
+ args[callbackIndex] = shimmer.wrapFunction(cb, (cb) => {
94
+ return wrapCallbackFinish(cb, this, args, errorCh, finishCh, ctx, prefix)
95
95
  })
96
96
 
97
97
  try {
98
- return fn.apply(this, arguments)
98
+ return fn.apply(this, args)
99
99
  } catch (error) {
100
100
  ctx.error = error
101
101
  void error.stack // trigger getting the stack at the original throwing point
@@ -105,7 +105,6 @@ function wrap (prefix, fn) {
105
105
  }
106
106
  })
107
107
  }
108
- return wrapped
109
108
  }
110
109
 
111
110
  // semver >=2 <3
@@ -174,12 +173,12 @@ function wrapCBandPromise (fn, name, startData, thisArg, args) {
174
173
 
175
174
  function wrapWithName (name) {
176
175
  return function (operation) {
177
- return function () { // no arguments used by us
176
+ return function (...args) { // no arguments used by us
178
177
  return wrapCBandPromise(operation, name, {
179
178
  collection: { name: this._name || '_default' },
180
179
  bucket: { name: this._scope._bucket._name },
181
180
  seedNodes: this._dd_connStr,
182
- }, this, arguments)
181
+ }, this, args)
183
182
  }
184
183
  }
185
184
  }
@@ -240,8 +239,6 @@ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.12'] }, Buc
240
239
  wrapAllNames(['upsert', 'insert', 'replace', 'append', 'prepend'], name => {
241
240
  shimmer.wrap(Bucket.prototype, name, fn => wrap(`apm:couchbase:${name}`, fn))
242
241
  })
243
-
244
- return Bucket
245
242
  })
246
243
 
247
244
  addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.12'] }, Cluster => {
@@ -251,42 +248,36 @@ addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.12'] }, Cl
251
248
 
252
249
  shimmer.wrap(Cluster.prototype, 'query', query => wrapQuery(query))
253
250
  shimmer.wrap(Cluster.prototype, 'openBucket', openBucket => {
254
- return function () {
255
- const bucket = openBucket.apply(this, arguments)
251
+ return function (...args) {
252
+ const bucket = openBucket.apply(this, args)
256
253
  const hosts = this.dsnObj.hosts
257
254
  bucket._dd_hosts = hosts.map(hostAndPort => hostAndPort.join(':')).join(',')
258
255
  return bucket
259
256
  }
260
257
  })
261
- return Cluster
262
258
  })
263
259
 
264
260
  // semver >=3 <3.2.0
265
261
 
266
262
  addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^3.0.7', '^3.1.3'] }, Bucket => {
267
263
  shimmer.wrap(Bucket.prototype, 'collection', getCollection => {
268
- return function () {
269
- const collection = getCollection.apply(this, arguments)
264
+ return function (...args) {
265
+ const collection = getCollection.apply(this, args)
270
266
  const connStr = this._cluster._connStr
271
267
  collection._dd_connStr = connStr
272
268
  return collection
273
269
  }
274
270
  })
275
-
276
- return Bucket
277
271
  })
278
272
 
279
273
  addHook({ name: 'couchbase', file: 'lib/collection.js', versions: ['^3.0.7', '^3.1.3'] }, Collection => {
280
274
  wrapAllNames(['upsert', 'insert', 'replace'], name => {
281
275
  shimmer.wrap(Collection.prototype, name, wrapWithName(name))
282
276
  })
283
-
284
- return Collection
285
277
  })
286
278
 
287
279
  addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^3.0.7', '^3.1.3'] }, Cluster => {
288
280
  shimmer.wrap(Cluster.prototype, 'query', wrapV3Query)
289
- return Cluster
290
281
  })
291
282
 
292
283
  // semver >=3.2.2
@@ -298,27 +289,22 @@ addHook({ name: 'couchbase', file: 'dist/collection.js', versions: ['>=3.2.2'] }
298
289
  wrapAllNames(['upsert', 'insert', 'replace'], name => {
299
290
  shimmer.wrap(Collection.prototype, name, wrapWithName(name))
300
291
  })
301
-
302
- return collection
303
292
  })
304
293
 
305
294
  addHook({ name: 'couchbase', file: 'dist/bucket.js', versions: ['>=3.2.2'] }, bucket => {
306
295
  const Bucket = bucket.Bucket
307
296
  shimmer.wrap(Bucket.prototype, 'collection', getCollection => {
308
- return function () {
309
- const collection = getCollection.apply(this, arguments)
297
+ return function (...args) {
298
+ const collection = getCollection.apply(this, args)
310
299
  const connStr = this._cluster._connStr
311
300
  collection._dd_connStr = connStr
312
301
  return collection
313
302
  }
314
303
  })
315
-
316
- return bucket
317
304
  })
318
305
 
319
306
  addHook({ name: 'couchbase', file: 'dist/cluster.js', versions: ['>=3.2.2'] }, (cluster) => {
320
307
  const Cluster = cluster.Cluster
321
308
 
322
309
  shimmer.wrap(Cluster.prototype, 'query', wrapV3Query)
323
- return cluster
324
310
  })
@@ -47,12 +47,12 @@ addHook({ name: 'crypto' }, crypto => {
47
47
 
48
48
  function wrapCryptoMethod (channel) {
49
49
  function wrapMethod (cryptoMethod) {
50
- return function () {
51
- if (channel.hasSubscribers && arguments.length > 0) {
52
- const algorithm = arguments[0]
50
+ return function (...args) {
51
+ if (channel.hasSubscribers && args.length > 0) {
52
+ const algorithm = args[0]
53
53
  channel.publish({ algorithm })
54
54
  }
55
- return cryptoMethod.apply(this, arguments)
55
+ return cryptoMethod.apply(this, args)
56
56
  }
57
57
  }
58
58
  return wrapMethod
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { performance } = require('node:perf_hooks')
4
+
3
5
  const { createCoverageMap } = require('../../../vendor/dist/istanbul-lib-coverage')
4
6
  const shimmer = require('../../datadog-shimmer')
5
7
  const log = require('../../dd-trace/src/log')
@@ -12,6 +14,7 @@ const {
12
14
  getTestSuitePath,
13
15
  CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
14
16
  getIsFaultyEarlyFlakeDetection,
17
+ getEfdRetryCount,
15
18
  recordAttemptToFixExecution,
16
19
  collectAttemptToFixExecutionsFromTraces,
17
20
  logAttemptToFixTestExecution,
@@ -62,6 +65,9 @@ const lastStatusByPickleId = new Map()
62
65
  /** For ATR: statuses keyed by stable scenario id (uri:name) so retries accumulate correctly */
63
66
  const atrStatusesByScenarioKey = new Map()
64
67
  const numRetriesByPickleId = new Map()
68
+ const efdRetryCountByPickleId = new Map()
69
+ const efdSlowAbortedPickleIds = new Set()
70
+ const testCaseStartedTimesById = new Map()
65
71
  const numAttemptToCtx = new Map()
66
72
  const newTestsByTestFullname = new Map()
67
73
  const attemptToFixTestsByTestFullname = new Map()
@@ -82,6 +88,7 @@ let isUnskippable = false
82
88
  let isSuitesSkippingEnabled = false
83
89
  let isEarlyFlakeDetectionEnabled = false
84
90
  let earlyFlakeDetectionNumRetries = 0
91
+ let earlyFlakeDetectionSlowTestRetries = {}
85
92
  let earlyFlakeDetectionFaultyThreshold = 0
86
93
  let isEarlyFlakeDetectionFaulty = false
87
94
  let isFlakyTestRetriesEnabled = false
@@ -290,9 +297,9 @@ function wrapRun (pl, isLatestVersion, version) {
290
297
 
291
298
  patched.add(pl)
292
299
 
293
- shimmer.wrap(pl.prototype, 'run', run => function () {
300
+ shimmer.wrap(pl.prototype, 'run', run => function (...args) {
294
301
  if (!testFinishCh.hasSubscribers) {
295
- return run.apply(this, arguments)
302
+ return run.apply(this, args)
296
303
  }
297
304
 
298
305
  let numAttempt = 0
@@ -360,9 +367,10 @@ function wrapRun (pl, isLatestVersion, version) {
360
367
  }
361
368
  this.eventBroadcaster.on('envelope', onEnvelope)
362
369
  let promise
370
+ const executionStart = performance.now()
363
371
 
364
372
  testFnCh.runStores(ctx, () => {
365
- promise = run.apply(this, arguments)
373
+ promise = run.apply(this, args)
366
374
  })
367
375
  promise.finally(async () => {
368
376
  this.eventBroadcaster.removeListener('envelope', onEnvelope)
@@ -424,15 +432,31 @@ function wrapRun (pl, isLatestVersion, version) {
424
432
  isEfdRetry = numRetries > 0
425
433
  }
426
434
 
435
+ if (
436
+ isEarlyFlakeDetectionEnabled &&
437
+ status !== 'skip' &&
438
+ (isNew || isModified) &&
439
+ !isEfdRetry &&
440
+ !efdRetryCountByPickleId.has(this.pickle.id)
441
+ ) {
442
+ const retryCount = getEfdRetryCount(performance.now() - executionStart, earlyFlakeDetectionSlowTestRetries)
443
+ efdRetryCountByPickleId.set(this.pickle.id, retryCount)
444
+ if (retryCount === 0) {
445
+ efdSlowAbortedPickleIds.add(this.pickle.id)
446
+ }
447
+ }
448
+
449
+ const efdRetryCount = efdRetryCountByPickleId.get(this.pickle.id) ?? earlyFlakeDetectionNumRetries
450
+
427
451
  // Check if all EFD retries failed
428
452
  if (isEfdRetry && (isNew || isModified)) {
429
453
  const statuses = lastStatusByPickleId.get(this.pickle.id)
430
- if (statuses.length === earlyFlakeDetectionNumRetries + 1) {
454
+ if (statuses.length === efdRetryCount + 1) {
431
455
  const { fail } = statuses.reduce((acc, status) => {
432
456
  acc[status]++
433
457
  return acc
434
458
  }, { pass: 0, fail: 0 })
435
- if (fail === earlyFlakeDetectionNumRetries + 1) {
459
+ if (fail === efdRetryCount + 1) {
436
460
  hasFailedAllRetries = true
437
461
  }
438
462
  }
@@ -480,7 +504,7 @@ function wrapRun (pl, isLatestVersion, version) {
480
504
  const isLastAtrRetry = isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry && numTestRetries > 0
481
505
 
482
506
  const statuses = lastStatusByPickleId.get(this.pickle.id)
483
- const isLastEfdRetry = isEfdRetry && statuses?.length === earlyFlakeDetectionNumRetries + 1
507
+ const isLastEfdRetry = isEfdRetry && statuses?.length === efdRetryCount + 1
484
508
  const isLastAttemptToFixRetry = isAttemptToFix && statuses?.length === testManagementAttemptToFixRetries + 1
485
509
 
486
510
  // Intermediate (non-last EFD or ATF retries) executions do not report a final status
@@ -514,6 +538,7 @@ function wrapRun (pl, isLatestVersion, version) {
514
538
  isDisabled,
515
539
  isQuarantined,
516
540
  isModified,
541
+ earlyFlakeAbortReason: efdSlowAbortedPickleIds.has(this.pickle.id) ? 'slow' : undefined,
517
542
  ...attemptCtx.currentStore,
518
543
  finalStatus,
519
544
  })
@@ -526,11 +551,11 @@ function wrapRun (pl, isLatestVersion, version) {
526
551
  })
527
552
  }
528
553
  })
529
- shimmer.wrap(pl.prototype, 'runStep', runStep => function () {
554
+ shimmer.wrap(pl.prototype, 'runStep', runStep => function (...args) {
530
555
  if (!testFinishCh.hasSubscribers) {
531
- return runStep.apply(this, arguments)
556
+ return runStep.apply(this, args)
532
557
  }
533
- const testStep = arguments[0]
558
+ const testStep = args[0]
534
559
  let resource
535
560
 
536
561
  if (isLatestVersion) {
@@ -542,7 +567,7 @@ function wrapRun (pl, isLatestVersion, version) {
542
567
  const ctx = { resource }
543
568
  return testStepStartCh.runStores(ctx, () => {
544
569
  try {
545
- const promise = runStep.apply(this, arguments)
570
+ const promise = runStep.apply(this, args)
546
571
 
547
572
  promise.then((result) => {
548
573
  const finalResult = satisfies(version, '>=12.0.0') ? result.result : result
@@ -603,6 +628,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
603
628
 
604
629
  isEarlyFlakeDetectionEnabled = configurationResponse.libraryConfig?.isEarlyFlakeDetectionEnabled
605
630
  earlyFlakeDetectionNumRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionNumRetries
631
+ earlyFlakeDetectionSlowTestRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionSlowTestRetries ?? {}
606
632
  earlyFlakeDetectionFaultyThreshold = configurationResponse.libraryConfig?.earlyFlakeDetectionFaultyThreshold
607
633
  isSuitesSkippingEnabled = configurationResponse.libraryConfig?.isSuitesSkippingEnabled
608
634
  isFlakyTestRetriesEnabled = configurationResponse.libraryConfig?.isFlakyTestRetriesEnabled
@@ -692,6 +718,10 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
692
718
 
693
719
  atrStatusesByScenarioKey.clear()
694
720
  attemptToFixTestsByTestFullname.clear()
721
+ efdRetryCountByPickleId.clear()
722
+ efdSlowAbortedPickleIds.clear()
723
+ testCaseStartedTimesById.clear()
724
+ newTestsByTestFullname.clear()
695
725
  sessionStartCh.publish({ command, frameworkVersion })
696
726
 
697
727
  if (!errorSkippableRequest && skippedSuites.length) {
@@ -816,7 +846,9 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
816
846
  }
817
847
  }
818
848
  // TODO: for >=11 we could use `runTestCaseResult` instead of accumulating results in `lastStatusByPickleId`
849
+ const firstExecutionStart = performance.now()
819
850
  let runTestCaseResult = await runTestCaseFunction.apply(this, arguments)
851
+ const firstExecutionDurationMs = performance.now() - firstExecutionStart
820
852
 
821
853
  // Restore dryRun so it doesn't affect subsequent tests in the same worker
822
854
  this.options.dryRun = originalDryRun
@@ -835,7 +867,15 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
835
867
 
836
868
  // If it's a new test and it hasn't been skipped, we run it again
837
869
  if (isEarlyFlakeDetectionEnabled && lastTestStatus !== 'skip' && (isNew || isModified)) {
838
- for (let retryIndex = 0; retryIndex < earlyFlakeDetectionNumRetries; retryIndex++) {
870
+ let efdRetryCount = efdRetryCountByPickleId.get(pickle.id)
871
+ if (efdRetryCount === undefined) {
872
+ efdRetryCount = getEfdRetryCount(firstExecutionDurationMs, earlyFlakeDetectionSlowTestRetries)
873
+ efdRetryCountByPickleId.set(pickle.id, efdRetryCount)
874
+ if (efdRetryCount === 0) {
875
+ efdSlowAbortedPickleIds.add(pickle.id)
876
+ }
877
+ }
878
+ for (let retryIndex = 0; retryIndex < efdRetryCount; retryIndex++) {
839
879
  numRetriesByPickleId.set(pickle.id, retryIndex + 1)
840
880
  // eslint-disable-next-line no-await-in-loop
841
881
  runTestCaseResult = await runTestCaseFunction.apply(this, arguments)
@@ -952,6 +992,9 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
952
992
  let pickle
953
993
 
954
994
  if (parsed.testCaseStarted) {
995
+ if (parsed.testCaseStarted.id) {
996
+ testCaseStartedTimesById.set(parsed.testCaseStarted.id, performance.now())
997
+ }
955
998
  if (isNewVersion) {
956
999
  pickle = this.inProgress[worker.id].pickle
957
1000
  } else {
@@ -973,6 +1016,10 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
973
1016
 
974
1017
  // after calling `parseWorkerMessageFunction`, the test status can already be read
975
1018
  if (parsed.testCaseFinished) {
1019
+ const testCaseStartedId = parsed.testCaseFinished.testCaseStartedId
1020
+ const testCaseStartedAt = testCaseStartedTimesById.get(testCaseStartedId)
1021
+ testCaseStartedTimesById.delete(testCaseStartedId)
1022
+
976
1023
  let worstTestStepResult
977
1024
  if (isNewVersion && eventDataCollector) {
978
1025
  pickle = this.inProgress[worker.id].pickle
@@ -1003,8 +1050,19 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
1003
1050
  testStatuses = [status]
1004
1051
  newTestsByTestFullname.set(testFullname, testStatuses)
1005
1052
  }
1053
+ let efdRetryCount = efdRetryCountByPickleId.get(pickle.id)
1054
+ if (efdRetryCount === undefined) {
1055
+ const firstExecutionDurationMs = testCaseStartedAt === undefined ? 0 : performance.now() - testCaseStartedAt
1056
+ efdRetryCount = status === 'skip'
1057
+ ? 0
1058
+ : getEfdRetryCount(firstExecutionDurationMs, earlyFlakeDetectionSlowTestRetries)
1059
+ efdRetryCountByPickleId.set(pickle.id, efdRetryCount)
1060
+ if (efdRetryCount === 0 && status !== 'skip') {
1061
+ efdSlowAbortedPickleIds.add(pickle.id)
1062
+ }
1063
+ }
1006
1064
  // We have finished all retries
1007
- if (testStatuses.length === earlyFlakeDetectionNumRetries + 1) {
1065
+ if (testStatuses.length === efdRetryCount + 1) {
1008
1066
  const newTestFinalStatus = getTestStatusFromRetries(testStatuses)
1009
1067
  // we only push to `finished` if the retries have finished
1010
1068
  finished.push(newTestFinalStatus)
@@ -1143,9 +1201,9 @@ addHook({
1143
1201
  versions: ['>=11.0.0'],
1144
1202
  file: 'lib/formatter/helpers/event_data_collector.js',
1145
1203
  }, (eventDataCollectorPackage) => {
1146
- shimmer.wrap(eventDataCollectorPackage.default.prototype, 'parseEnvelope', parseEnvelope => function () {
1204
+ shimmer.wrap(eventDataCollectorPackage.default.prototype, 'parseEnvelope', parseEnvelope => function (...args) {
1147
1205
  eventDataCollector = this
1148
- return parseEnvelope.apply(this, arguments)
1206
+ return parseEnvelope.apply(this, args)
1149
1207
  })
1150
1208
  return eventDataCollectorPackage
1151
1209
  })
@@ -1164,18 +1222,20 @@ addHook({
1164
1222
  parseWorkerMessage => getWrappedParseWorkerMessage(parseWorkerMessage, true)
1165
1223
  )
1166
1224
  // EFD in parallel mode only supported in >=11.0.0
1167
- shimmer.wrap(adapterPackage.ChildProcessAdapter.prototype, 'startWorker', startWorker => function () {
1225
+ shimmer.wrap(adapterPackage.ChildProcessAdapter.prototype, 'startWorker', startWorker => function (...args) {
1168
1226
  if (isKnownTestsEnabled && isValidKnownTests(knownTests)) {
1169
1227
  this.options.worldParameters._ddIsKnownTestsEnabled = true
1170
1228
  this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
1171
1229
  this.options.worldParameters._ddKnownTests = knownTests
1172
1230
  this.options.worldParameters._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
1231
+ this.options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries = earlyFlakeDetectionSlowTestRetries
1173
1232
  } else {
1174
1233
  isEarlyFlakeDetectionEnabled = false
1175
1234
  isKnownTestsEnabled = false
1176
1235
  this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled = false
1177
1236
  this.options.worldParameters._ddIsKnownTestsEnabled = false
1178
1237
  this.options.worldParameters._ddEarlyFlakeDetectionNumRetries = 0
1238
+ this.options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries = {}
1179
1239
  }
1180
1240
 
1181
1241
  if (isImpactedTestsEnabled) {
@@ -1192,7 +1252,7 @@ addHook({
1192
1252
  this.options.worldParameters._ddTestManagementAttemptToFixRetries = testManagementAttemptToFixRetries
1193
1253
  }
1194
1254
 
1195
- return startWorker.apply(this, arguments)
1255
+ return startWorker.apply(this, args)
1196
1256
  })
1197
1257
  return adapterPackage
1198
1258
  })
@@ -1222,6 +1282,7 @@ addHook({
1222
1282
  isEarlyFlakeDetectionEnabled = !!this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled
1223
1283
  if (isEarlyFlakeDetectionEnabled) {
1224
1284
  earlyFlakeDetectionNumRetries = this.options.worldParameters._ddEarlyFlakeDetectionNumRetries
1285
+ earlyFlakeDetectionSlowTestRetries = this.options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries ?? {}
1225
1286
  }
1226
1287
  isImpactedTestsEnabled = !!this.options.worldParameters._ddImpactedTestsEnabled
1227
1288
  if (isImpactedTestsEnabled) {