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
@@ -1,12 +1,13 @@
1
1
  'use strict'
2
2
 
3
3
  const shimmer = require('../../datadog-shimmer')
4
- const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
+ const { addHook, channel } = require('./helpers/instrument')
5
5
 
6
6
  const enterChannel = channel('apm:koa:middleware:enter')
7
7
  const exitChannel = channel('apm:koa:middleware:exit')
8
8
  const errorChannel = channel('apm:koa:middleware:error')
9
9
  const nextChannel = channel('apm:koa:middleware:next')
10
+ const finishChannel = channel('apm:koa:middleware:finish')
10
11
  const handleChannel = channel('apm:koa:request:handle')
11
12
  const routeChannel = channel('apm:koa:request:route')
12
13
 
@@ -86,42 +87,41 @@ function wrapMiddleware (fn, layer) {
86
87
  return function (ctx, next) {
87
88
  if (!ctx || !enterChannel.hasSubscribers) return fn.apply(this, arguments)
88
89
 
89
- const middlewareResource = new AsyncResource('bound-anonymous-fn')
90
90
  const req = ctx.req
91
91
 
92
- return middlewareResource.runInAsyncScope(() => {
93
- const path = layer && layer.path
94
- const route = typeof path === 'string' && !path.endsWith('(.*)') && !path.endsWith('([^/]*)') && path
92
+ const path = layer && layer.path
93
+ const route = typeof path === 'string' && !path.endsWith('(.*)') && !path.endsWith('([^/]*)') && path
95
94
 
96
- enterChannel.publish({ req, name, route })
95
+ enterChannel.publish({ req, name, route })
97
96
 
98
- if (typeof next === 'function') {
99
- arguments[1] = wrapNext(req, next)
100
- }
97
+ if (typeof next === 'function') {
98
+ arguments[1] = wrapNext(req, next)
99
+ }
101
100
 
102
- try {
103
- const result = fn.apply(this, arguments)
104
-
105
- if (result && typeof result.then === 'function') {
106
- return result.then(
107
- result => {
108
- fulfill(ctx)
109
- return result
110
- },
111
- err => {
112
- fulfill(ctx, err)
113
- throw err
114
- }
115
- )
116
- } else {
117
- fulfill(ctx)
118
- return result
119
- }
120
- } catch (e) {
121
- fulfill(ctx, e)
122
- throw e
101
+ try {
102
+ const result = fn.apply(this, arguments)
103
+
104
+ if (result && typeof result.then === 'function') {
105
+ return result.then(
106
+ result => {
107
+ fulfill(ctx)
108
+ return result
109
+ },
110
+ err => {
111
+ fulfill(ctx, err)
112
+ throw err
113
+ }
114
+ )
115
+ } else {
116
+ fulfill(ctx)
117
+ return result
123
118
  }
124
- })
119
+ } catch (e) {
120
+ fulfill(ctx, e)
121
+ throw e
122
+ } finally {
123
+ exitChannel.publish({ req })
124
+ }
125
125
  }
126
126
  }
127
127
 
@@ -138,7 +138,7 @@ function fulfill (ctx, error) {
138
138
  routeChannel.publish({ req, route })
139
139
  }
140
140
 
141
- exitChannel.publish({ req })
141
+ finishChannel.publish({ req })
142
142
  }
143
143
 
