dd-trace 2.12.2 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/ext/tags.d.ts +2 -1
  3. package/ext/tags.js +2 -1
  4. package/index.d.ts +43 -20
  5. package/package.json +5 -3
  6. package/packages/datadog-core/src/storage/async_resource.js +19 -1
  7. package/packages/datadog-instrumentations/index.js +1 -52
  8. package/packages/datadog-instrumentations/src/crypto.js +30 -0
  9. package/packages/datadog-instrumentations/src/cucumber.js +15 -0
  10. package/packages/datadog-instrumentations/src/fs.js +11 -0
  11. package/packages/datadog-instrumentations/src/helpers/hooks.js +70 -0
  12. package/packages/datadog-instrumentations/src/helpers/instrument.js +5 -34
  13. package/packages/datadog-instrumentations/src/helpers/instrumentations.js +7 -0
  14. package/packages/datadog-instrumentations/src/helpers/register.js +59 -0
  15. package/packages/datadog-instrumentations/src/http/server.js +1 -1
  16. package/packages/datadog-instrumentations/src/jest.js +33 -11
  17. package/packages/datadog-instrumentations/src/net.js +13 -0
  18. package/packages/datadog-plugin-cucumber/src/index.js +4 -0
  19. package/packages/datadog-plugin-fs/src/index.js +72 -38
  20. package/packages/datadog-plugin-jest/src/index.js +25 -4
  21. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  22. package/packages/datadog-plugin-mongodb-core/src/index.js +32 -8
  23. package/packages/datadog-plugin-oracledb/src/index.js +12 -4
  24. package/packages/dd-trace/index.js +1 -1
  25. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -0
  26. package/packages/dd-trace/src/appsec/iast/analyzers/index.js +20 -0
  27. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +48 -0
  28. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +24 -0
  29. package/packages/dd-trace/src/appsec/iast/iast-context.js +50 -0
  30. package/packages/dd-trace/src/appsec/iast/index.js +59 -0
  31. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +94 -0
  32. package/packages/dd-trace/src/appsec/iast/path-line.js +70 -0
  33. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +113 -0
  34. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +50 -0
  35. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +53 -8
  36. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +23 -24
  37. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +220 -0
  38. package/packages/dd-trace/src/config.js +89 -10
  39. package/packages/dd-trace/src/constants.js +9 -1
  40. package/packages/dd-trace/src/encode/0.4.js +51 -58
  41. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +13 -34
  42. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +84 -0
  43. package/packages/dd-trace/src/encode/span-stats.js +155 -0
  44. package/packages/dd-trace/src/exporters/agent/index.js +25 -7
  45. package/packages/dd-trace/src/exporters/agent/writer.js +7 -4
  46. package/packages/dd-trace/src/{profiling/exporters → exporters/common}/form-data.js +0 -0
  47. package/packages/dd-trace/src/exporters/common/request.js +25 -10
  48. package/packages/dd-trace/src/exporters/common/writer.js +9 -6
  49. package/packages/dd-trace/src/exporters/span-stats/index.js +20 -0
  50. package/packages/dd-trace/src/exporters/span-stats/writer.js +54 -0
  51. package/packages/dd-trace/src/format.js +2 -0
  52. package/packages/dd-trace/src/id.js +16 -13
  53. package/packages/dd-trace/src/iitm.js +11 -0
  54. package/packages/dd-trace/src/index.js +10 -0
  55. package/packages/dd-trace/src/noop/proxy.js +87 -0
  56. package/packages/dd-trace/src/opentracing/propagation/text_map.js +77 -6
  57. package/packages/dd-trace/src/opentracing/tracer.js +1 -1
  58. package/packages/dd-trace/src/plugin_manager.js +107 -65
  59. package/packages/dd-trace/src/plugins/index.js +58 -45
  60. package/packages/dd-trace/src/plugins/log_plugin.js +16 -9
  61. package/packages/dd-trace/src/plugins/util/ci.js +34 -9
  62. package/packages/dd-trace/src/plugins/util/git.js +52 -2
  63. package/packages/dd-trace/src/plugins/util/ip_blocklist.js +25 -0
  64. package/packages/dd-trace/src/plugins/util/tags.js +4 -1
  65. package/packages/dd-trace/src/plugins/util/web.js +99 -2
  66. package/packages/dd-trace/src/priority_sampler.js +36 -1
  67. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  68. package/packages/dd-trace/src/proxy.js +23 -89
  69. package/packages/dd-trace/src/ritm.js +10 -1
  70. package/packages/dd-trace/src/span_processor.js +7 -1
  71. package/packages/dd-trace/src/span_stats.js +210 -0
  72. package/packages/dd-trace/src/startup-log.js +8 -19
  73. package/packages/dd-trace/src/telemetry/dependencies.js +83 -0
  74. package/packages/dd-trace/src/{telemetry.js → telemetry/index.js} +11 -79
  75. package/packages/dd-trace/src/telemetry/send-data.js +35 -0
  76. package/scripts/install_plugin_modules.js +17 -26
