dd-trace 2.21.0 → 2.22.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 (74) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/index.d.ts +42 -31
  3. package/package.json +4 -2
  4. package/packages/datadog-instrumentations/src/body-parser.js +26 -0
  5. package/packages/datadog-instrumentations/src/child-process.js +30 -0
  6. package/packages/datadog-instrumentations/src/connect.js +15 -15
  7. package/packages/datadog-instrumentations/src/cucumber.js +1 -1
  8. package/packages/datadog-instrumentations/src/hapi.js +3 -3
  9. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
  10. package/packages/datadog-instrumentations/src/http/server.js +11 -12
  11. package/packages/datadog-instrumentations/src/jest.js +102 -42
  12. package/packages/datadog-instrumentations/src/koa.js +32 -32
  13. package/packages/datadog-instrumentations/src/mocha.js +87 -6
  14. package/packages/datadog-instrumentations/src/pg.js +1 -2
  15. package/packages/datadog-instrumentations/src/qs.js +24 -0
  16. package/packages/datadog-instrumentations/src/restify.js +6 -3
  17. package/packages/datadog-instrumentations/src/router.js +22 -22
  18. package/packages/datadog-plugin-cucumber/src/index.js +13 -32
  19. package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
  20. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +0 -1
  21. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +0 -1
  22. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +0 -1
  23. package/packages/datadog-plugin-http/src/client.js +5 -3
  24. package/packages/datadog-plugin-http/src/server.js +11 -0
  25. package/packages/datadog-plugin-http2/src/client.js +2 -0
  26. package/packages/datadog-plugin-http2/src/server.js +3 -0
  27. package/packages/datadog-plugin-jest/src/index.js +11 -131
  28. package/packages/datadog-plugin-mocha/src/index.js +33 -46
  29. package/packages/datadog-plugin-net/src/index.js +4 -0
  30. package/packages/datadog-plugin-next/src/index.js +3 -0
  31. package/packages/datadog-plugin-pg/src/index.js +5 -2
  32. package/packages/datadog-plugin-router/src/index.js +9 -1
  33. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +3 -5
  34. package/packages/dd-trace/src/appsec/gateway/engine/index.js +1 -1
  35. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -1
  36. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
  37. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
  38. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
  39. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
  40. package/packages/dd-trace/src/appsec/iast/index.js +6 -0
  41. package/packages/dd-trace/src/appsec/iast/path-line.js +8 -1
  42. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
  43. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
  44. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +125 -0
  45. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
  46. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
  47. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +66 -0
  48. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +52 -6
  49. package/packages/dd-trace/src/appsec/index.js +8 -0
  50. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
  51. package/packages/dd-trace/src/appsec/remote_config/index.js +34 -0
  52. package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
  53. package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
  54. package/packages/dd-trace/src/appsec/rule_manager.js +3 -0
  55. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +5 -7
  56. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +1 -3
  57. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -3
  58. package/packages/dd-trace/src/config.js +25 -9
  59. package/packages/dd-trace/src/constants.js +6 -1
  60. package/packages/dd-trace/src/exporters/common/request.js +7 -1
  61. package/packages/dd-trace/src/format.js +12 -10
  62. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
  63. package/packages/dd-trace/src/opentracing/span_context.js +9 -0
  64. package/packages/dd-trace/src/plugin_manager.js +4 -1
  65. package/packages/dd-trace/src/plugins/ci_plugin.js +132 -0
  66. package/packages/dd-trace/src/plugins/database.js +46 -0
  67. package/packages/dd-trace/src/plugins/tracing.js +2 -0
  68. package/packages/dd-trace/src/plugins/util/test.js +61 -8
  69. package/packages/dd-trace/src/plugins/util/web.js +14 -9
  70. package/packages/dd-trace/src/profiling/config.js +3 -1
  71. package/packages/dd-trace/src/profiling/index.js +2 -2
  72. package/packages/dd-trace/src/profiling/profiler.js +35 -6
  73. package/packages/dd-trace/src/proxy.js +5 -1
  74. package/packages/dd-trace/src/tracer.js +4 -3
@@ -1,8 +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')
5
4
  const log = require('../../dd-trace/src/log')
5
+ const { getCoveredFilenamesFromCoverage } = require('../../dd-trace/src/plugins/util/test')
6
6
 
7
7
  const testSessionStartCh = channel('ci:jest:session:start')
8
8
  const testSessionFinishCh = channel('ci:jest:session:finish')