144
144
  function wrapNext (req, next) {
@@ -0,0 +1,91 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook,
6
+ AsyncResource
7
+ } = require('./helpers/instrument')
8
+ const shimmer = require('../../datadog-shimmer')
9
+
10
+ function isString (value) {
11
+ return typeof value === 'string' || value instanceof String
12
+ }
13
+
14
+ function getCallbackArgIndex (args) {
15
+ let callbackIndex = -1
16
+ for (let i = args.length - 1; i >= 0; i--) {
17
+ if (typeof args[i] === 'function') {
18
+ callbackIndex = i
19
+ break
20
+ }
21
+ }
22
+ return callbackIndex
23
+ }
24
+
25
+ function wrapEmitter (corkedEmitter) {
26
+ const callbackMap = new WeakMap()
27
+
28
+ const addListener = on => function (name, fn) {
29
+ if (typeof fn === 'function') {
30
+ let bindedFn = callbackMap.get(fn)
31
+ if (!bindedFn) {
32
+ const callbackResource = new AsyncResource('bound-anonymous-fn')
33
+ bindedFn = callbackResource.bind(fn)
34
+ callbackMap.set(fn, bindedFn)
35
+ }
36
+ arguments[1] = bindedFn
37
+ }
38
+ on.apply(this, arguments)
39
+ }
40
+ shimmer.wrap(corkedEmitter, 'on', addListener)
41
+ shimmer.wrap(corkedEmitter, 'addListener', addListener)
42
+
43
+ const removeListener = off => function (name, fn) {
44
+ if (typeof fn === 'function') {
45
+ const emitterOn = callbackMap.get(fn)
46
+ if (emitterOn) {
47
+ arguments[1] = emitterOn
48
+ }
49
+ }
50
+ off.apply(this, arguments)
51
+ }
52
+ shimmer.wrap(corkedEmitter, 'off', removeListener)
53
+ shimmer.wrap(corkedEmitter, 'removeListener', removeListener)
54
+ }
55
+
56
+ addHook({ name: 'ldapjs', versions: ['>=2'] }, ldapjs => {
57
+ const ldapSearchCh = channel('datadog:ldapjs:client:search')
58
+
59
+ shimmer.wrap(ldapjs.Client.prototype, 'search', search => function (base, options) {
60
+ if (ldapSearchCh.hasSubscribers) {
61
+ let filter
62
+ if (isString(options)) {
63
+ filter = options
64
+ } else if (typeof options === 'object' && options.filter) {
65
+ if (isString(options.filter)) {
66
+ filter = options.filter
67
+ }
68
+ }
69
+ ldapSearchCh.publish({ base, filter })
70
+ }
71
+
72
+ return search.apply(this, arguments)
73
+ })
74
+
75
+ shimmer.wrap(ldapjs.Client.prototype, '_send', _send => function () {
76
+ const callbackIndex = getCallbackArgIndex(arguments)
77
+ if (callbackIndex > -1) {
78
+ const callback = arguments[callbackIndex]
79
+ arguments[callbackIndex] = shimmer.wrap(callback, function (err, corkedEmitter) {
80
+ if (typeof corkedEmitter === 'object' && typeof corkedEmitter['on'] === 'function') {
81
+ wrapEmitter(corkedEmitter)
82
+ }
83
+ callback.apply(this, arguments)
84
+ })
85
+ }
86
+
87
+ return _send.apply(this, arguments)
88
+ })
89
+
90
+ return ldapjs
91
+ })
@@ -0,0 +1,63 @@
1
+ 'use strict'
2
+
3
+ const { channel, addHook, AsyncResource } = require('./helpers/instrument')
4
+
5
+ const shimmer = require('../../datadog-shimmer')
6
+
7
+ const startCh = channel('apm:mariadb:query:start')
8
+ const finishCh = channel('apm:mariadb:query:finish')
9
+ const errorCh = channel('apm:mariadb:query:error')
10
+
11
+ function wrapCommandStart (start) {
12
+ return function () {
13
+ if (!startCh.hasSubscribers) return start.apply(this, arguments)
14
+
15
+ const callbackResource = new AsyncResource('bound-anonymous-fn')
16
+
17
+ const resolve = callbackResource.bind(this.resolve)
18
+ const reject = callbackResource.bind(this.reject)
19
+
20
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
21
+
22
+ shimmer.wrap(this, 'resolve', function wrapResolve () {
23
+ return function () {
24
+ asyncResource.runInAsyncScope(() => {
25
+ finishCh.publish()
26
+ })
27
+
28
+ return resolve.apply(this, arguments)
29
+ }
30
+ })
31
+
32
+ shimmer.wrap(this, 'reject', function wrapReject () {
33
+ return function (error) {
34
+ asyncResource.runInAsyncScope(() => {
35
+ errorCh.publish(error)
36
+ finishCh.publish()
37
+ })
38
+
39
+ return reject.apply(this, arguments)
40
+ }
41
+ })
42
+
43
+ return asyncResource.runInAsyncScope(() => {
44
+ startCh.publish({ sql: this.sql, conf: this.opts })
45
+ return start.apply(this, arguments)
46
+ })
47
+ }
48
+ }
49
+
50
+ const name = 'mariadb'
51
+ const versions = ['>=2.0.3']
52
+
53
+ addHook({ name, file: 'lib/cmd/query.js', versions }, (Query) => {
54
+ shimmer.wrap(Query.prototype, 'start', wrapCommandStart)
55
+
56
+ return Query
57
+ })
58
+
59
+ addHook({ name, file: 'lib/cmd/execute.js', versions }, (Query) => {
60
+ shimmer.wrap(Query.prototype, 'start', wrapCommandStart)
61
+
62
+ return Query
63
+ })
@@ -9,7 +9,6 @@ const shimmer = require('../../datadog-shimmer')
9
9
 
