dd-trace 5.103.0 → 5.105.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/LICENSE-3rdparty.csv +90 -102
  2. package/index.d.ts +107 -6
  3. package/package.json +18 -17
  4. package/packages/datadog-core/src/storage.js +1 -1
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/ai.js +8 -7
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +15 -2
  8. package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
  10. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
  11. package/packages/datadog-instrumentations/src/cucumber.js +181 -35
  12. package/packages/datadog-instrumentations/src/dns.js +54 -18
  13. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  14. package/packages/datadog-instrumentations/src/fastify.js +142 -82
  15. package/packages/datadog-instrumentations/src/graphql.js +188 -67
  16. package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
  17. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
  18. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
  21. package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
  22. package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
  23. package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
  24. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +31 -229
  32. package/packages/datadog-instrumentations/src/hono.js +54 -3
  33. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  34. package/packages/datadog-instrumentations/src/http/server.js +9 -4
  35. package/packages/datadog-instrumentations/src/ioredis.js +3 -3
  36. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
  37. package/packages/datadog-instrumentations/src/jest.js +390 -183
  38. package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
  39. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  40. package/packages/datadog-instrumentations/src/memcached.js +2 -1
  41. package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
  42. package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
  43. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  44. package/packages/datadog-instrumentations/src/mongoose.js +10 -12
  45. package/packages/datadog-instrumentations/src/mysql.js +2 -2
  46. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  47. package/packages/datadog-instrumentations/src/nats.js +182 -0
  48. package/packages/datadog-instrumentations/src/nyc.js +38 -1
  49. package/packages/datadog-instrumentations/src/openai.js +33 -18
  50. package/packages/datadog-instrumentations/src/oracledb.js +6 -1
  51. package/packages/datadog-instrumentations/src/pg.js +1 -1
  52. package/packages/datadog-instrumentations/src/pino.js +17 -5
  53. package/packages/datadog-instrumentations/src/playwright.js +537 -297
  54. package/packages/datadog-instrumentations/src/router.js +80 -34
  55. package/packages/datadog-instrumentations/src/stripe.js +1 -1
  56. package/packages/datadog-instrumentations/src/vitest.js +246 -149
  57. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  58. package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
  59. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
  60. package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
  61. package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
  62. package/packages/datadog-plugin-bunyan/src/index.js +28 -0
  63. package/packages/datadog-plugin-cucumber/src/index.js +17 -3
  64. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +223 -45
  65. package/packages/datadog-plugin-cypress/src/support.js +69 -1
  66. package/packages/datadog-plugin-dns/src/lookup.js +8 -6
  67. package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
  68. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
  69. package/packages/datadog-plugin-graphql/src/execute.js +2 -0
  70. package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
  71. package/packages/datadog-plugin-graphql/src/utils.js +4 -1
  72. package/packages/datadog-plugin-http/src/server.js +40 -15
  73. package/packages/datadog-plugin-jest/src/index.js +11 -3
  74. package/packages/datadog-plugin-jest/src/util.js +15 -8
  75. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  76. package/packages/datadog-plugin-kafkajs/src/producer.js +35 -0
  77. package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
  78. package/packages/datadog-plugin-mocha/src/index.js +19 -4
  79. package/packages/datadog-plugin-mongodb-core/src/index.js +311 -35
  80. package/packages/datadog-plugin-nats/src/consumer.js +43 -0
  81. package/packages/datadog-plugin-nats/src/index.js +20 -0
  82. package/packages/datadog-plugin-nats/src/producer.js +62 -0
  83. package/packages/datadog-plugin-nats/src/util.js +33 -0
  84. package/packages/datadog-plugin-next/src/index.js +5 -3
  85. package/packages/datadog-plugin-openai/src/tracing.js +15 -2
  86. package/packages/datadog-plugin-oracledb/src/index.js +13 -2
  87. package/packages/datadog-plugin-pino/src/index.js +42 -0
  88. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  89. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  90. package/packages/datadog-plugin-redis/src/index.js +37 -2
  91. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  92. package/packages/datadog-plugin-router/src/index.js +33 -44
  93. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  94. package/packages/datadog-plugin-undici/src/index.js +19 -0
  95. package/packages/datadog-plugin-vitest/src/index.js +24 -20
  96. package/packages/datadog-plugin-winston/src/index.js +30 -0
  97. package/packages/datadog-shimmer/src/shimmer.js +49 -21
  98. package/packages/dd-trace/src/aiguard/index.js +1 -1
  99. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  100. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  101. package/packages/dd-trace/src/appsec/blocking.js +2 -2
  102. package/packages/dd-trace/src/appsec/index.js +11 -4
  103. package/packages/dd-trace/src/appsec/reporter.js +24 -11
  104. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  105. package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
  106. package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
  107. package/packages/dd-trace/src/baggage.js +7 -1
  108. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
  109. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
  110. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
  111. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
  112. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
  113. package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
  114. package/packages/dd-trace/src/config/supported-configurations.json +36 -8
  115. package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
  116. package/packages/dd-trace/src/datastreams/context.js +4 -2
  117. package/packages/dd-trace/src/datastreams/writer.js +2 -4
  118. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
  119. package/packages/dd-trace/src/encode/0.4.js +124 -108
  120. package/packages/dd-trace/src/encode/0.5.js +114 -26
  121. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +57 -42
  122. package/packages/dd-trace/src/encode/agentless-json.js +4 -2
  123. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
  124. package/packages/dd-trace/src/encode/span-stats.js +16 -16
  125. package/packages/dd-trace/src/encode/tags-processors.js +16 -0
  126. package/packages/dd-trace/src/exporters/common/agents.js +3 -1
  127. package/packages/dd-trace/src/exporters/common/request.js +3 -1
  128. package/packages/dd-trace/src/id.js +17 -4
  129. package/packages/dd-trace/src/lambda/handler.js +2 -4
  130. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  131. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  132. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  133. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
  134. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  135. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
  136. package/packages/dd-trace/src/llmobs/sdk.js +10 -16
  137. package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
  138. package/packages/dd-trace/src/llmobs/tagger.js +9 -1
  139. package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
  140. package/packages/dd-trace/src/llmobs/util.js +66 -3
  141. package/packages/dd-trace/src/log/index.js +1 -1
  142. package/packages/dd-trace/src/log/writer.js +3 -1
  143. package/packages/dd-trace/src/msgpack/chunk.js +394 -10
  144. package/packages/dd-trace/src/msgpack/index.js +96 -2
  145. package/packages/dd-trace/src/noop/span.js +3 -1
  146. package/packages/dd-trace/src/openfeature/encoding.js +70 -0
  147. package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
  148. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
  149. package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
  150. package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
  151. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
  152. package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
  153. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  154. package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
  155. package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
  156. package/packages/dd-trace/src/opentracing/span.js +59 -19
  157. package/packages/dd-trace/src/opentracing/span_context.js +49 -0
  158. package/packages/dd-trace/src/plugins/apollo.js +3 -1
  159. package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
  160. package/packages/dd-trace/src/plugins/database.js +7 -6
  161. package/packages/dd-trace/src/plugins/index.js +4 -0
  162. package/packages/dd-trace/src/plugins/log_injection.js +56 -0
  163. package/packages/dd-trace/src/plugins/log_plugin.js +3 -46
  164. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  165. package/packages/dd-trace/src/plugins/plugin.js +15 -17
  166. package/packages/dd-trace/src/plugins/tracing.js +48 -8
  167. package/packages/dd-trace/src/plugins/util/git.js +3 -1
  168. package/packages/dd-trace/src/plugins/util/test.js +318 -13
  169. package/packages/dd-trace/src/plugins/util/web.js +89 -64
  170. package/packages/dd-trace/src/priority_sampler.js +2 -2
  171. package/packages/dd-trace/src/profiling/profiler.js +2 -2
  172. package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
  173. package/packages/dd-trace/src/sampling_rule.js +7 -7
  174. package/packages/dd-trace/src/scope.js +7 -5
  175. package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
  176. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
  177. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  178. package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
  179. package/packages/dd-trace/src/span_format.js +190 -58
  180. package/packages/dd-trace/src/spanleak.js +1 -1
  181. package/packages/dd-trace/src/standalone/index.js +3 -3
  182. package/packages/dd-trace/src/tagger.js +0 -2
  183. package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
  184. package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
  185. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  186. package/vendor/dist/protobufjs/index.js +1 -1
  187. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  188. package/packages/dd-trace/src/msgpack/encoder.js +0 -308
  189. package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
  190. package/vendor/dist/opentracing/LICENSE +0 -201
  191. package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
  192. package/vendor/dist/opentracing/constants.d.ts +0 -61
  193. package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
  194. package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
  195. package/vendor/dist/opentracing/functions.d.ts +0 -20
  196. package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
  197. package/vendor/dist/opentracing/index.d.ts +0 -12
  198. package/vendor/dist/opentracing/index.js +0 -1
  199. package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
  200. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
  201. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
  202. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
  203. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
  204. package/vendor/dist/opentracing/noop.d.ts +0 -8
  205. package/vendor/dist/opentracing/reference.d.ts +0 -33
  206. package/vendor/dist/opentracing/span.d.ts +0 -147
  207. package/vendor/dist/opentracing/span_context.d.ts +0 -26
  208. package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
  209. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
  210. package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
  211. package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
  212. package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
  213. package/vendor/dist/opentracing/tracer.d.ts +0 -127
