dd-trace 3.3.1 → 3.12.1

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 (198) hide show
  1. package/LICENSE-3rdparty.csv +8 -0
  2. package/README.md +108 -43
  3. package/ci/init.js +6 -1
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +129 -36
  7. package/package.json +18 -9
  8. package/packages/datadog-instrumentations/src/body-parser.js +26 -0
  9. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  10. package/packages/datadog-instrumentations/src/child-process.js +30 -0
  11. package/packages/datadog-instrumentations/src/connect.js +15 -15
  12. package/packages/datadog-instrumentations/src/cucumber.js +1 -3
  13. package/packages/datadog-instrumentations/src/elasticsearch.js +51 -47
  14. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +1 -1
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +9 -0
  16. package/packages/datadog-instrumentations/src/helpers/register.js +5 -0
  17. package/packages/datadog-instrumentations/src/http/server.js +20 -12
  18. package/packages/datadog-instrumentations/src/http2/server.js +67 -1
  19. package/packages/datadog-instrumentations/src/jest.js +182 -25
  20. package/packages/datadog-instrumentations/src/koa.js +32 -32
  21. package/packages/datadog-instrumentations/src/ldapjs.js +91 -0
  22. package/packages/datadog-instrumentations/src/mariadb.js +63 -0
  23. package/packages/datadog-instrumentations/src/memcached.js +1 -4
  24. package/packages/datadog-instrumentations/src/mocha.js +135 -24
  25. package/packages/datadog-instrumentations/src/next.js +10 -2
  26. package/packages/datadog-instrumentations/src/opensearch.js +10 -0
  27. package/packages/datadog-instrumentations/src/oracledb.js +8 -8
  28. package/packages/datadog-instrumentations/src/pg.js +7 -3
  29. package/packages/datadog-instrumentations/src/qs.js +24 -0
  30. package/packages/datadog-instrumentations/src/redis.js +12 -3
  31. package/packages/datadog-instrumentations/src/restify.js +5 -1
  32. package/packages/datadog-instrumentations/src/rhea.js +29 -15
  33. package/packages/datadog-instrumentations/src/router.js +23 -23
  34. package/packages/datadog-plugin-amqp10/src/consumer.js +32 -0
  35. package/packages/datadog-plugin-amqp10/src/index.js +11 -101
  36. package/packages/datadog-plugin-amqp10/src/producer.js +34 -0
  37. package/packages/datadog-plugin-amqp10/src/util.js +15 -0
  38. package/packages/datadog-plugin-amqplib/src/client.js +38 -0
  39. package/packages/datadog-plugin-amqplib/src/consumer.js +40 -0
  40. package/packages/datadog-plugin-amqplib/src/index.js +14 -102
  41. package/packages/datadog-plugin-amqplib/src/producer.js +37 -0
  42. package/packages/datadog-plugin-amqplib/src/util.js +14 -0
  43. package/packages/datadog-plugin-cassandra-driver/src/index.js +22 -60
  44. package/packages/datadog-plugin-cucumber/src/index.js +14 -33
  45. package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
  46. package/packages/datadog-plugin-dns/src/index.js +16 -91
  47. package/packages/datadog-plugin-dns/src/lookup.js +40 -0
  48. package/packages/datadog-plugin-dns/src/lookup_service.js +24 -0
  49. package/packages/datadog-plugin-dns/src/resolve.js +24 -0
  50. package/packages/datadog-plugin-dns/src/reverse.js +21 -0
  51. package/packages/datadog-plugin-elasticsearch/src/index.js +24 -60
  52. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +24 -0
  53. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +41 -0
  54. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +14 -99
  55. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +33 -0
  56. package/packages/datadog-plugin-graphql/src/execute.js +73 -0
  57. package/packages/datadog-plugin-graphql/src/index.js +14 -176
  58. package/packages/datadog-plugin-graphql/src/parse.js +32 -0
  59. package/packages/datadog-plugin-graphql/src/resolve.js +70 -76
  60. package/packages/datadog-plugin-graphql/src/validate.js +28 -0
  61. package/packages/datadog-plugin-grpc/src/client.js +46 -55
  62. package/packages/datadog-plugin-grpc/src/index.js +7 -24
  63. package/packages/datadog-plugin-grpc/src/server.js +50 -52
  64. package/packages/datadog-plugin-grpc/src/util.js +15 -14
  65. package/packages/datadog-plugin-http/src/client.js +15 -5
  66. package/packages/datadog-plugin-http/src/index.js +7 -22
  67. package/packages/datadog-plugin-http/src/server.js +19 -3
  68. package/packages/datadog-plugin-http2/src/client.js +20 -1
  69. package/packages/datadog-plugin-http2/src/index.js +8 -26
  70. package/packages/datadog-plugin-http2/src/server.js +44 -0
  71. package/packages/datadog-plugin-jest/src/index.js +41 -65
  72. package/packages/datadog-plugin-kafkajs/src/consumer.js +42 -0
  73. package/packages/datadog-plugin-kafkajs/src/index.js +11 -87
  74. package/packages/datadog-plugin-kafkajs/src/producer.js +31 -0
  75. package/packages/datadog-plugin-mariadb/src/index.js +10 -0
  76. package/packages/datadog-plugin-memcached/src/index.js +17 -52
  77. package/packages/datadog-plugin-mocha/src/index.js +40 -60
  78. package/packages/datadog-plugin-moleculer/src/client.js +22 -36
  79. package/packages/datadog-plugin-moleculer/src/index.js +8 -26
  80. package/packages/datadog-plugin-moleculer/src/server.js +18 -30
  81. package/packages/datadog-plugin-mongodb-core/src/index.js +23 -51
  82. package/packages/datadog-plugin-mysql/src/index.js +23 -52
  83. package/packages/datadog-plugin-mysql2/src/index.js +1 -3
  84. package/packages/datadog-plugin-net/src/index.js +4 -0
  85. package/packages/datadog-plugin-net/src/ipc.js +21 -0
  86. package/packages/datadog-plugin-net/src/tcp.js +46 -0
  87. package/packages/datadog-plugin-next/src/index.js +3 -0
  88. package/packages/datadog-plugin-opensearch/src/index.js +11 -0
  89. package/packages/datadog-plugin-oracledb/src/index.js +29 -55
  90. package/packages/datadog-plugin-pg/src/index.js +27 -51
  91. package/packages/datadog-plugin-redis/src/index.js +29 -60
  92. package/packages/datadog-plugin-rhea/src/consumer.js +55 -0
  93. package/packages/datadog-plugin-rhea/src/index.js +11 -96
  94. package/packages/datadog-plugin-rhea/src/producer.js +45 -0
  95. package/packages/datadog-plugin-router/src/index.js +13 -2
  96. package/packages/datadog-plugin-sharedb/src/index.js +22 -39
  97. package/packages/datadog-plugin-tedious/src/index.js +20 -41
  98. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  99. package/packages/dd-trace/src/appsec/blocking.js +44 -0
  100. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +8 -6
  101. package/packages/dd-trace/src/appsec/gateway/engine/engine.js +1 -1
  102. package/packages/dd-trace/src/appsec/gateway/engine/index.js +7 -2
  103. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -1
  104. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +4 -1
  105. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
  106. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
  107. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +11 -0
  108. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
  109. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +43 -5
  110. package/packages/dd-trace/src/appsec/iast/iast-context.js +3 -1
  111. package/packages/dd-trace/src/appsec/iast/index.js +24 -8
  112. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +20 -1
  113. package/packages/dd-trace/src/appsec/iast/path-line.js +17 -6
  114. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +17 -0
  115. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
  116. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
  117. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +98 -0
  118. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
  119. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
  120. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +67 -0
  121. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +103 -0
  122. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +98 -30
  123. package/packages/dd-trace/src/appsec/index.js +79 -25
  124. package/packages/dd-trace/src/{plugins/util → appsec}/ip_blocklist.js +0 -0
  125. package/packages/dd-trace/src/appsec/ip_extractor.js +98 -0
  126. package/packages/dd-trace/src/appsec/recommended.json +134 -53
  127. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
  128. package/packages/dd-trace/src/appsec/remote_config/index.js +56 -0
  129. package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
  130. package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
  131. package/packages/dd-trace/src/appsec/rule_manager.js +61 -1
  132. package/packages/dd-trace/src/appsec/templates/blocked.html +99 -0
  133. package/packages/dd-trace/src/appsec/templates/blocked.json +8 -0
  134. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +66 -0
  135. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +9 -5
  136. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +19 -51
  137. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +10 -5
  138. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +202 -0
  139. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +51 -62
  140. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +89 -0
  141. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +82 -0
  142. package/packages/dd-trace/src/config.js +119 -35
  143. package/packages/dd-trace/src/constants.js +9 -1
  144. package/packages/dd-trace/src/dogstatsd.js +42 -10
  145. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +10 -2
  146. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  147. package/packages/dd-trace/src/exporter.js +3 -0
  148. package/packages/dd-trace/src/exporters/agent/index.js +10 -2
  149. package/packages/dd-trace/src/exporters/agent/writer.js +2 -9
  150. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +82 -0
  151. package/packages/dd-trace/src/exporters/common/request.js +51 -1
  152. package/packages/dd-trace/src/exporters/span-stats/index.js +6 -2
  153. package/packages/dd-trace/src/format.js +29 -10
  154. package/packages/dd-trace/src/lambda/handler.js +72 -0
  155. package/packages/dd-trace/src/lambda/index.js +5 -0
  156. package/packages/dd-trace/src/lambda/runtime/errors.js +20 -0
  157. package/packages/dd-trace/src/lambda/runtime/patch.js +74 -0
  158. package/packages/dd-trace/src/lambda/runtime/ritm.js +138 -0
  159. package/packages/dd-trace/src/metrics.js +15 -2
  160. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
  161. package/packages/dd-trace/src/opentracing/span.js +2 -1
  162. package/packages/dd-trace/src/opentracing/span_context.js +9 -0
  163. package/packages/dd-trace/src/plugin_manager.js +11 -17
  164. package/packages/dd-trace/src/plugins/cache.js +9 -0
  165. package/packages/dd-trace/src/plugins/ci_plugin.js +97 -0
  166. package/packages/dd-trace/src/plugins/client.js +9 -0
  167. package/packages/dd-trace/src/plugins/composite.js +26 -0
  168. package/packages/dd-trace/src/plugins/consumer.js +9 -0
  169. package/packages/dd-trace/src/plugins/database.js +55 -0
  170. package/packages/dd-trace/src/plugins/incoming.js +7 -0
  171. package/packages/dd-trace/src/plugins/index.js +3 -0
  172. package/packages/dd-trace/src/plugins/log_plugin.js +2 -2
  173. package/packages/dd-trace/src/plugins/outgoing.js +31 -0
  174. package/packages/dd-trace/src/plugins/plugin.js +3 -0
  175. package/packages/dd-trace/src/plugins/producer.js +9 -0
  176. package/packages/dd-trace/src/plugins/server.js +9 -0
  177. package/packages/dd-trace/src/plugins/storage.js +21 -0
  178. package/packages/dd-trace/src/plugins/tracing.js +94 -0
  179. package/packages/dd-trace/src/plugins/util/ci.js +40 -4
  180. package/packages/dd-trace/src/plugins/util/git.js +58 -18
  181. package/packages/dd-trace/src/plugins/util/test.js +71 -8
  182. package/packages/dd-trace/src/plugins/util/user-provided-git.js +14 -1
  183. package/packages/dd-trace/src/plugins/util/web.js +11 -114
  184. package/packages/dd-trace/src/priority_sampler.js +6 -2
  185. package/packages/dd-trace/src/profiling/config.js +11 -6
  186. package/packages/dd-trace/src/profiling/exporters/agent.js +4 -0
  187. package/packages/dd-trace/src/profiling/index.js +2 -2
  188. package/packages/dd-trace/src/profiling/profiler.js +43 -7
  189. package/packages/dd-trace/src/proxy.js +8 -16
  190. package/packages/dd-trace/src/ritm.js +25 -14
  191. package/packages/dd-trace/src/span_processor.js +17 -0
  192. package/packages/dd-trace/src/span_sampler.js +77 -0
  193. package/packages/dd-trace/src/span_stats.js +2 -2
  194. package/packages/dd-trace/src/telemetry/dependencies.js +21 -7
  195. package/packages/dd-trace/src/telemetry/index.js +7 -1
  196. package/packages/dd-trace/src/telemetry/send-data.js +3 -1
  197. package/packages/dd-trace/src/tracer.js +10 -5
  198. package/packages/dd-trace/src/util.js +43 -1