10
10
  addHook({ name: 'memcached', versions: ['>=2.2'] }, Memcached => {
11
11
  const startCh = channel('apm:memcached:command:start')
12
- const startWithArgsCh = channel('apm:memcached:command:start:with-args')
13
12
  const finishCh = channel('apm:memcached:command:finish')
14
13
  const errorCh = channel('apm:memcached:command:error')
15
14
 
@@ -35,14 +34,12 @@ addHook({ name: 'memcached', versions: ['>=2.2'] }, Memcached => {
35
34
 
36
35
  return callback.apply(this, arguments)
37
36
  })
38
- startWithArgsCh.publish({ client, server, query })
37
+ startCh.publish({ client, server, query })
39
38
 
40
39
  return query
41
40
  })
42
41
 
43
42
  return asyncResource.runInAsyncScope(() => {
44
- startCh.publish()
45
-
46
43
  arguments[0] = wrappedQueryCompiler
47
44
 
48
45
  const result = command.apply(this, arguments)
@@ -1,5 +1,15 @@
1
+ const { createCoverageMap } = require('istanbul-lib-coverage')
2
+
1
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
2
4
  const shimmer = require('../../datadog-shimmer')
5
+ const log = require('../../dd-trace/src/log')
6
+ const {
7
+ getCoveredFilenamesFromCoverage,
8
+ resetCoverage,
9
+ mergeCoverage,
10
+ getTestSuitePath,
11
+ fromCoverageMapToCoverage
12
+ } = require('../../dd-trace/src/plugins/util/test')
3
13
 
4
14
  const testStartCh = channel('ci:mocha:test:start')
5
15
  const errorCh = channel('ci:mocha:test:error')
@@ -7,12 +17,16 @@ const skipCh = channel('ci:mocha:test:skip')
7
17
  const testFinishCh = channel('ci:mocha:test:finish')
8
18
  const parameterizedTestCh = channel('ci:mocha:test:parameterize')
9
19
 
10
- const testRunStartCh = channel('ci:mocha:run:start')
11
- const testRunFinishCh = channel('ci:mocha:run:finish')
20
+ const itrConfigurationCh = channel('ci:mocha:itr-configuration')
21
+ const skippableSuitesCh = channel('ci:mocha:test-suite:skippable')
22
+
23
+ const testSessionStartCh = channel('ci:mocha:session:start')
24
+ const testSessionFinishCh = channel('ci:mocha:session:finish')
12
25
 
13
26
  const testSuiteStartCh = channel('ci:mocha:test-suite:start')
14
27
  const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
15
28
  const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
29
+ const testSuiteCodeCoverageCh = channel('ci:mocha:test-suite:code-coverage')
16
30
 
17
31
  // TODO: remove when root hooks and fixtures are implemented
18
32
  const patched = new WeakSet()
@@ -21,6 +35,11 @@ const testToAr = new WeakMap()
21
35
  const originalFns = new WeakMap()
22
36
  const testFileToSuiteAr = new Map()
23
37
 
38
+ // We'll preserve the original coverage here
39
+ const originalCoverageMap = createCoverageMap()
40
+
41
+ let suitesToSkip = []
42
+
24
43
  function getSuitesByTestFile (root) {
25
44
  const suitesByTestFile = {}
26
45
  function getSuites (suite) {
@@ -46,13 +65,13 @@ function getSuitesByTestFile (root) {
46
65
  }
47
66
 
48
67
  function getTestStatus (test) {
49
- if (test.pending) {
68
+ if (test.isPending()) {
50
69
  return 'skip'
51
70
  }
52
- if (test.state !== 'failed' && !test.timedOut) {
53
- return 'pass'
71
+ if (test.isFailed() || test.timedOut) {
72
+ return 'fail'
54
73
  }
55
- return 'fail'
74
+ return 'pass'
56
75
  }
57
76
 
58
77
  function isRetry (test) {
@@ -70,6 +89,12 @@ function getTestAsyncResource (test) {
70
89
  return testToAr.get(originalFn)
71
90
  }
72
91
 
92
+ function getSuitesToRun (originalSuites) {
93
+ return originalSuites.filter(suite =>
94
+ !suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
95
+ )
96
+ }
97
+
73
98
  function mochaHook (Runner) {
74
99
  if (patched.has(Runner)) return Runner
75
100
 
@@ -92,13 +117,18 @@ function mochaHook (Runner) {
92
117
  status = 'fail'
93
118
  }
94
119
  testFileToSuiteAr.clear()
95
- testRunFinishCh.publish(status)
120
+
121
+ const isSuitesSkipped = !!suitesToSkip.length
122
+
123
+ testSessionFinishCh.publish({ status, isSuitesSkipped })
124
+ // restore the original coverage
125
+ global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
96
126
  }))
97
127
 
98
128
  this.once('start', testRunAsyncResource.bind(function () {
99
129
  const processArgv = process.argv.slice(2).join(' ')
100
130
  const command = `mocha ${processArgv}`
101
- testRunStartCh.publish(command)
131
+ testSessionStartCh.publish(command)
102
132
  }))
103
133
 
104
134
  this.on('suite', function (suite) {
@@ -140,9 +170,21 @@ function mochaHook (Runner) {
140
170
  })
141
171
  }
142
172
 
173
+ if (global.__coverage__) {
174
+ const coverageFiles = getCoveredFilenamesFromCoverage(global.__coverage__)
175
+
176
+ testSuiteCodeCoverageCh.publish({
177
+ coverageFiles,
178
+ suiteFile: suite.file
179
+ })
180
+ // We need to reset coverage to get a code coverage per suite
181
+ // Before that, we preserve the original coverage
182
+ mergeCoverage(global.__coverage__, originalCoverageMap)
183
+ resetCoverage(global.__coverage__)
184
+ }
185
+
143
186
  const asyncResource = testFileToSuiteAr.get(suite.file)
144
187
  asyncResource.runInAsyncScope(() => {
145
- // get suite status
146
188
  testSuiteFinishCh.publish(status)
147
189
  })
148
190
  })
@@ -229,7 +271,8 @@ function mochaHook (Runner) {
229
271
  skipCh.publish(test)
230
272
  })
231
273
  } else {
232
- // if there is no async resource, the test has been skipped through `test.skip``
274
+ // if there is no async resource, the test has been skipped through `test.skip`
275
+ // or the parent suite is skipped
233
276
  const skippedTestAsyncResource = new AsyncResource('bound-anonymous-fn')
234
277
  if (test.fn) {
235
278
  testToAr.set(test.fn, skippedTestAsyncResource)
@@ -245,13 +288,6 @@ function mochaHook (Runner) {
245
288
  return run.apply(this, arguments)
246
289
  })
247
290
 
248
- shimmer.wrap(Runner.prototype, 'runTests', runTests => function () {
249
- if (!testRunFinishCh.hasSubscribers) {
250
- return runTests.apply(this, arguments)
251
- }
252
- return runTests.apply(this, arguments)
253
- })
254
-
255
291
  return Runner
256
292
  }
257
293
 
@@ -273,18 +309,93 @@ function mochaEachHook (mochaEach) {
273
309
  })