@@ -13,12 +13,12 @@ const tracers = new WeakSet()
13
13
  const wrappedModels = new WeakSet()
14
14
 
15
15
  /**
16
- * Publishes already-converted AI guard style messages to the AIGuard channel.
16
+ * Publishes already-converted AI-style messages to the AI Guard evaluation channel.
17
17
  *
18
- * @param {Array<object>} messages - AI guard style messages to evaluate
18
+ * @param {Array<object>} messages - AI-style messages to evaluate.
19
19
  * @returns {Promise<void>}
20
20
  */
21
- function publishToAIGuard (messages) {
21
+ function publishEvaluation (messages) {
22
22
  return new Promise((resolve, reject) => {
23
23
  aiguardChannel.publish({ messages, integration: 'ai', resolve, reject })
24
24
  })
@@ -47,10 +47,11 @@ function wrapModelWithAIGuard (model) {
47
47
 
48
48
  // Run AI Guard input evaluation and LLM call in parallel.
49
49
  // The LLM has no side effects so it is safe to discard its result if AI Guard blocks.
50
- return Promise.all([publishToAIGuard(inputMessages), originalResult])
50
+ return Promise.all([publishEvaluation(inputMessages), originalResult])
51
51
  .then(([, result]) => {
52
52
  if (!result.content?.length) return result
53
- return publishToAIGuard(buildOutputMessages(inputMessages, result.content))
53
+ const outputMessages = buildOutputMessages(inputMessages, result.content)
54
+ return publishEvaluation(outputMessages)
54
55
  .then(() => result)
55
56
  })
56
57
  }
@@ -70,7 +71,7 @@ function wrapModelWithAIGuard (model) {
70
71
 
71
72
  // Run AI Guard input evaluation and LLM call in parallel.
72
73
  // The LLM has no side effects so it is safe to discard its result if AI Guard blocks.
73
- return Promise.all([publishToAIGuard(inputMessages), originalResult])
74
+ return Promise.all([publishEvaluation(inputMessages), originalResult])
74
75
  .then(([, result]) => {
75
76
  const chunks = []
76
77
  const reader = result.stream.getReader()
@@ -89,7 +90,7 @@ function wrapModelWithAIGuard (model) {
89
90
  const content = toolCalls.length ? toolCalls : text ? [{ type: 'text', text }] : []
90
91
 
91
92
  const evaluate = content.length
92
- ? publishToAIGuard(buildOutputMessages(inputMessages, content))
93
+ ? publishEvaluation(buildOutputMessages(inputMessages, content))
93
94
  : Promise.resolve()
94
95
 
95
96
  return evaluate.then(() => {
@@ -198,7 +198,7 @@ function wrapSmithySend (send) {
198
198
  })
199
199
 
200
200
  if (typeof cb === 'function') {
201
- args[args.length - 1] = shimmer.wrapFunction(cb, cb => function (err, result) {
201
+ args[args.length - 1] = shimmer.wrapCallback(cb, cb => function (err, result) {
202
202
  addResponse(ctx, err, result)
203
203
 
204
204
  handleCompletion(result, ctx, channels)
@@ -270,7 +270,7 @@ function handleCompletion (result, ctx, channels) {
270
270
 
271
271
  function wrapCb (cb, channels, ctx) {
272
272
  // eslint-disable-next-line n/handle-callback-err
273
- return shimmer.wrapFunction(cb, cb => function wrappedCb (err, response) {
273
+ return shimmer.wrapCallback(cb, cb => function wrappedCb (err, response) {
274
274
  ctx = { request: ctx.request, response }
275
275
  return channels.responseStart.runStores(ctx, () => {
276
276
  try {
@@ -324,6 +324,19 @@ addHook({ name: '@aws-sdk/smithy-client', versions: ['>=3'] }, smithy => {
324
324
  return smithy
325
325
  })
326
326
 
327
+ // `@aws-sdk/client-*` >= 3.1046.0 dropped `@smithy/smithy-client` and now
328
+ // extends from `@smithy/core/client` directly. The `Client.send` contract is
329
+ // unchanged, but the host module moved -- patch the new home so the v3 hooks
330
+ // keep firing.
331
+ addHook({
332
+ name: '@smithy/core',
333
+ file: 'dist-cjs/submodules/client/index.js',
334
+ versions: ['>=3.24.0'],
335
+ }, smithyCoreClient => {
336
+ shimmer.wrap(smithyCoreClient.Client.prototype, 'send', wrapSmithySend)
337
+ return smithyCoreClient
338
+ })
339
+
327
340
  addHook({ name: 'aws-sdk', versions: ['>=2.3.0'] }, AWS => {
328
341
  shimmer.wrap(AWS.config, 'setPromisesDependency', setPromisesDependency => {
329
342
  return function wrappedSetPromisesDependency (dep) {
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const { addHook, getHooks } = require('./helpers/instrument')
4
+
5
+ for (const hook of getHooks('@azure/cosmos')) {
6
+ addHook(hook, exports => exports)
7
+ }
@@ -26,6 +26,9 @@ addHook({ name: '@azure/functions', versions: ['>=4'], patchDefault: false }, (a
26
26
  // Event Hub triggers
27
27
  shimmer.wrap(app, 'eventHub', wrapHandler)
28
28
 
29
+ // CosmosDB triggers
30
+ shimmer.wrap(app, 'cosmosDB', wrapHandler)
31
+
29
32
  return azureFunction
30
33
  })
31
34
 
@@ -29,9 +29,12 @@ addHook({ name: 'cassandra-driver', versions: ['>=3.0.0'] }, cassandra => {
29
29
 
30
30
  try {
31
31
  const res = batch.apply(this, arguments)
32
- if (typeof res === 'function' || !res) {
32
+ if (typeof res === 'function') {
33
33
  return wrapCallback(finishCh, errorCh, startCtx, res)
34
34
  }
35
+ if (!res) {
36
+ return res
37
+ }
35
38
  return res.then(
36
39
  () => finish(finishCh, errorCh, startCtx),
37
40
  err => finish(finishCh, errorCh, startCtx, err)
@@ -162,7 +165,7 @@ function finish (finishCh, errorCh, ctx, error) {
162
165
  }
163
166
 
164
167
  function wrapCallback (finishCh, errorCh, ctx, callback) {
165
- return shimmer.wrapFunction(callback, callback => function (err) {
168
+ return shimmer.wrapCallback(callback, callback => function (err) {
166
169
  if (err) {
167
170
  ctx.error = err
168
171
  errorCh.publish(ctx)
@@ -7,19 +7,26 @@ const shimmer = require('../../datadog-shimmer')
7
7
  const log = require('../../dd-trace/src/log')
8
8
  const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
9
9
  const {
10
- getCoveredFilenamesFromCoverage,
10
+ getCoveredFilesFromCoverage,
11
+ getExecutableFilesFromCoverage,
11
12
  resetCoverage,
12
13
  mergeCoverage,
13
14
  fromCoverageMapToCoverage,
14
15
  getTestSuitePath,
16
+ getRelativeCoverageFiles,
15
17
  CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
16
18
  getIsFaultyEarlyFlakeDetection,
17
19
  getEfdRetryCount,
20
+ getMaxEfdRetryCount,
21
+ applySkippedCoverageToCoverage,
22
+ getTestCoverageLinesPercentage,
18
23
  recordAttemptToFixExecution,
19
24
  collectAttemptToFixExecutionsFromTraces,
20
25
  logAttemptToFixTestExecution,
21
26
  logTestOptimizationSummary,
27
+ getTestOptimizationRequestResults,
22
28
  } = require('../../dd-trace/src/plugins/util/test')
29
+ const { writeCoverageBackfillToCache } = require('../../dd-trace/src/ci-visibility/test-optimization-cache')
23
30
  const satisfies = require('../../../vendor/dist/semifies')
24
31
  const { addHook, channel } = require('./helpers/instrument')
25
32
 
@@ -51,6 +58,8 @@ const itrSkippedSuitesCh = channel('ci:cucumber:itr:skipped-suites')
51
58
 
52
59
  const getCodeCoverageCh = channel('ci:nyc:get-coverage')
53
60
 
61
+ const DD_EFD_RETRY_COUNT_MESSAGE = '_ddEfdRetryCount'
62
+
54
63
  const isMarkedAsUnskippable = (pickle) => {
55
64
  return pickle.tags.some(tag => tag.name === '@datadog:unskippable')
56
65
  }
@@ -67,7 +76,7 @@ const atrStatusesByScenarioKey = new Map()
67
76
  const numRetriesByPickleId = new Map()
68
77
  const efdRetryCountByPickleId = new Map()
69
78
  const efdSlowAbortedPickleIds = new Set()
70
- const testCaseStartedTimesById = new Map()
79
+ const finishedParallelSuites = new Set()
71
80
  const numAttemptToCtx = new Map()
72
81
  const newTestsByTestFullname = new Map()
73
82
  const attemptToFixTestsByTestFullname = new Map()
@@ -82,10 +91,14 @@ let pickleByFile = {}
82
91
  const pickleResultByFile = {}
83
92
 
84
93
  let skippableSuites = []
94
+ let skippableSuitesCoverage = {}
95
+ let skippedSuitesCoverage = {}
85
96
  let itrCorrelationId = ''
86
97
  let isForcedToRun = false
87
98
  let isUnskippable = false
99
+ let isItrEnabled = false
88
100
  let isSuitesSkippingEnabled = false
101
+ let isCoverageReportUploadEnabled = false
89
102
  let isEarlyFlakeDetectionEnabled = false
90
103
  let earlyFlakeDetectionNumRetries = 0
91
104
  let earlyFlakeDetectionSlowTestRetries = {}
@@ -102,11 +115,55 @@ let numTestRetries = 0
102
115
  let knownTests = {}
103
116
  let skippedSuites = []
104
117
  let isSuitesSkipped = false
118
+ let repositoryRoot
105
119
 
106
120
  function isValidKnownTests (receivedKnownTests) {
107
121
  return !!receivedKnownTests.cucumber
108
122
  }
109
123
 
124
+ function hasSkippableSuitesCoverage () {
125
+ return skippableSuitesCoverage &&
126
+ typeof skippableSuitesCoverage === 'object' &&
127
+ Object.keys(skippableSuitesCoverage).length > 0
128
+ }
129
+
130
+ function isTiaCoverageBackfillEnabled () {
131
+ return isItrEnabled && isCoverageReportUploadEnabled
132
+ }
133
+
134
+ function getCoverageRootDir () {
135
+ return repositoryRoot || process.cwd()
136
+ }
137
+
138
+ function shouldReportCodeCoverageLinesPct (hasBackfilledCoverage) {
139
+ return !isSuitesSkipped || hasBackfilledCoverage
140
+ }
141
+
142
+ function getSkippedSuitesCoverageForRun () {
143
+ return isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
144
+ ? skippableSuitesCoverage
145
+ : {}
146
+ }
147
+
148
+ function applySkippedCoverageToCucumberCoverageMap () {
149
+ if (!isTiaCoverageBackfillEnabled()) return false
150
+ return applySkippedCoverageToCoverage(originalCoverageMap, skippedSuitesCoverage, getCoverageRootDir())
151
+ }
152
+
153
+ function getCucumberTestSessionCoverageFiles () {
154
+ return getRelativeCoverageFiles(getExecutableFilesFromCoverage(originalCoverageMap), getCoverageRootDir())
155
+ }
156
+
157
+ function resetSuiteSkippingRunState () {
158
+ skippableSuites = []
159
+ skippableSuitesCoverage = {}
160
+ skippedSuitesCoverage = {}
161
+ skippedSuites = []
162
+ isSuitesSkipped = false
163
+ repositoryRoot = undefined
164
+ writeCoverageBackfillToCache({})
165
+ }
166
+
110
167
  function getSuiteStatusFromTestStatuses (testStatuses) {
111
168
  if (testStatuses.includes('fail')) {
112
169
  return 'fail'
@@ -117,6 +174,68 @@ function getSuiteStatusFromTestStatuses (testStatuses) {
117
174
  return 'pass'
118
175
  }
119
176
 
177
+ function getConfiguredEfdRetryCount () {
178
+ const maxSlowTestRetryCount = getMaxEfdRetryCount(earlyFlakeDetectionSlowTestRetries)
179
+ return maxSlowTestRetryCount || earlyFlakeDetectionNumRetries
180
+ }
181
+
182
+ function publishWorkerEfdRetryCount (pickle, retryCount) {
183
+ if (typeof process.send !== 'function') return
184
+
185
+ try {
186
+ process.send({
187
+ [DD_EFD_RETRY_COUNT_MESSAGE]: {
188
+ pickleId: pickle.id,
189
+ retryCount,
190
+ testFileAbsolutePath: pickle.uri,
191
+ testName: pickle.name,
192
+ },
193
+ })
194
+ } catch {
195
+ // ignore IPC errors
196
+ }
197
+ }
198
+
199
+ function finishParallelSuiteIfDone (testFileAbsolutePath) {
200
+ const finished = pickleResultByFile[testFileAbsolutePath]
201
+ const expectedPickles = pickleByFile[testFileAbsolutePath]
202
+
203
+ if (!finished || !expectedPickles || finished.length !== expectedPickles.length) return
204
+ if (finishedParallelSuites.has(testFileAbsolutePath)) return
205
+
206
+ finishedParallelSuites.add(testFileAbsolutePath)
207
+ testSuiteFinishCh.publish({
208
+ status: getSuiteStatusFromTestStatuses(finished),
209
+ testSuitePath: getTestSuitePath(testFileAbsolutePath, process.cwd()),
210
+ })
211
+ }
212
+
213
+ function maybeRecordFinalParallelEfdStatus ({ pickleId, testFileAbsolutePath, testFullname }) {
214
+ const efdRetryCount = efdRetryCountByPickleId.get(pickleId)
215
+ const testStatuses = newTestsByTestFullname.get(testFullname)
216
+ const finished = pickleResultByFile[testFileAbsolutePath]
217
+
218
+ if (efdRetryCount === undefined || !testStatuses || !finished) return
219
+ if (testStatuses.length !== efdRetryCount + 1) return
220
+
221
+ finished.push(getTestStatusFromRetries(testStatuses))
222
+ newTestsByTestFullname.delete(testFullname)
223
+ finishParallelSuiteIfDone(testFileAbsolutePath)
224
+ }
225
+
226
+ function handleEfdRetryCountMessage (message) {
227
+ const { pickleId, retryCount, testFileAbsolutePath, testName } = message
228
+
229
+ if (!pickleId || typeof retryCount !== 'number' || !testFileAbsolutePath || !testName) return
230
+
231
+ efdRetryCountByPickleId.set(pickleId, retryCount)
232
+ maybeRecordFinalParallelEfdStatus({
233
+ pickleId,
234
+ testFileAbsolutePath,
235
+ testFullname: `${testFileAbsolutePath}:${testName}`,
236
+ })
237
+ }
238
+
120
239
  function getStatusFromResult (result) {
121
240
  if (result.status === 1) {
122
241
  return { status: 'pass' }
@@ -617,6 +736,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
617
736
  if (!libraryConfigurationCh.hasSubscribers) {
618
737
  return start.apply(this, arguments)
619
738
  }
739
+ resetSuiteSkippingRunState()
620
740
  const options = getCucumberOptions(this)
621
741
 
622
742
  if (!isParallel && this.adapter?.options) {
@@ -626,11 +746,14 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
626
746
 
627
747
  const configurationResponse = await getChannelPromise(libraryConfigurationCh, frameworkVersion)
628
748
 
749
+ repositoryRoot = configurationResponse.repositoryRoot
750
+ isItrEnabled = configurationResponse.libraryConfig?.isItrEnabled
629
751
  isEarlyFlakeDetectionEnabled = configurationResponse.libraryConfig?.isEarlyFlakeDetectionEnabled
630
752
  earlyFlakeDetectionNumRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionNumRetries
631
753
  earlyFlakeDetectionSlowTestRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionSlowTestRetries ?? {}
632
754
  earlyFlakeDetectionFaultyThreshold = configurationResponse.libraryConfig?.earlyFlakeDetectionFaultyThreshold
633
- isSuitesSkippingEnabled = configurationResponse.libraryConfig?.isSuitesSkippingEnabled
755
+ isSuitesSkippingEnabled = isItrEnabled && configurationResponse.libraryConfig?.isSuitesSkippingEnabled
756
+ isCoverageReportUploadEnabled = configurationResponse.libraryConfig?.isCoverageReportUploadEnabled
634
757
  isFlakyTestRetriesEnabled = configurationResponse.libraryConfig?.isFlakyTestRetriesEnabled
635
758
  const configRetryCount = configurationResponse.libraryConfig?.flakyTestRetriesCount
636
759
  numTestRetries = (typeof configRetryCount === 'number' && configRetryCount > 0) ? configRetryCount : 0
@@ -639,21 +762,35 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
639
762
  testManagementAttemptToFixRetries = configurationResponse.libraryConfig?.testManagementAttemptToFixRetries
640
763
  isImpactedTestsEnabled = configurationResponse.libraryConfig?.isImpactedTestsEnabled
641
764
 
765
+ const {
766
+ knownTestsResponse,
767
+ testManagementTestsResponse,
768
+ skippableSuitesResponse,
769
+ } = await getTestOptimizationRequestResults({
770
+ isKnownTestsEnabled,
771
+ isTestManagementTestsEnabled,
772
+ isSuitesSkippingEnabled,
773
+ getKnownTests: () => getChannelPromise(knownTestsCh),
774
+ getTestManagementTests: () => getChannelPromise(testManagementTestsCh),
775
+ getSkippableSuites: () => getChannelPromise(skippableSuitesCh),
776
+ })
777
+
642
778
  if (isKnownTestsEnabled) {
643
- const knownTestsResponse = await getChannelPromise(knownTestsCh)
644
- if (knownTestsResponse.err) {
779
+ const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
780
+ if (currentKnownTestsResponse.err) {
645
781
  isEarlyFlakeDetectionEnabled = false
646
782
  isKnownTestsEnabled = false
647
783
  } else {
648
- knownTests = knownTestsResponse.knownTests
784
+ knownTests = currentKnownTestsResponse.knownTests
649
785
  }
650
786
  }
651
787
 
652
788
  if (isSuitesSkippingEnabled) {
653
- const skippableResponse = await getChannelPromise(skippableSuitesCh)
789
+ const skippableResponse = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
654
790
 
655
791
  errorSkippableRequest = skippableResponse.err
656
792
  skippableSuites = skippableResponse.skippableSuites ?? []
793
+ skippableSuitesCoverage = skippableResponse.skippableSuitesCoverage ?? {}
657
794
 
658
795
  if (!errorSkippableRequest) {
659
796
  const filteredPickles = isCoordinator
@@ -674,6 +811,8 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
674
811
  }
675
812
 
676
813
  skippedSuites = [...filteredPickles.skippedSuites]
814
+ skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
815
+ writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
677
816
  itrCorrelationId = skippableResponse.itrCorrelationId
678
817
  }
679
818
  }
@@ -694,11 +833,12 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
694
833
  }
695
834
 
696
835
  if (isTestManagementTestsEnabled) {
697
- const testManagementTestsResponse = await getChannelPromise(testManagementTestsCh)
698
- if (testManagementTestsResponse.err) {
836
+ const currentTestManagementTestsResponse =
837
+ testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
838
+ if (currentTestManagementTestsResponse.err) {
699
839
  isTestManagementTestsEnabled = false
700
840
  } else {
701
- testManagementTests = testManagementTestsResponse.testManagementTests
841
+ testManagementTests = currentTestManagementTestsResponse.testManagementTests
702
842
  }
703
843
  }
704
844
 
@@ -720,7 +860,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
720
860
  attemptToFixTestsByTestFullname.clear()
721
861
  efdRetryCountByPickleId.clear()
722
862
  efdSlowAbortedPickleIds.clear()
723
- testCaseStartedTimesById.clear()
863
+ finishedParallelSuites.clear()
724
864
  newTestsByTestFullname.clear()
725
865
  sessionStartCh.publish({ command, frameworkVersion })
726
866
 
@@ -736,13 +876,25 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
736
876
  }
737
877
 
738
878
  let testCodeCoverageLinesTotal
879
+ let testSessionCoverageFiles
739
880
 
740
- if (global.__coverage__) {
881
+ if (global.__coverage__ || untestedCoverage) {
741
882
  try {
883
+ let hasBackfilledCoverage = false
742
884
  if (untestedCoverage) {
743
885
  originalCoverageMap.merge(fromCoverageMapToCoverage(untestedCoverage))
744
886
  }
745
- testCodeCoverageLinesTotal = originalCoverageMap.getCoverageSummary().lines.pct
887
+ hasBackfilledCoverage = applySkippedCoverageToCucumberCoverageMap()
888
+ if (shouldReportCodeCoverageLinesPct(hasBackfilledCoverage)) {
889
+ testCodeCoverageLinesTotal = getTestCoverageLinesPercentage(
890
+ originalCoverageMap,
891
+ undefined,
892
+ getCoverageRootDir()
893
+ )
894
+ }
895
+ if (isTiaCoverageBackfillEnabled()) {
896
+ testSessionCoverageFiles = getCucumberTestSessionCoverageFiles()
897
+ }
746
898
  } catch {
747
899
  // ignore errors
748
900
  }
@@ -754,6 +906,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
754
906
  status: success ? 'pass' : 'fail',
755
907
  isSuitesSkipped,
756
908
  testCodeCoverageLinesTotal,
909
+ testSessionCoverageFiles,
757
910
  numSkippedSuites: skippedSuites.length,
758
911
  hasUnskippableSuites: isUnskippable,
759
912
  hasForcedToRunSuites: isForcedToRun,
@@ -875,6 +1028,9 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
875
1028
  efdSlowAbortedPickleIds.add(pickle.id)
876
1029
  }
877
1030
  }
1031
+ if (isWorker) {
1032
+ publishWorkerEfdRetryCount(pickle, efdRetryCount)
1033
+ }
878
1034
  for (let retryIndex = 0; retryIndex < efdRetryCount; retryIndex++) {
879
1035
  numRetriesByPickleId.set(pickle.id, retryIndex + 1)
880
1036
  // eslint-disable-next-line no-await-in-loop
@@ -925,7 +1081,7 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
925
1081
  // last test in suite
926
1082
  const testSuiteStatus = getSuiteStatusFromTestStatuses(pickleResultByFile[testFileAbsolutePath])
927
1083
  if (global.__coverage__) {
928
- const coverageFiles = getCoveredFilenamesFromCoverage(global.__coverage__)
1084
+ const coverageFiles = getCoveredFilesFromCoverage(global.__coverage__)
929
1085
 
930
1086
  testSuiteCodeCoverageCh.publish({
931
1087
  coverageFiles,
@@ -973,6 +1129,10 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
973
1129
  return
974
1130
  }
975
1131
  }
1132
+ if (message[DD_EFD_RETRY_COUNT_MESSAGE]) {
1133
+ handleEfdRetryCountMessage(message[DD_EFD_RETRY_COUNT_MESSAGE])
1134
+ return
1135
+ }
976
1136
 
977
1137
  const envelope = isNewVersion ? message.envelope : message.jsonEnvelope
978
1138
 
@@ -989,12 +1149,13 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
989
1149
  return parseWorkerMessageFunction.apply(this, arguments)
990
1150
  }
991
1151
  }
1152
+ if (parsed[DD_EFD_RETRY_COUNT_MESSAGE]) {
1153
+ handleEfdRetryCountMessage(parsed[DD_EFD_RETRY_COUNT_MESSAGE])
1154
+ return
1155
+ }
992
1156
  let pickle
993
1157
 
994
1158
  if (parsed.testCaseStarted) {
995
- if (parsed.testCaseStarted.id) {
996
- testCaseStartedTimesById.set(parsed.testCaseStarted.id, performance.now())
997
- }
998
1159
  if (isNewVersion) {
999
1160
  pickle = this.inProgress[worker.id].pickle
1000
1161
  } else {
@@ -1016,10 +1177,6 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
1016
1177
 
1017
1178
  // after calling `parseWorkerMessageFunction`, the test status can already be read
1018
1179
  if (parsed.testCaseFinished) {
1019
- const testCaseStartedId = parsed.testCaseFinished.testCaseStartedId
1020
- const testCaseStartedAt = testCaseStartedTimesById.get(testCaseStartedId)
1021
- testCaseStartedTimesById.delete(testCaseStartedId)
1022
-
1023
1180
  let worstTestStepResult
1024
1181
  if (isNewVersion && eventDataCollector) {
1025
1182
  pickle = this.inProgress[worker.id].pickle
@@ -1052,21 +1209,15 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
1052
1209
  }
1053
1210
  let efdRetryCount = efdRetryCountByPickleId.get(pickle.id)
1054
1211
  if (efdRetryCount === undefined) {
1055
- const firstExecutionDurationMs = testCaseStartedAt === undefined ? 0 : performance.now() - testCaseStartedAt
1056
1212
  efdRetryCount = status === 'skip'
1057
1213
  ? 0
1058
- : getEfdRetryCount(firstExecutionDurationMs, earlyFlakeDetectionSlowTestRetries)
1214
+ : getConfiguredEfdRetryCount()
1059
1215
  efdRetryCountByPickleId.set(pickle.id, efdRetryCount)
1060
1216
  if (efdRetryCount === 0 && status !== 'skip') {
1061
1217
  efdSlowAbortedPickleIds.add(pickle.id)
1062
1218
  }
1063
1219
  }
1064
- // We have finished all retries
1065
- if (testStatuses.length === efdRetryCount + 1) {
1066
- const newTestFinalStatus = getTestStatusFromRetries(testStatuses)
1067
- // we only push to `finished` if the retries have finished
1068
- finished.push(newTestFinalStatus)
1069
- }
1220
+ maybeRecordFinalParallelEfdStatus({ pickleId: pickle.id, testFileAbsolutePath, testFullname })
1070
1221
  } else if (
1071
1222
  isTestManagementTestsEnabled &&
1072
1223
  getTestProperties(getTestSuitePath(testFileAbsolutePath, process.cwd()), pickle.name).attemptToFix
@@ -1090,12 +1241,7 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
1090
1241
  finished.push(status)
1091
1242
  }
1092
1243
 
1093
- if (finished.length === pickleByFile[testFileAbsolutePath].length) {
1094
- testSuiteFinishCh.publish({
1095
- status: getSuiteStatusFromTestStatuses(finished),
1096
- testSuitePath: getTestSuitePath(testFileAbsolutePath, process.cwd()),
1097
- })
1098
- }
1244
+ finishParallelSuiteIfDone(testFileAbsolutePath)
1099
1245
  }
1100
1246
 
1101
1247
  return parseWorkerResponse
@@ -3,6 +3,7 @@
3
3
  const shimmer = require('../../datadog-shimmer')
4
4
  const { addHook } = require('./helpers/instrument')
5
5
  const { createCallbackInstrumentor } = require('./helpers/callback-instrumentor')
6
+ const { createPromiseInstrumentor } = require('./helpers/promise-instrumentor')
6
7
 
7
8
  const rrtypes = {
8
9
  resolveAny: 'ANY',
@@ -18,30 +19,55 @@ const rrtypes = {
18
19
  resolveSoa: 'SOA',
19
20
  }
20
21
 
21
- addHook({ name: 'dns' }, dns => {
22
- const lookup = createCallbackInstrumentor('apm:dns:lookup', { captureResult: true })
23
- const lookupService = createCallbackInstrumentor('apm:dns:lookup_service', { captureResult: true })
24
- const resolve = createCallbackInstrumentor('apm:dns:resolve', { captureResult: true })
25
- const reverse = createCallbackInstrumentor('apm:dns:reverse', { captureResult: true })
26
-
27
- shimmer.wrap(dns, 'lookup', lookup(buildArgsContext()))
28
- shimmer.wrap(dns, 'lookupService', lookupService(buildArgsContext()))
29
- shimmer.wrap(dns, 'resolve', resolve(buildArgsContext()))
30
- shimmer.wrap(dns, 'reverse', reverse(buildArgsContext()))
31
-
32
- patchResolveShorthands(dns, resolve)
22
+ // `dns.promises` and `require('dns/promises')` resolve to the same exports object. Both
23
+ // access paths register a hook, so without a guard the second hook to fire would stack a
24
+ // second wrap layer on top and publish every `apm:dns:*` event twice per call. The WeakSet
25
+ // collapses the two hooks to one wrap regardless of which one runs first.
26
+ const wrappedPromiseApis = new WeakSet()
33
27
 
34
- if (dns.Resolver) {
35
- shimmer.wrap(dns.Resolver.prototype, 'resolve', resolve(buildArgsContext()))
36
- shimmer.wrap(dns.Resolver.prototype, 'reverse', reverse(buildArgsContext()))
28
+ addHook({ name: 'dns' }, dns => {
29
+ patchApi(dns, createCallbackInstrumentor, buildCallbackArgsContext)
37
30
 
38
- patchResolveShorthands(dns.Resolver.prototype, resolve)
31
+ if (dns.promises) {
32
+ patchPromiseApi(dns.promises)
39
33
  }
40
34
 
41
35
  return dns
42
36
  })
43
37
 
44
- function patchResolveShorthands (prototype, resolve) {
38
+ addHook({ name: 'dns/promises' }, dnsPromises => {
39
+ patchPromiseApi(dnsPromises)
40
+ return dnsPromises
41
+ })
42
+
43
+ function patchPromiseApi (api) {
44
+ if (wrappedPromiseApis.has(api)) return
45
+ wrappedPromiseApis.add(api)
46
+ patchApi(api, createPromiseInstrumentor, buildPromiseArgsContext)
47
+ }
48
+
49
+ function patchApi (api, instrumentorFactory, buildArgsContext) {
50
+ const lookup = instrumentorFactory('apm:dns:lookup', { captureResult: true })
51
+ const lookupService = instrumentorFactory('apm:dns:lookup_service', { captureResult: true })
52
+ const resolve = instrumentorFactory('apm:dns:resolve', { captureResult: true })
53
+ const reverse = instrumentorFactory('apm:dns:reverse', { captureResult: true })
54
+
55
+ shimmer.wrap(api, 'lookup', lookup(buildArgsContext()))
56
+ shimmer.wrap(api, 'lookupService', lookupService(buildArgsContext()))
57
+ shimmer.wrap(api, 'resolve', resolve(buildArgsContext()))
58
+ shimmer.wrap(api, 'reverse', reverse(buildArgsContext()))
59
+
60
+ patchResolveShorthands(api, resolve, buildArgsContext)
61
+
62
+ if (api.Resolver) {
63
+ shimmer.wrap(api.Resolver.prototype, 'resolve', resolve(buildArgsContext()))
64
+ shimmer.wrap(api.Resolver.prototype, 'reverse', reverse(buildArgsContext()))
65
+
66
+ patchResolveShorthands(api.Resolver.prototype, resolve, buildArgsContext)
67
+ }
68
+ }
69
+
70
+ function patchResolveShorthands (prototype, resolve, buildArgsContext) {
45
71
  for (const method of Object.keys(rrtypes)) {
46
72
  if (prototype[method]) {
47
73
  shimmer.wrap(prototype, method, resolve(buildArgsContext(rrtypes[method])))
@@ -49,7 +75,7 @@ function patchResolveShorthands (prototype, resolve) {
49
75
  }
50
76
  }
51
77
 
52
- function buildArgsContext (rrtype) {
78
+ function buildCallbackArgsContext (rrtype) {
53
79
  return function (_, args) {
54
80
  if (args.length < 2) return
55
81
  const captured = [...args]
@@ -60,3 +86,13 @@ function buildArgsContext (rrtype) {
60
86
  return { args: captured }
61
87
  }
62
88
  }
89
+
90
+ function buildPromiseArgsContext (rrtype) {
91
+ return function (_, args) {
92
+ const captured = [...args]
93
+ if (rrtype) {
94
+ captured.push(rrtype)
95
+ }
96
+ return { args: captured }
97
+ }
98
+ }
@@ -51,9 +51,9 @@ function createWrapSelect () {
51
51
  const connectCh = channel('apm:elasticsearch:query:connect')
52
52
  return function wrapRequest (request) {
53
53
  return function (...args) {
54
- if (args.length === 1) {
55
- const cb = args[0]
56
- args[0] = shimmer.wrapFunction(cb, cb => function (err, connection) {
54
+ const cb = args[0]
55
+ if (args.length === 1 && typeof cb === 'function') {
56
+ args[0] = shimmer.wrapCallback(cb, cb => function (err, connection) {
57
57
  if (connectCh.hasSubscribers && connection && connection.host) {
58
58
  connectCh.publish({ hostname: connection.host.host, port: connection.host.port })
59
59
  }
@@ -85,7 +85,7 @@ function createWrapRequest (name) {
85
85
  cb = arguments[lastIndex]
86
86
 
87
87
  if (typeof cb === 'function') {
88
- arguments[lastIndex] = shimmer.wrapFunction(cb, cb => function (error) {
88
+ arguments[lastIndex] = shimmer.wrapCallback(cb, cb => function (error) {
89
89
  if (error) {
90
90
  ctx.error = error
91
91
  errorCh.publish(ctx)