@@ -23,6 +23,7 @@ const jestConfigurationCh = channel('ci:jest:configuration')
23
23
 
24
24
  let skippableSuites = []
25
25
  let isCodeCoverageEnabled = false
26
+ let isSuitesSkippingEnabled = false
26
27
 
27
28
  const {
28
29
  getTestSuitePath,
@@ -33,21 +34,6 @@ const { getFormattedJestTestParameters, getJestTestName } = require('../../datad
33
34
 
34
35
  const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
35
36
 
36
- function extractCoverageInformation (coverage, rootDir) {
37
- const coverageMap = istanbul.createCoverageMap(coverage)
38
-
39
- return coverageMap
40
- .files()
41
- .filter(filename => {
42
- const fileCoverage = coverageMap.fileCoverageFor(filename)
43
- const lineCoverage = fileCoverage.getLineCoverage()
44
- const isAnyLineExecuted = Object.entries(lineCoverage).some(([, numExecutions]) => !!numExecutions)
45
-
46
- return isAnyLineExecuted
47
- })
48
- .map(filename => filename.replace(`${rootDir}/`, ''))
49
- }
50
-
51
37
  const specStatusToTestStatus = {
52
38
  'pending': 'skip',
53
39
  'disabled': 'skip',
@@ -186,38 +172,42 @@ addHook({
186
172
 
187
173
  function cliWrapper (cli) {
188
174
  const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
189
- let onResponse, onError
190
- const configurationPromise = new Promise((resolve, reject) => {
191
- onResponse = resolve
192
- onError = reject
175
+ let onDone
176
+ const configurationPromise = new Promise((resolve) => {
177
+ onDone = resolve
193
178
  })
194
179
 
195
180
  sessionAsyncResource.runInAsyncScope(() => {
196
- jestConfigurationCh.publish({ onResponse, onError })
181
+ jestConfigurationCh.publish({ onDone })
197
182
  })
198
183
 
199
- let isSuitesSkippingEnabled = false
200
-
201
184
  try {
202
- const config = await configurationPromise
185
+ const { err, config } = await configurationPromise
186
+ if (err) {
187
+ log.error(err)
188
+ }
203
189
  isCodeCoverageEnabled = config.isCodeCoverageEnabled
204
190
  isSuitesSkippingEnabled = config.isSuitesSkippingEnabled
205
191
  } catch (e) {
206
- // ignore error
192
+ log.error(e)
207
193
  }
208
194
 
209
195
  if (isSuitesSkippingEnabled) {
210
- const skippableSuitesPromise = new Promise((resolve, reject) => {
211
- onResponse = resolve
212
- onError = reject
196
+ const skippableSuitesPromise = new Promise((resolve) => {
197
+ onDone = resolve
213
198
  })
214
199
 
215
200
  sessionAsyncResource.runInAsyncScope(() => {
216
- skippableSuitesCh.publish({ onResponse, onError })
201
+ skippableSuitesCh.publish({ onDone })
217
202
  })
218
203
 
219
204
  try {
220
- skippableSuites = await skippableSuitesPromise
205
+ const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
206
+ if (err) {
207
+ log.error(err)
208
+ } else {
209
+ skippableSuites = receivedSkippableSuites
210
+ }
221
211
  } catch (e) {
222
212
  log.error(e)
223
213
  }
@@ -253,6 +243,35 @@ function cliWrapper (cli) {
253
243
  return cli
254
244
  }
255
245
 
246
+ function coverageReporterWrapper (coverageReporter) {
247
+ const CoverageReporter = coverageReporter.default ? coverageReporter.default : coverageReporter
248
+
249
+ /**
250
+ * If ITR is active, we're running fewer tests, so of course the total code coverage is reduced.
251
+ * This calculation adds no value, so we'll skip it.
252
+ */
253
+ shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => async function () {
254
+ if (isSuitesSkippingEnabled) {
255
+ return Promise.resolve()
256
+ }
257
+ return addUntestedFiles.apply(this, arguments)
258
+ })
259
+
260
+ return coverageReporter
261
+ }
262
+
263
+ addHook({
264
+ name: '@jest/reporters',
265
+ file: 'build/coverage_reporter.js',
266
+ versions: ['>=24.8.0 <26.6.2']
267
+ }, coverageReporterWrapper)
268
+
269
+ addHook({
270
+ name: '@jest/reporters',
271
+ file: 'build/CoverageReporter.js',
272
+ versions: ['>=26.6.2']
273
+ }, coverageReporterWrapper)
274
+
256
275
  addHook({
257
276
  name: '@jest/core',
258
277
  file: 'build/cli/index.js',
@@ -281,13 +300,16 @@ function jestAdapterWrapper (jestAdapter) {
281
300
  status = 'fail'
282
301
  }
283
302
  testSuiteFinishCh.publish({ status, errorMessage })
284
- if (environment.global.__coverage__) {
285
- const coverageFiles = extractCoverageInformation(environment.global.__coverage__, environment.rootDir)
286
- if (coverageFiles.length &&
287
- environment.testEnvironmentOptions &&
288
- environment.testEnvironmentOptions._ddTestCodeCoverageEnabled) {
303
+
304
+ const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
305
+ .map(filename => getTestSuitePath(filename, environment.rootDir))
306
+
307
+ if (coverageFiles &&
308
+ environment.testEnvironmentOptions &&
309
+ environment.testEnvironmentOptions._ddTestCodeCoverageEnabled) {
310
+ asyncResource.runInAsyncScope(() => {
289
311
  testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
290
- }
312
+ })
291
313
  }
292
314
  return suiteResults
293
315
  })
@@ -310,12 +332,6 @@ addHook({
310
332
 
311
333
  function configureTestEnvironment (readConfigsResult) {
312
334
  const { configs } = readConfigsResult
313
- configs.forEach(config => {
314
- skippableSuites.forEach((suite) => {
315
- config.testMatch.push(`!**/${suite}`)
316
- })
317
- skippableSuites = []
318
- })
319
335
  sessionAsyncResource.runInAsyncScope(() => {
320
336
  testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
321
337
  })
@@ -324,6 +340,7 @@ function configureTestEnvironment (readConfigsResult) {
324
340
  configs.forEach(config => {
325
341
  config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
326
342
  })
343
+
327
344
  if (isCodeCoverageEnabled) {
328
345
  const globalConfig = {
329
346
  ...readConfigsResult.globalConfig,
@@ -331,6 +348,16 @@ function configureTestEnvironment (readConfigsResult) {
331
348
  }
332
349
  readConfigsResult.globalConfig = globalConfig
333
350
  }
351
+ if (isSuitesSkippingEnabled) {
352
+ // If suite skipping is enabled, the code coverage results are not going to be relevant,
353
+ // so we do not show them.
354
+ const globalConfig = {
355
+ ...readConfigsResult.globalConfig,
356
+ coverageReporters: ['none']
357
+ }
358
+ readConfigsResult.globalConfig = globalConfig
359
+ }
360
+
334
361
  return readConfigsResult
335
362
  }
336
363
 
@@ -352,6 +379,39 @@ function jestConfigSyncWrapper (jestConfig) {
352
379
  return jestConfig
353
380
  }
354
381
 
382
+ /**
383
+ * Hook to remove the test paths (test suite) that are part of `skippableSuites`
384
+ */
385
+ addHook({
386
+ name: '@jest/core',
387
+ versions: ['>=24.8.0'],
388
+ file: 'build/SearchSource.js'
389
+ }, searchSourcePackage => {
390
+ const SearchSource = searchSourcePackage.default ? searchSourcePackage.default : searchSourcePackage
391
+
392
+ shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
393
+ if (!skippableSuites.length) {
394
+ return getTestPaths.apply(this, arguments)
395
+ }
396
+
397
+ const [{ rootDir }] = arguments
398
+
399
+ const testPaths = await getTestPaths.apply(this, arguments)
400
+ const { tests } = testPaths
401
+
402
+ const filteredTests = tests.filter(({ path: testPath }) => {
403
+ const relativePath = testPath.replace(`${rootDir}/`, '')
404
+ return !skippableSuites.includes(relativePath)
405
+ })
406
+
407
+ skippableSuites = []
408
+
409
+ return { ...testPaths, tests: filteredTests }
410
+ })
411
+
412
+ return searchSourcePackage
413
+ })
414
+
355
415
  // from 25.1.0 on, readConfigs becomes async
356
416
  addHook({
357
417
  name: 'jest-config',
@@ -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) {
@@ -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
 
20
+ const configurationCh = channel('ci:mocha:configuration')
21
+ const skippableSuitesCh = channel('ci:mocha:test-suite:skippable')
22
+
10
23
  const testSessionStartCh = channel('ci:mocha:session:start')
11
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) {
@@ -93,6 +112,8 @@ function mochaHook (Runner) {
93
112
  }
94
113
  testFileToSuiteAr.clear()
95
114
  testSessionFinishCh.publish(status)
115
+ // restore the original coverage
116
+ global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
96
117
  }))
97
118
 
98
119
  this.once('start', testRunAsyncResource.bind(function () {
@@ -140,9 +161,21 @@ function mochaHook (Runner) {
140
161
  })
141
162
  }
142
163
 
164
+ if (global.__coverage__) {
165
+ const coverageFiles = getCoveredFilenamesFromCoverage(global.__coverage__)
166
+
167
+ testSuiteCodeCoverageCh.publish({
168
+ coverageFiles,
169
+ suiteFile: suite.file
170
+ })
171
+ // We need to reset coverage to get a code coverage per suite
172
+ // Before that, we preserve the original coverage
173
+ mergeCoverage(global.__coverage__, originalCoverageMap)
174
+ resetCoverage(global.__coverage__)
175
+ }
176
+
143
177
  const asyncResource = testFileToSuiteAr.get(suite.file)
144
178
  asyncResource.runInAsyncScope(() => {
145
- // get suite status
146
179
  testSuiteFinishCh.publish(status)
147
180
  })
148
181
  })
@@ -229,7 +262,8 @@ function mochaHook (Runner) {
229
262
  skipCh.publish(test)
230
263
  })
231
264
  } else {
232
- // if there is no async resource, the test has been skipped through `test.skip``
265
+ // if there is no async resource, the test has been skipped through `test.skip`
266
+ // or the parent suite is skipped
233
267
  const skippedTestAsyncResource = new AsyncResource('bound-anonymous-fn')
234
268
  if (test.fn) {
235
269
  testToAr.set(test.fn, skippedTestAsyncResource)
@@ -242,6 +276,11 @@ function mochaHook (Runner) {
242
276
  }
243
277
  })
244
278
 
279
+ // We remove the suites that we skip through ITR
280
+ this.suite.suites = this.suite.suites.filter(suite =>
281
+ !suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
282
+ )
283
+
245
284
  return run.apply(this, arguments)
246
285
  })
247
286
 
@@ -266,6 +305,48 @@ function mochaEachHook (mochaEach) {
266
305
  })
267
306
  }
268
307
 
308
+ addHook({
309
+ name: 'mocha',
310
+ versions: ['>=5.2.0'],
311
+ file: 'lib/mocha.js'
312
+ }, (Mocha) => {
313
+ const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
314
+
315
+ /**
316
+ * Get ITR configuration and skippable suites
317
+ * If ITR is disabled, `onDone` is called immediately on the subscriber
318
+ */
319
+ shimmer.wrap(Mocha.prototype, 'run', run => function () {
320
+ const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
321
+ if (err) {
322
+ log.error(err)
323
+ suitesToSkip = []
324
+ } else {
325
+ suitesToSkip = skippableSuites
326
+ }
327
+ run.apply(this, arguments)
328
+ }
329
+
330
+ const onReceivedConfiguration = ({ err }) => {
331
+ if (err) {
332
+ log.error(err)
333
+ return run.apply(this, arguments)
334
+ }
335
+
336
+ skippableSuitesCh.publish({
337
+ onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
338
+ })
339
+ }
340
+
341
+ mochaRunAsyncResource.runInAsyncScope(() => {
342
+ configurationCh.publish({
343
+ onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
344
+ })
345
+ })
346
+ })
347
+ return Mocha
348
+ })
349
+
269
350
  addHook({
270
351
  name: 'mocha',
271
352
  versions: ['>=5.2.0'],
@@ -37,13 +37,12 @@ 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
 
45
44
  return asyncResource.runInAsyncScope(() => {
46
- startCh.publish({ params: this.connectionParameters, statement, processId })
45
+ startCh.publish({ params: this.connectionParameters, query: pgQuery, processId })
47
46
 
48
47
  const finish = asyncResource.bind(function (error) {
49
48
  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
+ })
@@ -9,6 +9,7 @@ const handleChannel = channel('apm:restify:request:handle')
9
9
  const errorChannel = channel('apm:restify:middleware:error')
10
10
  const enterChannel = channel('apm:restify:middleware:enter')
11
11
  const exitChannel = channel('apm:restify:middleware:exit')
12
+ const finishChannel = channel('apm:restify:middleware:finish')
12
13
  const nextChannel = channel('apm:restify:middleware:next')
13
14
 
14
15
  function wrapSetupRequest (setupRequest) {
@@ -53,8 +54,10 @@ function wrapFn (fn) {
53
54
  } catch (error) {
54
55
  errorChannel.publish({ req, error })
55
56
  nextChannel.publish({ req })
56
- exitChannel.publish({ req })
57
+ finishChannel.publish({ req })
57
58
  throw error
59
+ } finally {
60
+ exitChannel.publish({ req })
58
61
  }
59
62
  }
60
63
  }
@@ -62,13 +65,13 @@ function wrapFn (fn) {
62
65
  function wrapNext (req, next) {
63
66
  return function () {
64
67
  nextChannel.publish({ req })
65
- exitChannel.publish({ req })
68
+ finishChannel.publish({ req })
66
69
 
67
70
  next.apply(this, arguments)
68
71
  }
69
72
  }
70
73
 
71
- addHook({ name: 'restify', versions: ['>=3'], file: 'lib/server.js' }, Server => {
74
+ addHook({ name: 'restify', versions: ['>=3 <=8.6.1'], file: 'lib/server.js' }, Server => {
72
75
  shimmer.wrap(Server.prototype, '_setupRequest', wrapSetupRequest)
73
76
  shimmer.massWrap(Server.prototype, handlers, wrapHandler)
74
77
  shimmer.massWrap(Server.prototype, methods, wrapMethod)
@@ -3,11 +3,12 @@
3
3
  const METHODS = require('methods').concat('all')
4
4
  const pathToRegExp = require('path-to-regexp')
5
5
  const shimmer = require('../../datadog-shimmer')
6
- const { addHook, channel, AsyncResource } = require('./helpers/instrument')
6
+ const { addHook, channel } = require('./helpers/instrument')
7
7
 
8
8
  function createWrapRouterMethod (name) {
9
9
  const enterChannel = channel(`apm:${name}:middleware:enter`)
10
10
  const exitChannel = channel(`apm:${name}:middleware:exit`)
11
+ const finishChannel = channel(`apm:${name}:middleware:finish`)
11
12
  const errorChannel = channel(`apm:${name}:middleware:error`)
12
13
  const nextChannel = channel(`apm:${name}:middleware:next`)
13
14
 
@@ -21,7 +22,6 @@ function createWrapRouterMethod (name) {
21
22
  if (!enterChannel.hasSubscribers) return original.apply(this, arguments)
22
23
 
23
24
  const matchers = layerMatchers.get(layer)
24
- const middlewareResource = new AsyncResource('bound-anonymous-fn')
25
25
  const lastIndex = arguments.length - 1
26
26
  const name = original._name || original.name
27
27
  const req = arguments[arguments.length > 3 ? 1 : 0]
@@ -31,32 +31,32 @@ function createWrapRouterMethod (name) {
31
31
  arguments[lastIndex] = wrapNext(req, next)
32
32
  }
33
33
 
34
- return middlewareResource.runInAsyncScope(() => {
35
- let route
34
+ let route
36
35
 
37
- if (matchers) {
38
- // Try to guess which path actually matched
39
- for (let i = 0; i < matchers.length; i++) {
40
- if (matchers[i].test(layer)) {
41
- route = matchers[i].path
36
+ if (matchers) {
37
+ // Try to guess which path actually matched
38
+ for (let i = 0; i < matchers.length; i++) {
39
+ if (matchers[i].test(layer)) {
40
+ route = matchers[i].path
42
41
 
43
- break
44
- }
42
+ break
45
43
  }
46
44
  }
45
+ }
47
46
 
48
- enterChannel.publish({ name, req, route })
47
+ enterChannel.publish({ name, req, route })
49
48
 
50
- try {
51
- return original.apply(this, arguments)
52
- } catch (error) {
53
- errorChannel.publish({ req, error })
54
- nextChannel.publish({ req })
55
- exitChannel.publish({ req })
49
+ try {
50
+ return original.apply(this, arguments)
51
+ } catch (error) {
52
+ errorChannel.publish({ req, error })
53
+ nextChannel.publish({ req })
54
+ finishChannel.publish({ req })
56
55
 
57
- throw error
58
- }
59
- })
56
+ throw error
57
+ } finally {
58
+ exitChannel.publish({ req })
59
+ }
60
60
  })
61
61
 
62
62
  // This is a workaround for the `loopback` library so that it can find the correct express layer
@@ -95,7 +95,7 @@ function createWrapRouterMethod (name) {
95
95
  }
96
96
 
97
97
  nextChannel.publish({ req })
98
- exitChannel.publish({ req })
98
+ finishChannel.publish({ req })
99
99
 
100
100
  next.apply(this, arguments)
101
101
  }