274
310
  }
275
311
 
312
+ addHook({
313
+ name: 'mocha',
314
+ versions: ['>=5.2.0'],
315
+ file: 'lib/mocha.js'
316
+ }, (Mocha) => {
317
+ const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
318
+
319
+ /**
320
+ * Get ITR configuration and skippable suites
321
+ * If ITR is disabled, `onDone` is called immediately on the subscriber
322
+ */
323
+ shimmer.wrap(Mocha.prototype, 'run', run => function () {
324
+ if (!itrConfigurationCh.hasSubscribers) {
325
+ return run.apply(this, arguments)
326
+ }
327
+ this.options.delay = true
328
+
329
+ const runner = run.apply(this, arguments)
330
+
331
+ const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
332
+ if (err) {
333
+ log.error(err)
334
+ suitesToSkip = []
335
+ } else {
336
+ suitesToSkip = skippableSuites
337
+ }
338
+ // We remove the suites that we skip through ITR
339
+ runner.suite.suites = getSuitesToRun(runner.suite.suites)
340
+ global.run()
341
+ }
342
+
343
+ const onReceivedConfiguration = ({ err }) => {
344
+ if (err) {
345
+ log.error(err)
346
+ return global.run()
347
+ }
348
+ if (!skippableSuitesCh.hasSubscribers) {
349
+ return global.run()
350
+ }
351
+
352
+ skippableSuitesCh.publish({
353
+ onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
354
+ })
355
+ }
356
+
357
+ mochaRunAsyncResource.runInAsyncScope(() => {
358
+ itrConfigurationCh.publish({
359
+ onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
360
+ })
361
+ })
362
+ return runner
363
+ })
364
+ return Mocha
365
+ })
366
+
276
367
  addHook({
277
368
  name: 'mocha',
278
369
  versions: ['>=5.2.0'],
279
370
  file: 'lib/runner.js'
280
371
  }, mochaHook)