@@ -4,10 +4,12 @@ require,@datadog/native-metrics,Apache license 2.0,Copyright 2018 Datadog Inc.
4
4
  require,@datadog/pprof,Apache license 2.0,Copyright 2019 Google Inc.
5
5
  require,@datadog/sketches-js,Apache license 2.0,Copyright 2020 Datadog Inc.
6
6
  require,@types/node,MIT,Copyright Authors
7
+ require,cidr-matcher,MIT,Copyright 2015 Marco Pracucci
7
8
  require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
8
9
  require,diagnostics_channel,MIT,Copyright 2021 Simon D.
9
10
  require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
10
11
  require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
12
+ require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.
11
13
  require,koalas,MIT,Copyright 2013-2017 Brian Woodward
12
14
  require,limiter,MIT,Copyright 2011 John Hurliman
13
15
  require,lodash.kebabcase,MIT,Copyright JS Foundation and other contributors
package/ext/tags.d.ts CHANGED
@@ -15,7 +15,8 @@ declare const tags: {
15
15
  HTTP_ROUTE: 'http.route'
16
16
  HTTP_REQUEST_HEADERS: 'http.request.headers'
17
17
  HTTP_RESPONSE_HEADERS: 'http.response.headers'
18
- HTTP_USERAGENT: 'http.useragent'
18
+ HTTP_USERAGENT: 'http.useragent',
19
+ HTTP_CLIENT_IP: 'http.client_ip'
19
20
  }
20
21
 
21
22
  export = tags
package/ext/tags.js CHANGED
@@ -20,7 +20,8 @@ const tags = {
20
20
  HTTP_ROUTE: 'http.route',
21
21
  HTTP_REQUEST_HEADERS: 'http.request.headers',
22
22
  HTTP_RESPONSE_HEADERS: 'http.response.headers',
23
- HTTP_USERAGENT: 'http.useragent'
23
+ HTTP_USERAGENT: 'http.useragent',
24
+ HTTP_CLIENT_IP: 'http.client_ip'
24
25
  }
25
26
 
26
27
  // Deprecated