@@ -7,76 +7,80 @@ const {
7
7
  } = require('./helpers/instrument')
8
8
  const shimmer = require('../../datadog-shimmer')
9
9
 
10
- const startCh = channel('apm:elasticsearch:query:start')
11
- const finishCh = channel('apm:elasticsearch:query:finish')
12
- const errorCh = channel('apm:elasticsearch:query:error')
13
-
14
10
  addHook({ name: '@elastic/transport', file: 'lib/Transport.js', versions: ['>=8'] }, (exports) => {
15
- shimmer.wrap(exports.default.prototype, 'request', wrapRequest)
11
+ shimmer.wrap(exports.default.prototype, 'request', createWrapRequest('elasticsearch'))
16
12
  return exports
17
13
  })
18
14
 
19
15
  addHook({ name: '@elastic/elasticsearch', file: 'lib/Transport.js', versions: ['>=5.6.16 <8', '>=8'] }, Transport => {
20
- shimmer.wrap(Transport.prototype, 'request', wrapRequest)
16
+ shimmer.wrap(Transport.prototype, 'request', createWrapRequest('elasticsearch'))
21
17
  return Transport
22
18
  })
23
19
 
24
20
  addHook({ name: 'elasticsearch', file: 'src/lib/transport.js', versions: ['>=10'] }, Transport => {
25
- shimmer.wrap(Transport.prototype, 'request', wrapRequest)
21
+ shimmer.wrap(Transport.prototype, 'request', createWrapRequest('elasticsearch'))
26
22
  return Transport
27
23
  })