281
372
 
373
+ addHook({
374
+ name: 'mocha',
375
+ versions: ['>=5.2.0'],
376
+ file: 'lib/cli/run-helpers.js'
377
+ }, (run) => {
378
+ shimmer.wrap(run, 'runMocha', runMocha => async function () {
379
+ const mocha = arguments[0]
380
+ /**
381
+ * This attaches `run` to the global context, which we'll call after
382
+ * our configuration and skippable suites requests
383
+ */
384
+ mocha.options.delay = true
385
+ return runMocha.apply(this, arguments)
386
+ })
387
+ return run
388
+ })
389
+
282
390
  addHook({
283
391
  name: 'mocha',
284
392
  versions: ['>=5.2.0'],
285
393
  file: 'lib/runnable.js'
286
394
  }, (Runnable) => {
287
395
  shimmer.wrap(Runnable.prototype, 'run', run => function () {
396
+ if (!testStartCh.hasSubscribers) {
397
+ return run.apply(this, arguments)
398
+ }
288
399
  const isBeforeEach = this.parent._beforeEach.includes(this)
289
400
  const isAfterEach = this.parent._afterEach.includes(this)
290
401
 
@@ -300,13 +411,15 @@ addHook({
300
411
  const test = isTestHook ? this.ctx.currentTest : this
301
412
  const asyncResource = getTestAsyncResource(test)
302
413
 
303
- // we bind the test fn to the correct async resource
304
- const newFn = asyncResource.bind(this.fn)
414
+ if (asyncResource) {
415
+ // we bind the test fn to the correct async resource
416
+ const newFn = asyncResource.bind(this.fn)
305
417
 
306
- // we store the original function, not to lose it
307
- originalFns.set(newFn, this.fn)
418
+ // we store the original function, not to lose it
419
+ originalFns.set(newFn, this.fn)
308
420
 
309
- this.fn = newFn
421
+ this.fn = newFn
422
+ }
310
423
  }
311
424
 
312
425
  return run.apply(this, arguments)
@@ -318,5 +431,3 @@ addHook({
318
431
  name: 'mocha-each',
319
432
  versions: ['>=2.0.1']
320
433
  }, mochaEachHook)
321
-
322
- module.exports = { mochaHook, mochaEachHook }
@@ -99,12 +99,16 @@ function instrument (req, res, handler) {
99
99
  try {
100
100
  const promise = handler()
101
101
 
102
+ // promise should only reject when propagateError is true:
103
+ // https://github.com/vercel/next.js/blob/cee656238a/packages/next/server/api-utils/node.ts#L547
102
104
  return promise.then(
103
105
  result => finish(req, res, result),
104
106
  err => finish(req, res, null, err)
105
107
  )
106
108
  } catch (e) {
107
- finish(req, res, null, e)
109
+ // this will probably never happen as the handler caller is an async function:
110
+ // https://github.com/vercel/next.js/blob/cee656238a/packages/next/server/api-utils/node.ts#L420
111
+ return finish(req, res, null, e)
108
112
  }
109
113
  })
110
114
  }
@@ -116,7 +120,11 @@ function finish (req, res, result, err) {
116
120
 
117
121
  finishChannel.publish({ req, res })
118
122
 
119
- return result || err
123
+ if (err) {
124
+ throw err
125
+ }
126
+
127
+ return result
120
128
  }
121
129
 
122
130
  addHook({ name: 'next', versions: ['>=11.1'], file: 'dist/server/next-server.js' }, nextServer => {
@@ -0,0 +1,10 @@
1
+ 'use strict'
2
+
3
+ const { addHook } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+ const { createWrapRequest } = require('./elasticsearch')
6
+
7
+ addHook({ name: '@opensearch-project/opensearch', file: 'lib/Transport.js', versions: ['>=1'] }, Transport => {
8
+ shimmer.wrap(Transport.prototype, 'request', createWrapRequest('opensearch'))
9
+ return Transport
10
+ })
@@ -10,21 +10,21 @@ const shimmer = require('../../datadog-shimmer')
10
10
  const connectionAttributes = new WeakMap()
11
11
  const poolAttributes = new WeakMap()
12
12
 
13
- const executeStartChannel = channel('apm:oracledb:execute:start')
14
- const executeErrorChannel = channel('apm:oracledb:execute:error')
15
- const executeFinishChannel = channel('apm:oracledb:execute:finish')
13
+ const startChannel = channel('apm:oracledb:query:start')
14
+ const errorChannel = channel('apm:oracledb:query:error')
15
+ const finishChannel = channel('apm:oracledb:query:finish')
16
16
 
17
17
  function finish (err) {
18
18
  if (err) {
19
- executeErrorChannel.publish(err)
19
+ errorChannel.publish(err)
20
20
  }
21
- executeFinishChannel.publish(undefined)
21
+ finishChannel.publish(undefined)
22
22
  }
23
23
 
24
24
  addHook({ name: 'oracledb', versions: ['5'] }, oracledb => {
25
25
  shimmer.wrap(oracledb.Connection.prototype, 'execute', execute => {
26
26
  return function wrappedExecute (dbQuery, ...args) {
27
- if (!executeStartChannel.hasSubscribers) {
27
+ if (!startChannel.hasSubscribers) {
28
28
  return execute.apply(this, arguments)
29
29
  }
30
30
 
@@ -39,7 +39,7 @@ addHook({ name: 'oracledb', versions: ['5'] }, oracledb => {
39
39
 
40
40
  return new AsyncResource('apm:oracledb:inner-scope').runInAsyncScope(() => {
41
41
  const connAttrs = connectionAttributes.get(this)
42
- executeStartChannel.publish({ query: dbQuery, connAttrs })
42
+ startChannel.publish({ query: dbQuery, connAttrs })
43
43
  try {
44
44
  let result = execute.apply(this, arguments)
45
45
 
@@ -58,7 +58,7 @@ addHook({ name: 'oracledb', versions: ['5'] }, oracledb => {
58
58
 
59
59
  return result
60
60
  } catch (err) {
61
- executeErrorChannel.publish(err)
61
+ errorChannel.publish(err)
62
62
  throw err
63
63
  }
64
64
  })
@@ -37,12 +37,16 @@ function wrapQuery (query) {
37
37
  return retval
38
38
  }
39
39
 
40
- const statement = pgQuery.text
41
40
  const callbackResource = new AsyncResource('bound-anonymous-fn')
42
41
  const asyncResource = new AsyncResource('bound-anonymous-fn')
43
-
42
+ const processId = this.processID
44
43
  return asyncResource.runInAsyncScope(() => {
45
- startCh.publish({ params: this.connectionParameters, statement })
44
+ startCh.publish({
45
+ params: this.connectionParameters,
46
+ originalQuery: pgQuery.text,
47
+ query: pgQuery,
48
+ processId
49
+ })
46
50
 
47
51
  const finish = asyncResource.bind(function (error) {
48
52
  if (error) {
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+
3
+ const { addHook, channel } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+
6
+ const qsParseCh = channel('datadog:qs:parse:finish')
7
+
8
+ function wrapParse (originalParse) {
9
+ return function () {
10
+ const qsParsedObj = originalParse.apply(this, arguments)
11
+ if (qsParseCh.hasSubscribers && qsParsedObj) {
12
+ qsParseCh.publish({ qs: qsParsedObj })
13
+ }
14
+ return qsParsedObj
15
+ }
16
+ }
17
+
18
+ addHook({
19
+ name: 'qs',
20
+ versions: ['>=1']
21
+ }, qs => {
22
+ shimmer.wrap(qs, 'parse', wrapParse)
23
+ return qs
24
+ })