package/index.d.ts CHANGED
@@ -267,6 +267,22 @@ export declare interface TracerOptions {
267
267
  */
268
268
  sampleRate?: number;
269
269
 
270
+ /**
271
+ * Global rate limit that is applied on the global sample rate and all rules,
272
+ * and controls the ingestion rate limit between the agent and the backend.
273
+ * Defaults to deferring the decision to the agent.
274
+ */
275
+ rateLimit?: Number,
276
+
277
+ /**
278
+ * Sampling rules to apply to priority samplin. Each rule is a JSON,
279
+ * consisting of `service` and `name`, which are regexes to match against
280
+ * a trace's `service` and `name`, and a corresponding `sampleRate`. If not
281
+ * specified, will defer to global sampling rate for all spans.
282
+ * @default []
283
+ */
284
+ samplingRules?: SamplingRule[]
285
+
270
286
  /**
271
287
  * Interval in milliseconds at which the tracer will submit traces to the agent.
272
288
  * @default 2000
@@ -298,7 +314,10 @@ export declare interface TracerOptions {
298
314
  protocolVersion?: string
299
315
 
300
316
  /**
301
- * Configuration of the ingestion between the agent and the backend.
317
+ * Deprecated in favor of the global versions of the variables provided under this option
318
+ *
319
+ * @deprecated
320
+ * @hidden
302
321
  */
303
322
  ingestion?: {
304
323
  /**
@@ -307,7 +326,7 @@ export declare interface TracerOptions {
307
326
  sampleRate?: number
308
327
 
309
328
  /**
310
- * Controls the ingestion rate limit between the agent and the backend.
329
+ * Controls the ingestion rate limit between the agent and the backend. Defaults to deferring the decision to the agent.
311
330
  */
312
331
  rateLimit?: number
313
332
  };
@@ -333,32 +352,36 @@ export declare interface TracerOptions {
333
352
  exporter?: 'log' | 'agent'
334
353
 
335
354
  /**
336
- * Configuration of the priority sampler. Supports a global config and rules by span name or service name. The first matching rule is applied, and if no rule matches it falls back to the global config or on the rates provided by the agent if there is no global config.
355
+ * Whether to enable the experimental `getRumData` method.
356
+ * @default false
337
357
  */
338
- sampler?: {
358
+ enableGetRumData?: boolean
359
+
360
+ /**
361
+ * Configuration of the IAST. Can be a boolean as an alias to `iast.enabled`.
362
+ */
363
+ iast?: boolean | {
339
364
  /**
340
- * Sample rate to apply globally when no other rule is matched. Omit to fallback on the dynamic rates returned by the agent instead.
365
+ * Whether to enable IAST.
366
+ * @default false
341
367
  */
342
- sampleRate?: Number,
343
-
368
+ enabled?: boolean,
344
369
  /**
345
- * Global rate limit that is applied on the global sample rate and all rules.
346
- * @default 100
370
+ * Controls the percentage of requests that iast will analyze
371
+ * @default 30
347
372
  */
348
- rateLimit?: Number,
349
-
373
+ requestSampling?: number,
350
374
  /**
351
- * Sampling rules to apply to priority sampling.
352
- * @default []
375
+ * Controls how many request can be analyzing code vulnerabilities at the same time
376
+ * @default 2
353
377
  */
354
- rules?: SamplingRule[]
378
+ maxConcurrentRequests?: number,
379
+ /**
380
+ * Controls how many code vulnerabilities can be detected in the same request
381
+ * @default 2
382
+ */
383
+ maxContextOperations?: number
355
384
  }
356
-
357
- /**
358
- * Whether to enable the experimental `getRumData` method.
359
- * @default false
360
- */
361
- enableGetRumData?: boolean
362
385
  };
363
386
 
364
387
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.12.2",
3
+ "version": "2.15.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -61,12 +61,14 @@
61
61
  "@datadog/native-appsec": "^1.2.1",
62
62
  "@datadog/native-metrics": "^1.4.2",
63
63
  "@datadog/pprof": "^1.0.2",
64
- "@datadog/sketches-js": "^1.0.5",
64
+ "@datadog/sketches-js": "^2.1.0",
65
65
  "@types/node": ">=12",
66
+ "cidr-matcher": "^2.1.1",
66
67
  "crypto-randomuuid": "^1.0.0",
67
68
  "diagnostics_channel": "^1.1.0",
68
69
  "ignore": "^5.2.0",
69
- "import-in-the-middle": "^1.3.0",
70
+ "import-in-the-middle": "^1.3.1",
71
+ "istanbul-lib-coverage": "3.2.0",
70
72
  "koalas": "^1.0.2",
71
73
  "limiter": "^1.1.4",
72
74
  "lodash.kebabcase": "^4.1.1",
@@ -6,9 +6,27 @@ const { channel } = require('diagnostics_channel')
6
6
  const beforeCh = channel('dd-trace:storage:before')
7
7
  const afterCh = channel('dd-trace:storage:after')
8
8
 
9
+ let PrivateSymbol = Symbol
10
+ function makePrivateSymbol () {
11
+ // eslint-disable-next-line no-new-func
12
+ PrivateSymbol = new Function('name', 'return %CreatePrivateSymbol(name)')
13
+ }
14
+
15
+ try {
16
+ makePrivateSymbol()
17
+ } catch (e) {
18
+ try {
19
+ const v8 = require('v8')
20
+ v8.setFlagsFromString('--allow-natives-syntax')
21
+ makePrivateSymbol()
22
+ v8.setFlagsFromString('--no-allow-natives-syntax')
23
+ // eslint-disable-next-line no-empty
24
+ } catch (e) {}
25
+ }
26
+
9
27
  class AsyncResourceStorage {
10
28
  constructor () {
11
- this._ddResourceStore = Symbol('ddResourceStore')
29
+ this._ddResourceStore = PrivateSymbol('ddResourceStore')
12
30
  this._enabled = false
13
31
  this._hook = createHook(this._createHook())
14
32
  }
@@ -1,54 +1,3 @@
1
1
  'use strict'
2
2
 
3
- require('./src/amqplib')
4
- require('./src/amqp10')
5
- require('./src/aws-sdk')
6
- require('./src/bluebird')
7
- require('./src/bunyan')
8
- require('./src/cassandra-driver')
9
- require('./src/connect')
10
- require('./src/couchbase')
11
- require('./src/cucumber')
12
- require('./src/dns')
13
- require('./src/elasticsearch')
14
- require('./src/express')
15
- require('./src/fastify')
16
- require('./src/find-my-way')
17
- require('./src/generic-pool')
18
- require('./src/google-cloud-pubsub')
19
- require('./src/graphql')
20
- require('./src/grpc')
21
- require('./src/hapi')
22
- require('./src/http')
23
- require('./src/http2')
24
- require('./src/ioredis')
25
- require('./src/jest')
26
- require('./src/kafkajs')
27
- require('./src/knex')
28
- require('./src/koa')
29
- require('./src/memcached')
30
- require('./src/microgateway-core')
31
- require('./src/moleculer')
32
- require('./src/mongodb-core')
33
- require('./src/mongoose')
34
- require('./src/mysql')
35
- require('./src/mysql2')
36
- require('./src/mocha')
37
- require('./src/net')
38
- require('./src/next')
39
- require('./src/oracledb')
40
- require('./src/paperplane')
41
- require('./src/pino')
42
- require('./src/pg')
43
- require('./src/promise')
44
- require('./src/promise-js')
45
- require('./src/q')
46
- require('./src/redis')
47
- require('./src/restify')
48
- require('./src/router')
49
- require('./src/rhea')
50
- require('./src/sharedb')
51
- require('./src/tedious')
52
- require('./src/when')
53
- require('./src/winston')
54
- require('./src/limitd-client')
3
+ require('./src/helpers/register')
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook
6
+ } = require('./helpers/instrument')
7
+ const shimmer = require('../../datadog-shimmer')
8
+
9
+ const cryptoCh = channel('datadog:crypto:hashing:start')
10
+
11
+ addHook({ name: 'crypto' }, crypto => {
12
+ shimmer.massWrap(
13
+ crypto,
14
+ ['createHash', 'createHmac', 'createSign', 'createVerify', 'sign', 'verify'],
15
+ wrapMethod
16
+ )
17
+ return crypto
18
+ })
19
+
20
+ function wrapMethod (cryptoMethod) {
21
+ return function () {
22
+ if (cryptoCh.hasSubscribers) {
23
+ if (arguments.length > 0) {
24
+ const algorithm = arguments[0]
25
+ cryptoCh.publish({ algorithm })
26
+ }
27
+ }
28
+ return cryptoMethod.apply(this, arguments)
29
+ }
30
+ }
@@ -7,6 +7,7 @@ const runStartCh = channel('ci:cucumber:run:start')
7
7
  const runFinishCh = channel('ci:cucumber:run:finish')
8
8
  const runStepStartCh = channel('ci:cucumber:run-step:start')
9
9
  const errorCh = channel('ci:cucumber:error')
10
+ const sessionFinishCh = channel('ci:cucumber:session:finish')
10
11
 
11
12
  // TODO: remove in a later major version
12
13
  const patched = new WeakSet()
@@ -128,4 +129,18 @@ addHook({
128
129
  file: 'lib/runtime/test_case_runner.js'
129
130
  }, testCaseHook)
130
131
 
132
+ addHook({
133
+ name: '@cucumber/cucumber',
134
+ versions: ['>=7.0.0'],
135
+ file: 'lib/runtime/index.js'
136
+ }, (Runtime) => {
137
+ shimmer.wrap(Runtime.default.prototype, 'start', start => async function () {
138
+ const result = await start.apply(this, arguments)
139
+ sessionFinishCh.publish(undefined)
140
+ return result
141
+ })
142
+
143
+ return Runtime
144
+ })
145
+
131
146
  module.exports = { pickleHook, testCaseHook }
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ const { addHook, channel } = require('./helpers/instrument')
4
+
5
+ const hookChannel = channel('apm:fs:hook')
6
+
7
+ // HACK: trigger old style plugin
8
+ addHook({ name: 'fs' }, fs => {
9
+ hookChannel.publish(fs)
10
+ return fs
11
+ })
@@ -0,0 +1,70 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ '@cucumber/cucumber': () => require('../cucumber'),
5
+ '@elastic/elasticsearch': () => require('../elasticsearch'),
6
+ '@elastic/transport': () => require('../elasticsearch'),
7
+ '@google-cloud/pubsub': () => require('../google-cloud-pubsub'),
8
+ '@grpc/grpc-js': () => require('../grpc'),
9
+ '@hapi/hapi': () => require('../hapi'),
10
+ '@koa/router': () => require('../koa'),
11
+ '@node-redis/client': () => require('../redis'),
12
+ 'amqp10': () => require('../amqp10'),
13
+ 'amqplib': () => require('../amqplib'),
14
+ 'aws-sdk': () => require('../aws-sdk'),
15
+ 'bluebird': () => require('../bluebird'),
16
+ 'bunyan': () => require('../bunyan'),
17
+ 'cassandra-driver': () => require('../cassandra-driver'),
18
+ 'connect': () => require('../connect'),
19
+ 'couchbase': () => require('../couchbase'),
20
+ 'crypto': () => require('../crypto'),
21
+ 'cypress': () => require('../cypress'),
22
+ 'dns': () => require('../dns'),
23
+ 'elasticsearch': () => require('../elasticsearch'),
24
+ 'express': () => require('../express'),
25
+ 'fastify': () => require('../fastify'),
26
+ 'find-my-way': () => require('../find-my-way'),
27
+ 'fs': () => require('../fs'),
28
+ 'graphql': () => require('../graphql'),
29
+ 'grpc': () => require('../grpc'),
30
+ 'hapi': () => require('../hapi'),
31
+ 'http': () => require('../http'),
32
+ 'http2': () => require('../http2'),
33
+ 'https': () => require('../http'),
34
+ 'ioredis': () => require('../ioredis'),
35
+ 'jest-environment-node': () => require('../jest'),
36
+ 'jest-environment-jsdom': () => require('../jest'),
37
+ 'jest-jasmine2': () => require('../jest'),
38
+ 'koa': () => require('../koa'),
39
+ 'koa-router': () => require('../koa'),
40
+ 'kafkajs': () => require('../kafkajs'),
41
+ 'limitd-client': () => require('../limitd-client'),
42
+ 'memcached': () => require('../memcached'),
43
+ 'microgateway-core': () => require('../microgateway-core'),
44
+ 'mocha': () => require('../mocha'),
45
+ 'mocha-each': () => require('../mocha'),
46
+ 'moleculer': () => require('../moleculer'),
47
+ 'mongodb': () => require('../mongodb-core'),
48
+ 'mongodb-core': () => require('../mongodb-core'),
49
+ 'mongoose': () => require('../mongoose'),
50
+ 'mysql': () => require('../mysql'),
51
+ 'mysql2': () => require('../mysql2'),
52
+ 'net': () => require('../net'),
53
+ 'next': () => require('../next'),
54
+ 'oracledb': () => require('../oracledb'),
55
+ 'paperplane': () => require('../paperplane'),
56
+ 'pg': () => require('../pg'),
57
+ 'pino': () => require('../pino'),
58
+ 'pino-pretty': () => require('../pino'),
59
+ 'promise-js': () => require('../promise-js'),
60
+ 'promise': () => require('../promise'),
61
+ 'q': () => require('../q'),
62
+ 'redis': () => require('../redis'),
63
+ 'restify': () => require('../restify'),
64
+ 'rhea': () => require('../rhea'),
65
+ 'router': () => require('../router'),
66
+ 'sharedb': () => require('../sharedb'),
67
+ 'tedious': () => require('../tedious'),
68
+ 'when': () => require('../when'),
69
+ 'winston': () => require('../winston')
70
+ }
@@ -1,16 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const dc = require('diagnostics_channel')
4
- const path = require('path')
5
4
  const semver = require('semver')
6
- const Hook = require('./hook')
7
- const requirePackageJson = require('../../../dd-trace/src/require-package-json')
5
+ const instrumentations = require('./instrumentations')
8
6
  const { AsyncResource } = require('async_hooks')
9
- const log = require('../../../dd-trace/src/log')
10
7
 
11
- const pathSepExpr = new RegExp(`\\${path.sep}`, 'g')
12
8
  const channelMap = {}
13
- exports.channel = function channel (name) {
9
+ exports.channel = function (name) {
14
10
  const maybe = channelMap[name]
15
11
  if (maybe) return maybe
16
12
  const ch = dc.channel(name)
@@ -19,36 +15,11 @@ exports.channel = function channel (name) {
19
15
  }
20
16
 
21
17
  exports.addHook = function addHook ({ name, versions, file }, hook) {
22
- const fullFilename = filename(name, file)
23
-
24
- Hook([name], (moduleExports, moduleName, moduleBaseDir) => {
25
- moduleName = moduleName.replace(pathSepExpr, '/')
26
-
27
- if (moduleName !== fullFilename || !matchVersion(getVersion(moduleBaseDir), versions)) {
28
- return moduleExports
29
- }
30
-
31
- try {
32
- return hook(moduleExports)
33
- } catch (e) {
34
- log.error(e)
35
- return moduleExports
36
- }
37
- })
38
- }
39
-
40
- function matchVersion (version, ranges) {
41
- return !version || (ranges && ranges.some(range => semver.satisfies(semver.coerce(version), range)))
42
- }
43
-
44
- function getVersion (moduleBaseDir) {
45
- if (moduleBaseDir) {
46
- return requirePackageJson(moduleBaseDir, module).version
18
+ if (!instrumentations[name]) {
19
+ instrumentations[name] = []
47
20
  }
48
- }
49
21
 
50
- function filename (name, file) {
51
- return [name, file].filter(val => val).join('/')
22
+ instrumentations[name].push({ name, versions, file, hook })
52
23
  }
53
24
 
54
25
  // AsyncResource.bind exists and binds `this` properly only from 17.8.0 and up.
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const sym = Symbol.for('_ddtrace_instrumentations')
4
+
5
+ global[sym] = global[sym] || {}
6
+
7
+ module.exports = global[sym]
@@ -0,0 +1,59 @@
1
+ 'use strict'
2
+
3
+ const { channel } = require('diagnostics_channel')
4
+ const path = require('path')
5
+ const semver = require('semver')
6
+ const Hook = require('./hook')
7
+ const requirePackageJson = require('../../../dd-trace/src/require-package-json')
8
+ const log = require('../../../dd-trace/src/log')
9
+
10
+ const hooks = require('./hooks')
11
+ const instrumentations = require('./instrumentations')
12
+ const names = Object.keys(hooks)
13
+ const pathSepExpr = new RegExp(`\\${path.sep}`, 'g')
14
+
15
+ const loadChannel = channel('dd-trace:instrumentation:load')
16
+
17
+ // TODO: make this more efficient
18
+
19
+ for (const packageName of names) {
20
+ Hook([packageName], (moduleExports, moduleName, moduleBaseDir) => {
21
+ moduleName = moduleName.replace(pathSepExpr, '/')
22
+
23
+ hooks[packageName]()
24
+
25
+ for (const { name, file, versions, hook } of instrumentations[packageName]) {
26
+ const fullFilename = filename(name, file)
27
+
28
+ if (moduleName === fullFilename) {
29
+ const version = getVersion(moduleBaseDir)
30
+
31
+ if (matchVersion(version, versions)) {
32
+ try {
33
+ loadChannel.publish({ name, version, file })
34
+
35
+ moduleExports = hook(moduleExports)
36
+ } catch (e) {
37
+ log.error(e)
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ return moduleExports
44
+ })
45
+ }
46
+
47
+ function matchVersion (version, ranges) {
48
+ return !version || (ranges && ranges.some(range => semver.satisfies(semver.coerce(version), range)))
49
+ }
50
+
51
+ function getVersion (moduleBaseDir) {
52
+ if (moduleBaseDir) {
53
+ return requirePackageJson(moduleBaseDir, module).version
54
+ }
55
+ }
56
+
57
+ function filename (name, file) {
58
+ return [name, file].filter(val => val).join('/')
59
+ }
@@ -29,7 +29,7 @@ function wrapResponseEmit (emit) {
29
29
  return emit.apply(this, arguments)
30
30
  }
31
31
 
32
- if (eventName === 'finish') {
32
+ if (eventName === 'close') {
33
33
  finishServerCh.publish({ req: this.req })
34
34
  }
35
35
 
@@ -1,5 +1,5 @@
1
1
  'use strict'
2
-
2
+ const istanbul = require('istanbul-lib-coverage')
3
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
 
@@ -7,7 +7,8 @@ const testStartCh = channel('ci:jest:test:start')
7
7
  const testSkippedCh = channel('ci:jest:test:skip')
8
8
  const testRunFinishCh = channel('ci:jest:test:finish')
9
9
  const testErrCh = channel('ci:jest:test:err')
10
- const testSuiteFinish = channel('ci:jest:test-suite:finish')
10
+
11
+ const testCodeCoverageCh = channel('ci:jest:test:code-coverage')
11
12
 
12
13
  const {
13
14
  getTestSuitePath,
@@ -16,6 +17,24 @@ const {
16
17
 
17
18
  const { getFormattedJestTestParameters, getJestTestName } = require('../../datadog-plugin-jest/src/util')
18
19
 
20
+ // This function also resets the coverage counters
21
+ function extractCoverageInformation (coverage, rootDir) {
22
+ const coverageMap = istanbul.createCoverageMap(coverage)
23
+
24
+ return coverageMap
25
+ .files()
26
+ .filter(filename => {
27
+ const fileCoverage = coverageMap.fileCoverageFor(filename)
28
+ const lineCoverage = fileCoverage.getLineCoverage()
29
+ const isAnyLineExecuted = Object.entries(lineCoverage).some(([, numExecutions]) => !!numExecutions)
30
+
31
+ fileCoverage.resetHits()
32
+
33
+ return isAnyLineExecuted
34
+ })
35
+ .map(filename => filename.replace(`${rootDir}/`, ''))
36
+ }
37
+
19
38
  const specStatusToTestStatus = {
20
39
  'pending': 'skip',
21
40
  'disabled': 'skip',
@@ -49,15 +68,11 @@ function getWrappedEnvironment (BaseEnvironment) {
49
68
  constructor (config, context) {
50
69
  super(config, context)
51
70
  const rootDir = config.globalConfig ? config.globalConfig.rootDir : config.rootDir
71
+ this.rootDir = rootDir
52
72
  this.testSuite = getTestSuitePath(context.testPath, rootDir)
53
73
  this.nameToParams = {}
54
74
  this.global._ddtrace = global._ddtrace
55
75
  }
56
- async teardown () {
57
- super.teardown().finally(() => {
58
- testSuiteFinish.publish()
59
- })
60
- }
61
76
 
62
77
  async handleTestEvent (event, state) {
63
78
  if (super.handleTestEvent) {
@@ -99,6 +114,10 @@ function getWrappedEnvironment (BaseEnvironment) {
99
114
  if (event.name === 'test_done') {
100
115
  const asyncResource = asyncResources.get(event.test)
101
116
  asyncResource.runInAsyncScope(() => {
117
+ if (this.global.__coverage__) {
118
+ const coverageFiles = extractCoverageInformation(this.global.__coverage__, this.rootDir)
119
+ testCodeCoverageCh.publish(coverageFiles)
120
+ }
102
121
  let status = 'pass'
103
122
  if (event.test.errors && event.test.errors.length) {
104
123
  status = 'fail'
@@ -111,10 +130,13 @@ function getWrappedEnvironment (BaseEnvironment) {
111
130
  })
112
131
  }
113
132
  if (event.name === 'test_skip' || event.name === 'test_todo') {
114
- testSkippedCh.publish({
115
- name: getJestTestName(event.test),
116
- suite: this.testSuite,
117
- runner: 'jest-circus'
133
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
134
+ asyncResource.runInAsyncScope(() => {
135
+ testSkippedCh.publish({
136
+ name: getJestTestName(event.test),
137
+ suite: this.testSuite,
138
+ runner: 'jest-circus'
139
+ })
118
140
  })
119
141
  }
120
142
  }
@@ -49,6 +49,19 @@ addHook({ name: 'net' }, net => {
49
49
  setupListeners(this, 'tcp', asyncResource)
50
50
  }
51
51
 
52
+ const emit = this.emit
53
+ this.emit = function (eventName) {
54
+ switch (eventName) {
55
+ case 'ready':
56
+ case 'connect':
57
+ return callbackResource.runInAsyncScope(() => {
58
+ return emit.apply(this, arguments)
59
+ })
60
+ default:
61
+ return emit.apply(this, arguments)
62
+ }
63
+ }
64
+
52
65
  try {
53
66
  return connect.apply(this, arguments)
54
67
  } catch (err) {
@@ -30,6 +30,10 @@ class CucumberPlugin extends Plugin {
30
30
  const sourceRoot = process.cwd()
31
31
  const codeOwnersEntries = getCodeOwnersFileEntries(sourceRoot)
32
32
 
33
+ this.addSub('ci:cucumber:session:finish', () => {
34
+ this.tracer._exporter._writer.flush()
35
+ })
36
+
33
37
  this.addSub('ci:cucumber:run:start', ({ pickleName, pickleUri }) => {
34
38
  const store = storage.getStore()
35
39
  const childOf = store ? store.span : store