28
24
 
29
- function wrapRequest (request) {
30
- return function (params, options, cb) {
31
- if (!startCh.hasSubscribers) {
32
- return request.apply(this, arguments)
33
- }
25
+ function createWrapRequest (name) {
26
+ const startCh = channel(`apm:${name}:query:start`)
27
+ const finishCh = channel(`apm:${name}:query:finish`)
28
+ const errorCh = channel(`apm:${name}:query:error`)
34
29
 
35
- if (!params) return request.apply(this, arguments)
30
+ return function wrapRequest (request) {
31
+ return function (params, options, cb) {
32
+ if (!startCh.hasSubscribers) {
33
+ return request.apply(this, arguments)
34
+ }
36
35
 
37
- const parentResource = new AsyncResource('bound-anonymous-fn')
38
- const asyncResource = new AsyncResource('bound-anonymous-fn')
36
+ if (!params) return request.apply(this, arguments)
39
37
 
40
- return asyncResource.runInAsyncScope(() => {
41
- startCh.publish({ params })
38
+ const parentResource = new AsyncResource('bound-anonymous-fn')
39
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
42
40
 
43
- try {
44
- const lastIndex = arguments.length - 1
45
- cb = arguments[lastIndex]
41
+ return asyncResource.runInAsyncScope(() => {
42
+ startCh.publish({ params })
46
43
 
47
- if (typeof cb === 'function') {
48
- cb = parentResource.bind(cb)
44
+ try {
45
+ const lastIndex = arguments.length - 1
46
+ cb = arguments[lastIndex]
49
47
 
50
- arguments[lastIndex] = asyncResource.bind(function (error) {
51
- finish(params, error)
52
- return cb.apply(null, arguments)
53
- })
54
- return request.apply(this, arguments)
55
- } else {
56
- const promise = request.apply(this, arguments)
57
- if (promise && typeof promise.then === 'function') {
58
- const onResolve = asyncResource.bind(() => finish(params))
59
- const onReject = asyncResource.bind(e => finish(params, e))
48
+ if (typeof cb === 'function') {
49
+ cb = parentResource.bind(cb)
60
50
 
61
- promise.then(onResolve, onReject)
51
+ arguments[lastIndex] = asyncResource.bind(function (error) {
52
+ finish(params, error)
53
+ return cb.apply(null, arguments)
54
+ })
55
+ return request.apply(this, arguments)
62
56
  } else {
63
- finish(params)
57
+ const promise = request.apply(this, arguments)
58
+ if (promise && typeof promise.then === 'function') {
59
+ const onResolve = asyncResource.bind(() => finish(params))
60
+ const onReject = asyncResource.bind(e => finish(params, e))
61
+
62
+ promise.then(onResolve, onReject)
63
+ } else {
64
+ finish(params)
65
+ }
66
+ return promise
64
67
  }
65
- return promise
66
- }
67
- } catch (err) {
68
- err.stack // trigger getting the stack at the original throwing point
69
- errorCh.publish(err)
68
+ } catch (err) {
69
+ err.stack // trigger getting the stack at the original throwing point
70
+ errorCh.publish(err)
70
71
 
71
- throw err
72
- }
73
- })
72
+ throw err
73
+ }
74
+ })
75
+ }
74
76
  }
75
- }
76
77
 
77
- function finish (params, error) {
78
- if (error) {
79
- errorCh.publish(error)
78
+ function finish (params, error) {
79
+ if (error) {
80
+ errorCh.publish(error)
81
+ }
82
+ finishCh.publish({ params })
80
83
  }
81
- finishCh.publish({ params })
82
84
  }
85
+
86
+ module.exports = { createWrapRequest }
@@ -65,7 +65,7 @@ addHook({ name: '@google-cloud/pubsub', versions: ['>=1.2'] }, (obj) => {
65
65
  try {
66
66
  return emit.apply(this, arguments)
67
67
  } catch (err) {
68
- receiveErrorCh.publish({ err, message })
68
+ receiveErrorCh.publish(err)
69
69
  throw err
70
70
  }
71
71
  })
@@ -8,14 +8,20 @@ module.exports = {
8
8
  '@grpc/grpc-js': () => require('../grpc'),
9
9
  '@hapi/hapi': () => require('../hapi'),
10
10
  '@jest/core': () => require('../jest'),
11
+ '@jest/reporters': () => require('../jest'),
11
12
  '@koa/router': () => require('../koa'),
12
13
  '@node-redis/client': () => require('../redis'),
14
+ '@opensearch-project/opensearch': () => require('../opensearch'),
15
+ '@redis/client': () => require('../redis'),
13
16
  'amqp10': () => require('../amqp10'),
14
17
  'amqplib': () => require('../amqplib'),
15
18
  'aws-sdk': () => require('../aws-sdk'),
16
19
  'bluebird': () => require('../bluebird'),
20
+ 'body-parser': () => require('../body-parser'),
17
21
  'bunyan': () => require('../bunyan'),
18
22
  'cassandra-driver': () => require('../cassandra-driver'),
23
+ 'child_process': () => require('../child-process'),
24
+ 'node:child_process': () => require('../child-process'),
19
25
  'connect': () => require('../connect'),
20
26
  'couchbase': () => require('../couchbase'),
21
27
  'crypto': () => require('../crypto'),
@@ -40,7 +46,9 @@ module.exports = {
40
46
  'koa': () => require('../koa'),
41
47
  'koa-router': () => require('../koa'),
42
48
  'kafkajs': () => require('../kafkajs'),
49
+ 'ldapjs': () => require('../ldapjs'),
43
50
  'limitd-client': () => require('../limitd-client'),
51
+ 'mariadb': () => require('../mariadb'),
44
52
  'memcached': () => require('../memcached'),
45
53
  'microgateway-core': () => require('../microgateway-core'),
46
54
  'mocha': () => require('../mocha'),
@@ -61,6 +69,7 @@ module.exports = {
61
69
  'promise-js': () => require('../promise-js'),
62
70
  'promise': () => require('../promise'),
63
71
  'q': () => require('../q'),
72
+ 'qs': () => require('../qs'),
64
73
  'redis': () => require('../redis'),
65
74
  'restify': () => require('../restify'),
66
75
  'rhea': () => require('../rhea'),
@@ -57,3 +57,8 @@ function getVersion (moduleBaseDir) {
57
57
  function filename (name, file) {
58
58
  return [name, file].filter(val => val).join('/')
59
59
  }
60
+
61
+ module.exports = {
62
+ filename,
63
+ pathSepExpr
64
+ }
@@ -1,16 +1,19 @@
1
1
  'use strict'
2
2
 
3
+ const { AbortController } = require('node-abort-controller') // AbortController is not available in node <15
3
4
  const {
4
5
  channel,
5
- addHook,
6
- AsyncResource
6
+ addHook
7
7
  } = require('../helpers/instrument')
8
8
  const shimmer = require('../../../datadog-shimmer')
9
9
 
10
10
  const startServerCh = channel('apm:http:server:request:start')
11
+ const exitServerCh = channel('apm:http:server:request:exit')
11
12
  const errorServerCh = channel('apm:http:server:request:error')
12
13
  const finishServerCh = channel('apm:http:server:request:finish')
13
14
 
15
+ const requestFinishedSet = new WeakSet()
16
+
14
17
  addHook({ name: 'https' }, http => {
15
18
  // http.ServerResponse not present on https
16
19
  shimmer.wrap(http.Server.prototype, 'emit', wrapEmit)
@@ -29,8 +32,9 @@ function wrapResponseEmit (emit) {
29
32
  return emit.apply(this, arguments)
30
33
  }
31
34
 
32
- if (eventName === 'close') {
35
+ if (['finish', 'close'].includes(eventName) && !requestFinishedSet.has(this)) {
33
36
  finishServerCh.publish({ req: this.req })
37
+ requestFinishedSet.add(this)
34
38
  }
35
39
 
36
40
  return emit.apply(this, arguments)
@@ -45,18 +49,22 @@ function wrapEmit (emit) {
45
49
  if (eventName === 'request') {
46
50
  res.req = req
47
51
 
48
- const asyncResource = new AsyncResource('bound-anonymous-fn')
49
- return asyncResource.runInAsyncScope(() => {
50
- startServerCh.publish({ req, res })
52
+ const abortController = new AbortController()
51
53
 
52
- try {
53
- return emit.apply(this, arguments)
54
- } catch (err) {
55
- errorServerCh.publish(err)
54
+ startServerCh.publish({ req, res, abortController })
56
55
 
57
- throw err
56
+ try {
57
+ if (abortController.signal.aborted) {
58
+ return res.end()
58
59
  }
59
- })
60
+ return emit.apply(this, arguments)
61
+ } catch (err) {
62
+ errorServerCh.publish(err)
63
+
64
+ throw err
65
+ } finally {
66
+ exitServerCh.publish({ req })
67
+ }
60
68
  }
61
69
  return emit.apply(this, arguments)
62
70
  }
@@ -1,3 +1,69 @@
1
1
  'use strict'
2
2
 
3
- // Instrumentation temporarily disabled. See https://github.com/DataDog/dd-trace-js/issues/312
3
+ // Old instrumentation temporarily replaced with compatibility mode only instrumentation.
4
+ // See https://github.com/DataDog/dd-trace-js/issues/312
5
+
6
+ const {
7
+ channel,
8
+ addHook,
9
+ AsyncResource
10
+ } = require('../helpers/instrument')
11
+ const shimmer = require('../../../datadog-shimmer')
12
+
13
+ const startServerCh = channel('apm:http2:server:request:start')
14
+ const errorServerCh = channel('apm:http2:server:request:error')
15
+ const finishServerCh = channel('apm:http2:server:request:finish')
16
+
17
+ addHook({ name: 'http2' }, http2 => {
18
+ shimmer.wrap(http2, 'createSecureServer', wrapCreateServer)
19
+ shimmer.wrap(http2, 'createServer', wrapCreateServer)
20
+ return http2
21
+ })
22
+
23
+ function wrapCreateServer (createServer) {
24
+ return function (...args) {
25
+ const server = createServer.apply(this, args)
26
+ shimmer.wrap(server, 'emit', wrapEmit)
27
+ return server
28
+ }
29
+ }
30
+
31
+ function wrapResponseEmit (emit) {
32
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
33
+ return function (eventName, event) {
34
+ return asyncResource.runInAsyncScope(() => {
35
+ if (eventName === 'close' && finishServerCh.hasSubscribers) {
36
+ finishServerCh.publish({ req: this.req })
37
+ }
38
+
39
+ return emit.apply(this, arguments)
40
+ })
41
+ }
42
+ }
43
+ function wrapEmit (emit) {
44
+ return function (eventName, req, res) {
45
+ if (!startServerCh.hasSubscribers) {
46
+ return emit.apply(this, arguments)
47
+ }
48
+
49
+ if (eventName === 'request') {
50
+ res.req = req
51
+
52
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
53
+ return asyncResource.runInAsyncScope(() => {
54
+ startServerCh.publish({ req, res })
55
+
56
+ shimmer.wrap(res, 'emit', wrapResponseEmit)
57
+
58
+ try {
59
+ return emit.apply(this, arguments)
60
+ } catch (err) {
61
+ errorServerCh.publish(err)
62
+
63
+ throw err
64
+ }
65
+ })
66
+ }
67
+ return emit.apply(this, arguments)
68
+ }
69
+ }
@@ -1,7 +1,8 @@
1
1
  'use strict'
2
- const istanbul = require('istanbul-lib-coverage')
3
2
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
3
  const shimmer = require('../../datadog-shimmer')
4
+ const log = require('../../dd-trace/src/log')
5
+ const { getCoveredFilenamesFromCoverage } = require('../../dd-trace/src/plugins/util/test')
5
6
 
6
7
  const testSessionStartCh = channel('ci:jest:session:start')
7
8
  const testSessionFinishCh = channel('ci:jest:session:finish')
@@ -17,6 +18,13 @@ const testSkippedCh = channel('ci:jest:test:skip')
17
18
  const testRunFinishCh = channel('ci:jest:test:finish')
18
19
  const testErrCh = channel('ci:jest:test:err')
19
20
 
21
+ const skippableSuitesCh = channel('ci:jest:test-suite:skippable')
22
+ const jestItrConfigurationCh = channel('ci:jest:itr-configuration')
23
+
24
+ let skippableSuites = []
25
+ let isCodeCoverageEnabled = false
26
+ let isSuitesSkippingEnabled = false
27
+
20
28
  const {
21
29
  getTestSuitePath,
22
30
  getTestParametersString
@@ -26,21 +34,6 @@ const { getFormattedJestTestParameters, getJestTestName } = require('../../datad
26
34
 
27
35
  const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
28
36
 
29
- function extractCoverageInformation (coverage, rootDir) {
30
- const coverageMap = istanbul.createCoverageMap(coverage)
31
-
32
- return coverageMap
33
- .files()
34
- .filter(filename => {
35
- const fileCoverage = coverageMap.fileCoverageFor(filename)
36
- const lineCoverage = fileCoverage.getLineCoverage()
37
- const isAnyLineExecuted = Object.entries(lineCoverage).some(([, numExecutions]) => !!numExecutions)
38
-
39
- return isAnyLineExecuted
40
- })
41
- .map(filename => filename.replace(`${rootDir}/`, ''))
42
- }
43
-
44
37
  const specStatusToTestStatus = {
45
38
  'pending': 'skip',
46
39
  'disabled': 'skip',
@@ -179,17 +172,80 @@ addHook({
179
172
 
180
173
  function cliWrapper (cli) {
181
174
  const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
175
+ let onDone
176
+ const configurationPromise = new Promise((resolve) => {
177
+ onDone = resolve
178
+ })
179
+ if (!jestItrConfigurationCh.hasSubscribers) {
180
+ return runCLI.apply(this, arguments)
181
+ }
182
+
183
+ sessionAsyncResource.runInAsyncScope(() => {
184
+ jestItrConfigurationCh.publish({ onDone })
185
+ })
186
+
187
+ try {
188
+ const { err, itrConfig } = await configurationPromise
189
+ if (err) {
190
+ log.error(err)
191
+ }
192
+ isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
193
+ isSuitesSkippingEnabled = itrConfig.isSuitesSkippingEnabled
194
+ } catch (e) {
195
+ log.error(e)
196
+ }
197
+
198
+ if (isSuitesSkippingEnabled) {
199
+ const skippableSuitesPromise = new Promise((resolve) => {
200
+ onDone = resolve
201
+ })
202
+
203
+ sessionAsyncResource.runInAsyncScope(() => {
204
+ skippableSuitesCh.publish({ onDone })
205
+ })
206
+
207
+ try {
208
+ const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
209
+ if (err) {
210
+ log.error(err)
211
+ } else {
212
+ skippableSuites = receivedSkippableSuites
213
+ }
214
+ } catch (e) {
215
+ log.error(e)
216
+ }
217
+ }
218
+
219
+ const isSuitesSkipped = !!skippableSuites.length
220
+
182
221
  const processArgv = process.argv.slice(2).join(' ')
183
222
  sessionAsyncResource.runInAsyncScope(() => {
184
223
  testSessionStartCh.publish(`jest ${processArgv}`)
185
224
  })
186
- return runCLI.apply(this, arguments).then(result => {
187
- const { results: { success } } = result
188
- sessionAsyncResource.runInAsyncScope(() => {
189
- testSessionFinishCh.publish(success ? 'pass' : 'fail')
225
+
226
+ const result = await runCLI.apply(this, arguments)
227
+
228
+ const { results: { success, coverageMap } } = result
229
+
230
+ let testCodeCoverageLinesTotal
231
+ try {
232
+ const { pct, total } = coverageMap.getCoverageSummary().lines
233
+ testCodeCoverageLinesTotal = total !== 0 ? pct : 0
234
+ } catch (e) {
235
+ // ignore errors
236
+ }
237
+
238
+ sessionAsyncResource.runInAsyncScope(() => {
239
+ testSessionFinishCh.publish({
240
+ status: success ? 'pass' : 'fail',
241
+ isSuitesSkipped,
242
+ isSuitesSkippingEnabled,
243
+ isCodeCoverageEnabled,
244
+ testCodeCoverageLinesTotal
190
245
  })
191
- return result
192
246
  })
247
+
248
+ return result
193
249
  })
194
250
 
195
251
  cli.runCLI = wrapped.runCLI
@@ -197,6 +253,35 @@ function cliWrapper (cli) {
197
253
  return cli
198
254
  }
199
255
 
256
+ function coverageReporterWrapper (coverageReporter) {
257
+ const CoverageReporter = coverageReporter.default ? coverageReporter.default : coverageReporter
258
+
259
+ /**
260
+ * If ITR is active, we're running fewer tests, so of course the total code coverage is reduced.
261
+ * This calculation adds no value, so we'll skip it.
262
+ */
263
+ shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => async function () {
264
+ if (isSuitesSkippingEnabled) {
265
+ return Promise.resolve()
266
+ }
267
+ return addUntestedFiles.apply(this, arguments)
268
+ })
269
+
270
+ return coverageReporter
271
+ }
272
+
273
+ addHook({
274
+ name: '@jest/reporters',
275
+ file: 'build/coverage_reporter.js',
276
+ versions: ['>=24.8.0 <26.6.2']
277
+ }, coverageReporterWrapper)
278
+
279
+ addHook({
280
+ name: '@jest/reporters',
281
+ file: 'build/CoverageReporter.js',
282
+ versions: ['>=26.6.2']
283
+ }, coverageReporterWrapper)
284
+
200
285
  addHook({
201
286
  name: '@jest/core',
202
287
  file: 'build/cli/index.js',
@@ -207,6 +292,9 @@ function jestAdapterWrapper (jestAdapter) {
207
292
  const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
208
293
  const newAdapter = shimmer.wrap(adapter, function () {
209
294
  const environment = arguments[2]
295
+ if (!environment) {
296
+ return adapter.apply(this, arguments)
297
+ }
210
298
  const asyncResource = new AsyncResource('bound-anonymous-fn')
211
299
  return asyncResource.runInAsyncScope(() => {
212
300
  testSuiteStartCh.publish({
@@ -222,11 +310,21 @@ function jestAdapterWrapper (jestAdapter) {
222
310
  status = 'fail'
223
311
  }
224
312
  testSuiteFinishCh.publish({ status, errorMessage })
225
- if (environment.global.__coverage__) {
226
- const coverageFiles = extractCoverageInformation(environment.global.__coverage__, environment.rootDir)
227
- if (coverageFiles.length) {
313
+
314
+ const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
315
+ .map(filename => getTestSuitePath(filename, environment.rootDir))
316
+
317
+ /**
318
+ * Child processes do not each request ITR configuration, so the jest's parent process
319
+ * needs to pass them the configuration. This is done via _ddTestCodeCoverageEnabled, which
320
+ * controls whether coverage is reported.
321
+ */
322
+ if (coverageFiles &&
323
+ environment.testEnvironmentOptions &&
324
+ environment.testEnvironmentOptions._ddTestCodeCoverageEnabled) {
325
+ asyncResource.runInAsyncScope(() => {
228
326
  testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
229
- }
327
+ })
230
328
  }
231
329
  return suiteResults
232
330
  })
@@ -252,6 +350,32 @@ function configureTestEnvironment (readConfigsResult) {
252
350
  sessionAsyncResource.runInAsyncScope(() => {
253
351
  testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
254
352
  })
353
+ // We can't directly use isCodeCoverageEnabled when reporting coverage in `jestAdapterWrapper`
354
+ // because `jestAdapterWrapper` runs in a different process. We have to go through `testEnvironmentOptions`
355
+ configs.forEach(config => {
356
+ config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
357
+ })
358
+
359
+ if (isCodeCoverageEnabled) {
360
+ const globalConfig = {
361
+ ...readConfigsResult.globalConfig,
362
+ collectCoverage: true
363
+ }
364
+ readConfigsResult.globalConfig = globalConfig
365
+ }
366
+ if (isSuitesSkippingEnabled) {
367
+ // If suite skipping is enabled, the code coverage results are not going to be relevant,
368
+ // so we do not show them.
369
+ // Also, we might skip every test, so we need to pass `passWithNoTests`
370
+ const globalConfig = {
371
+ ...readConfigsResult.globalConfig,
372
+ coverageReporters: ['none'],
373
+ passWithNoTests: true
374
+ }
375
+ readConfigsResult.globalConfig = globalConfig
376
+ }
377
+
378
+ return readConfigsResult
255
379
  }
256
380
 
257
381
  function jestConfigAsyncWrapper (jestConfig) {
@@ -272,6 +396,39 @@ function jestConfigSyncWrapper (jestConfig) {
272
396
  return jestConfig
273
397
  }
274
398
 
399
+ /**
400
+ * Hook to remove the test paths (test suite) that are part of `skippableSuites`
401
+ */
402
+ addHook({
403
+ name: '@jest/core',
404
+ versions: ['>=24.8.0'],
405
+ file: 'build/SearchSource.js'
406
+ }, searchSourcePackage => {
407
+ const SearchSource = searchSourcePackage.default ? searchSourcePackage.default : searchSourcePackage
408
+
409
+ shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
410
+ if (!skippableSuites.length) {
411
+ return getTestPaths.apply(this, arguments)
412
+ }
413
+
414
+ const [{ rootDir }] = arguments
415
+
416
+ const testPaths = await getTestPaths.apply(this, arguments)
417
+ const { tests } = testPaths
418
+
419
+ const filteredTests = tests.filter(({ path: testPath }) => {
420
+ const relativePath = testPath.replace(`${rootDir}/`, '')
421
+ return !skippableSuites.includes(relativePath)
422
+ })
423
+
424
+ skippableSuites = []
425
+
426
+ return { ...testPaths, tests: filteredTests }
427
+ })
428
+
429
+ return searchSourcePackage
430
+ })
431
+
275
432
  // from 25.1.0 on, readConfigs becomes async
276
433
  addHook({
277
434
  name: 'jest-config',