dd-trace 2.4.2 → 2.6.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 (53) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ci/init.js +6 -0
  3. package/ci/jest/env.js +16 -3
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +17 -1
  7. package/package.json +5 -4
  8. package/packages/datadog-instrumentations/index.js +1 -0
  9. package/packages/datadog-instrumentations/src/cypress.js +8 -0
  10. package/packages/datadog-instrumentations/src/jest.js +170 -0
  11. package/packages/datadog-plugin-aws-sdk/src/helpers.js +4 -4
  12. package/packages/datadog-plugin-aws-sdk/src/index.js +1 -1
  13. package/packages/datadog-plugin-cucumber/src/index.js +16 -16
  14. package/packages/datadog-plugin-cypress/src/index.js +10 -5
  15. package/packages/datadog-plugin-cypress/src/plugin.js +18 -17
  16. package/packages/datadog-plugin-fs/src/index.js +2 -0
  17. package/packages/datadog-plugin-http/src/server.js +0 -8
  18. package/packages/datadog-plugin-jest/src/index.js +101 -3
  19. package/packages/datadog-plugin-jest/src/util.js +1 -29
  20. package/packages/datadog-plugin-mocha/src/index.js +14 -15
  21. package/packages/dd-trace/lib/version.js +1 -1
  22. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +29 -12
  23. package/packages/dd-trace/src/appsec/index.js +7 -3
  24. package/packages/dd-trace/src/appsec/recommended.json +15 -5
  25. package/packages/dd-trace/src/appsec/reporter.js +29 -3
  26. package/packages/dd-trace/src/appsec/rule_manager.js +2 -2
  27. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +32 -0
  28. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +51 -0
  29. package/packages/dd-trace/src/config.js +33 -4
  30. package/packages/dd-trace/src/encode/0.4.js +0 -1
  31. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +193 -0
  32. package/packages/dd-trace/src/encode/tags-processors.js +116 -0
  33. package/packages/dd-trace/src/exporter.js +3 -0
  34. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  35. package/packages/dd-trace/src/exporters/agent/writer.js +7 -32
  36. package/packages/dd-trace/src/exporters/{agent → common}/docker.js +0 -0
  37. package/packages/dd-trace/src/exporters/common/request.js +83 -0
  38. package/packages/dd-trace/src/exporters/common/writer.js +36 -0
  39. package/packages/dd-trace/src/exporters/{agent/scheduler.js → scheduler.js} +0 -0
  40. package/packages/dd-trace/src/format.js +9 -5
  41. package/packages/dd-trace/src/instrumenter.js +3 -0
  42. package/packages/dd-trace/src/pkg.js +11 -6
  43. package/packages/dd-trace/src/plugins/util/test.js +79 -1
  44. package/packages/dd-trace/src/plugins/util/web.js +11 -10
  45. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  46. package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -1
  47. package/packages/dd-trace/src/proxy.js +2 -0
  48. package/packages/dd-trace/src/span_processor.js +4 -1
  49. package/packages/dd-trace/src/telemetry.js +187 -0
  50. package/scripts/install_plugin_modules.js +1 -0
  51. package/packages/datadog-plugin-jest/src/jest-environment.js +0 -272
  52. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +0 -185
  53. package/packages/dd-trace/src/exporters/agent/request.js +0 -86
@@ -7,6 +7,7 @@ require,@types/node,MIT,Copyright Authors
7
7
  require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
8
8
  require,diagnostics_channel,MIT,Copyright 2021 Simon D.
9
9
  require,form-data,MIT,Copyright 2012 Felix Geisendörfer and contributors
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.
11
12
  require,koalas,MIT,Copyright 2013-2017 Brian Woodward
12
13
  require,limiter,MIT,Copyright 2011 John Hurliman
package/ci/init.js CHANGED
@@ -11,6 +11,12 @@ const options = {
11
11
  }
12
12
  }
13
13
 
14
+ if (process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED && (process.env.DATADOG_API_KEY || process.env.DD_API_KEY)) {
15
+ options.experimental = {
16
+ exporter: 'datadog'
17
+ }
18
+ }
19
+
14
20
  // TODO: remove this in a later major version since we now recommend using
15
21
  // `NODE_OPTIONS='-r dd-trace/ci/init'`.
16
22
  try {
package/ci/jest/env.js CHANGED
@@ -1,13 +1,26 @@
1
1
  const tracer = require('../../packages/dd-trace')
2
2
  const { ORIGIN_KEY } = require('../../packages/dd-trace/src/constants')
3
3
 
4
- tracer.init({
4
+ const options = {
5
5
  startupLogs: false,
6
- flushInterval: 400000,
7
6
  tags: {
8
7
  [ORIGIN_KEY]: 'ciapp-test'
9
8
  }
10
- })
9
+ }
10
+
11
+ if (process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED && (process.env.DATADOG_API_KEY || process.env.DD_API_KEY)) {
12
+ tracer.init({
13
+ ...options,
14
+ experimental: {
15
+ exporter: 'datadog'
16
+ }
17
+ })
18
+ } else {
19
+ tracer.init({
20
+ ...options,
21
+ flushInterval: 400000
22
+ })
23
+ }
11
24
 
12
25
  tracer.use('fs', false)
13
26
 
@@ -1,6 +1,7 @@
1
1
  declare const exporters: {
2
2
  LOG: 'log',
3
- AGENT: 'agent'
3
+ AGENT: 'agent',
4
+ DATADOG: 'datadog'
4
5
  }
5
6
 
6
7
  export = exporters
package/ext/exporters.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
  module.exports = {
3
3
  LOG: 'log',
4
- AGENT: 'agent'
4
+ AGENT: 'agent',
5
+ DATADOG: 'datadog'
5
6
  }
package/index.d.ts CHANGED
@@ -428,7 +428,23 @@ export declare interface TracerOptions {
428
428
  * Controls the maximum amount of traces sampled by AppSec attacks, per second.
429
429
  * @default 100
430
430
  */
431
- rateLimit?: number
431
+ rateLimit?: number,
432
+
433
+ /**
434
+ * Controls the maximum amount of time in microseconds the WAF is allowed to run synchronously for.
435
+ * @default 5000
436
+ */
437
+ wafTimeout?: number,
438
+
439
+ /**
440
+ * Specifies a regex that will redact sensitive data by its key in attack reports.
441
+ */
442
+ obfuscatorKeyRegex?: string,
443
+
444
+ /**
445
+ * Specifies a regex that will redact sensitive data by its value in attack reports.
446
+ */
447
+ obfuscatorValueRegex?: string
432
448
  };
433
449
  }
434
450
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.4.2",
3
+ "version": "2.6.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -61,14 +61,15 @@
61
61
  "node": ">=12"
62
62
  },
63
63
  "dependencies": {
64
- "@datadog/native-appsec": "^1.0.0",
65
- "@datadog/native-metrics": "^1.1.0",
66
- "@datadog/pprof": "^0.3.0",
64
+ "@datadog/native-appsec": "^1.1.1",
65
+ "@datadog/native-metrics": "^1.2.0",
66
+ "@datadog/pprof": "^0.4.0",
67
67
  "@datadog/sketches-js": "^1.0.4",
68
68
  "@types/node": ">=12",
69
69
  "crypto-randomuuid": "^1.0.0",
70
70
  "diagnostics_channel": "^1.1.0",
71
71
  "form-data": "^3.0.0",
72
+ "ignore": "^5.2.0",
72
73
  "import-in-the-middle": "^1.2.1",
73
74
  "koalas": "^1.0.2",
74
75
  "limiter": "^1.1.4",
@@ -12,6 +12,7 @@ require('./src/elasticsearch')
12
12
  require('./src/generic-pool')
13
13
  require('./src/http')
14
14
  require('./src/ioredis')
15
+ require('./src/jest')
15
16
  require('./src/memcached')
16
17
  require('./src/mongodb-core')
17
18
  require('./src/mongoose')
@@ -0,0 +1,8 @@
1
+ const { addHook } = require('./helpers/instrument')
2
+
3
+ // No handler because this is only useful for testing.
4
+ // Cypress plugin does not patch any library.
5
+ addHook({
6
+ name: 'cypress',
7
+ versions: ['>=6.7.0']
8
+ })
@@ -0,0 +1,170 @@
1
+ 'use strict'
2
+
3
+ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+
6
+ const testStartCh = channel('ci:jest:test:start')
7
+ const testSkippedCh = channel('ci:jest:test:skip')
8
+ const testRunEndCh = channel('ci:jest:test:end')
9
+ const testErrCh = channel('ci:jest:test:err')
10
+ const testSuiteEnd = channel('ci:jest:test-suite:end')
11
+
12
+ const {
13
+ getTestSuitePath,
14
+ getTestParametersString
15
+ } = require('../../dd-trace/src/plugins/util/test')
16
+
17
+ const { getFormattedJestTestParameters } = require('../../datadog-plugin-jest/src/util')
18
+
19
+ const specStatusToTestStatus = {
20
+ 'pending': 'skip',
21
+ 'disabled': 'skip',
22
+ 'todo': 'skip',
23
+ 'passed': 'pass',
24
+ 'failed': 'fail'
25
+ }
26
+
27
+ const asyncResources = new WeakMap()
28
+ const originalTestFns = new WeakMap()
29
+
30
+ // based on https://github.com/facebook/jest/blob/main/packages/jest-circus/src/formatNodeAssertErrors.ts#L41
31
+ function formatJestError (errors) {
32
+ let error
33
+ if (Array.isArray(errors)) {
34
+ const [originalError, asyncError] = errors
35
+ if (originalError === null || !originalError.stack) {
36
+ error = asyncError
37
+ error.message = originalError
38
+ } else {
39
+ error = originalError
40
+ }
41
+ } else {
42
+ error = errors
43
+ }
44
+ return error
45
+ }
46
+
47
+ function getWrappedEnvironment (BaseEnvironment) {
48
+ return class DatadogEnvironment extends BaseEnvironment {
49
+ constructor (config, context) {
50
+ super(config, context)
51
+ this.testSuite = getTestSuitePath(context.testPath, config.rootDir)
52
+ this.nameToParams = {}
53
+ this.global._ddtrace = global._ddtrace
54
+ }
55
+ async teardown () {
56
+ super.teardown().finally(() => {
57
+ testSuiteEnd.publish()
58
+ })
59
+ }
60
+
61
+ async handleTestEvent (event, state) {
62
+ if (super.handleTestEvent) {
63
+ await super.handleTestEvent(event, state)
64
+ }
65
+
66
+ let context
67
+ if (this.getVmContext) {
68
+ context = this.getVmContext()
69
+ } else {
70
+ context = this.context
71
+ }
72
+
73
+ const setNameToParams = (name, params) => { this.nameToParams[name] = params }
74
+
75
+ if (event.name === 'setup') {
76
+ shimmer.wrap(this.global.test, 'each', each => function () {
77
+ const testParameters = getFormattedJestTestParameters(arguments)
78
+ const eachBind = each.apply(this, arguments)
79
+ return function () {
80
+ const [testName] = arguments
81
+ setNameToParams(testName, testParameters)
82
+ return eachBind.apply(this, arguments)
83
+ }
84
+ })
85
+ }
86
+ if (event.name === 'test_start') {
87
+ const testParameters = getTestParametersString(this.nameToParams, event.test.name)
88
+
89
+ // Async resource for this test is created here
90
+ // It is used later on by the test_done handler
91
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
92
+ asyncResources.set(event.test, asyncResource)
93
+ asyncResource.runInAsyncScope(() => {
94
+ testStartCh.publish({
95
+ name: context.expect.getState().currentTestName,
96
+ suite: this.testSuite,
97
+ runner: 'jest-circus',
98
+ testParameters
99
+ })
100
+ originalTestFns.set(event.test, event.test.fn)
101
+ event.test.fn = asyncResource.bind(event.test.fn)
102
+ })
103
+ }
104
+ if (event.name === 'test_done') {
105
+ const asyncResource = asyncResources.get(event.test)
106
+ asyncResource.runInAsyncScope(() => {
107
+ let status = 'pass'
108
+ if (event.test.errors && event.test.errors.length) {
109
+ status = 'fail'
110
+ const formattedError = formatJestError(event.test.errors[0])
111
+ testErrCh.publish(formattedError)
112
+ }
113
+ testRunEndCh.publish(status)
114
+ // restore in case it is retried
115
+ event.test.fn = originalTestFns.get(event.test)
116
+ })
117
+ }
118
+ if (event.name === 'test_skip' || event.name === 'test_todo') {
119
+ testSkippedCh.publish({
120
+ name: context.expect.getState().currentTestName,
121
+ suite: this.testSuite,
122
+ runner: 'jest-circus'
123
+ })
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ addHook({
130
+ name: 'jest-environment-node',
131
+ versions: ['>=24.8.0']
132
+ }, getWrappedEnvironment)
133
+
134
+ addHook({
135
+ name: 'jest-environment-jsdom',
136
+ versions: ['>=24.8.0']
137
+ }, getWrappedEnvironment)
138
+
139
+ addHook({
140
+ name: 'jest-jasmine2',
141
+ versions: ['>=24.8.0'],
142
+ file: 'build/jasmineAsyncInstall.js'
143
+ }, (jasmineAsyncInstallExport) => {
144
+ return function (globalConfig, globalInput) {
145
+ globalInput._ddtrace = global._ddtrace
146
+ shimmer.wrap(globalInput.jasmine.Spec.prototype, 'execute', execute => function (onComplete) {
147
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
148
+ asyncResource.runInAsyncScope(() => {
149
+ const testSuite = getTestSuitePath(this.result.testPath, globalConfig.rootDir)
150
+ testStartCh.publish({
151
+ name: this.getFullName(),
152
+ suite: testSuite,
153
+ runner: 'jest-jasmine2'
154
+ })
155
+ const spec = this
156
+ const callback = asyncResource.bind(function () {
157
+ if (spec.result.failedExpectations && spec.result.failedExpectations.length) {
158
+ const formattedError = formatJestError(spec.result.failedExpectations[0].error)
159
+ testErrCh.publish(formattedError)
160
+ }
161
+ testRunEndCh.publish(specStatusToTestStatus[spec.result.status])
162
+ onComplete.apply(this, arguments)
163
+ })
164
+ arguments[0] = callback
165
+ execute.apply(this, arguments)
166
+ })
167
+ })
168
+ return jasmineAsyncInstallExport.default(globalConfig, globalInput)
169
+ }
170
+ })
@@ -19,7 +19,7 @@ function getService (Service) {
19
19
  }
20
20
 
21
21
  const helpers = {
22
- finish (span, err) {
22
+ finish (config, span, response, err) {
23
23
  if (err) {
24
24
  span.setTag('error', err)
25
25
 
@@ -28,6 +28,8 @@ const helpers = {
28
28
  }
29
29
  }
30
30
 
31
+ config.hooks.request(span, response)
32
+
31
33
  span.finish()
32
34
  },
33
35
 
@@ -43,14 +45,12 @@ const helpers = {
43
45
  : true
44
46
  },
45
47
 
46
- addResponseTags (span, response, serviceName, config) {
48
+ addResponseTags (span, response, serviceName) {
47
49
  if (!span) return
48
50
 
49
51
  if (response.request) {
50
52
  this.addServicesTags(span, response, serviceName)
51
53
  }
52
-
53
- config.hooks.request(span, response)
54
54
  },
55
55
 
56
56
  addServicesTags (span, response, serviceName) {
@@ -36,7 +36,7 @@ function createWrapRequest (tracer, config) {
36
36
  if (!span) return
37
37
 
38
38
  awsHelpers.addResponseTags(span, response, serviceIdentifier, config, tracer)
39
- awsHelpers.finish(span, response.error)
39
+ awsHelpers.finish(config, span, response, response.error)
40
40
  })
41
41
 
42
42
  analyticsSampler.sample(span, config.measured)
@@ -5,20 +5,18 @@ const { storage } = require('../../datadog-core')
5
5
 
6
6
  const {
7
7
  CI_APP_ORIGIN,
8
- TEST_TYPE,
9
- TEST_NAME,
10
- TEST_SUITE,
11
8
  TEST_SKIP_REASON,
12
- TEST_FRAMEWORK_VERSION,
13
9
  ERROR_MESSAGE,
14
10
  TEST_STATUS,
11
+ TEST_CODE_OWNERS,
15
12
  finishAllTraceSpans,
16
13
  getTestEnvironmentMetadata,
17
- getTestSuitePath
14
+ getTestSuitePath,
15
+ getCodeOwnersFileEntries,
16
+ getCodeOwnersForFilename,
17
+ getTestCommonTags
18
18
  } = require('../../dd-trace/src/plugins/util/test')
19
- const { SPAN_TYPE, RESOURCE_NAME, SAMPLING_PRIORITY } = require('../../../ext/tags')
20
- const { SAMPLING_RULE_DECISION } = require('../../dd-trace/src/constants')
21
- const { AUTO_KEEP } = require('../../../ext/priority')
19
+ const { RESOURCE_NAME } = require('../../../ext/tags')
22
20
 
23
21
  class CucumberPlugin extends Plugin {
24
22
  static get name () {
@@ -30,26 +28,28 @@ class CucumberPlugin extends Plugin {
30
28
 
31
29
  const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber', this.config)
32
30
  const sourceRoot = process.cwd()
31
+ const codeOwnersEntries = getCodeOwnersFileEntries(sourceRoot)
33
32
 
34
33
  this.addSub('ci:cucumber:run:start', ({ pickleName, pickleUri }) => {
35
34
  const store = storage.getStore()
36
35
  const childOf = store ? store.span : store
37
36
  const testSuite = getTestSuitePath(pickleUri, sourceRoot)
38
37
 
38
+ const commonTags = getTestCommonTags(pickleName, testSuite, this.tracer._version)
39
+
40
+ const codeOwners = getCodeOwnersForFilename(testSuite, codeOwnersEntries)
41
+ if (codeOwners) {
42
+ commonTags[TEST_CODE_OWNERS] = codeOwners
43
+ }
44
+
39
45
  const span = this.tracer.startSpan('cucumber.test', {
40
46
  childOf,
41
47
  tags: {
42
- [SPAN_TYPE]: 'test',
43
- [RESOURCE_NAME]: pickleName,
44
- [TEST_TYPE]: 'test',
45
- [TEST_NAME]: pickleName,
46
- [TEST_SUITE]: testSuite,
47
- [SAMPLING_RULE_DECISION]: 1,
48
- [SAMPLING_PRIORITY]: AUTO_KEEP,
49
- [TEST_FRAMEWORK_VERSION]: this.tracer._version,
48
+ ...commonTags,
50
49
  ...testEnvironmentMetadata
51
50
  }
52
51
  })
52
+
53
53
  span.context()._trace.origin = CI_APP_ORIGIN
54
54
  this.enter(span, store)
55
55
  })
@@ -1,6 +1,11 @@
1
- module.exports = [
2
- {
3
- name: 'cypress',
4
- versions: ['>=6.7.0']
1
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
2
+
3
+ // Cypress plugin does not patch any library. This is just a placeholder to
4
+ // follow the structure of the plugins
5
+ class CypressPlugin extends Plugin {
6
+ static get name () {
7
+ return 'cypress'
5
8
  }
6
- ]
9
+ }
10
+
11
+ module.exports = CypressPlugin
@@ -1,18 +1,16 @@
1
1
  const {
2
- TEST_TYPE,
3
- TEST_NAME,
4
- TEST_SUITE,
5
2
  TEST_STATUS,
6
- TEST_FRAMEWORK_VERSION,
7
3
  TEST_IS_RUM_ACTIVE,
4
+ TEST_CODE_OWNERS,
8
5
  getTestEnvironmentMetadata,
9
6
  CI_APP_ORIGIN,
10
- getTestParentSpan
7
+ getTestParentSpan,
8
+ getCodeOwnersFileEntries,
9
+ getCodeOwnersForFilename,
10
+ getTestCommonTags
11
11
  } = require('../../dd-trace/src/plugins/util/test')
12
12
 
13
- const { SAMPLING_RULE_DECISION, ORIGIN_KEY } = require('../../dd-trace/src/constants')
14
- const { SAMPLING_PRIORITY, SPAN_TYPE, RESOURCE_NAME } = require('../../../ext/tags')
15
- const { AUTO_KEEP } = require('../../../ext/priority')
13
+ const { ORIGIN_KEY } = require('../../dd-trace/src/constants')
16
14
 
17
15
  const CYPRESS_STATUS_TO_TEST_STATUS = {
18
16
  passed: 'pass',
@@ -24,21 +22,20 @@ const CYPRESS_STATUS_TO_TEST_STATUS = {
24
22
  function getTestSpanMetadata (tracer, testName, testSuite, cypressConfig) {
25
23
  const childOf = getTestParentSpan(tracer)
26
24
 
25
+ const commonTags = getTestCommonTags(testName, testSuite, cypressConfig.version)
26
+
27
27
  return {
28
28
  childOf,
29
- resource: `${testSuite}.${testName}`,
30
- [TEST_TYPE]: 'test',
31
- [TEST_NAME]: testName,
32
- [TEST_SUITE]: testSuite,
33
- [SAMPLING_RULE_DECISION]: 1,
34
- [SAMPLING_PRIORITY]: AUTO_KEEP,
35
- [TEST_FRAMEWORK_VERSION]: cypressConfig.version
29
+ ...commonTags
36
30
  }
37
31
  }
38
32
 
39
33
  module.exports = (on, config) => {
40
34
  const tracer = require('../../dd-trace')
41
35
  const testEnvironmentMetadata = getTestEnvironmentMetadata('cypress')
36
+
37
+ const codeOwnersEntries = getCodeOwnersFileEntries()
38
+
42
39
  let activeSpan = null
43
40
  on('after:run', () => {
44
41
  return new Promise(resolve => {
@@ -55,12 +52,16 @@ module.exports = (on, config) => {
55
52
  ...testSpanMetadata
56
53
  } = getTestSpanMetadata(tracer, testName, testSuite, config)
57
54
 
55
+ const codeOwners = getCodeOwnersForFilename(testSuite, codeOwnersEntries)
56
+
57
+ if (codeOwners) {
58
+ testSpanMetadata[TEST_CODE_OWNERS] = codeOwners
59
+ }
60
+
58
61
  if (!activeSpan) {
59
62
  activeSpan = tracer.startSpan('cypress.test', {
60
63
  childOf,
61
64
  tags: {
62
- [SPAN_TYPE]: 'test',
63
- [RESOURCE_NAME]: resource,
64
65
  [ORIGIN_KEY]: CI_APP_ORIGIN,
65
66
  ...testSpanMetadata,
66
67
  ...testEnvironmentMetadata
@@ -60,6 +60,7 @@ function createWrapCreateReadStream (config, tracer) {
60
60
  const tags = makeFSFlagTags('ReadStream', path, options, 'r', config, tracer)
61
61
  return tracer.trace('fs.operation', { tags, orphanable }, (span, done) => {
62
62
  const stream = createReadStream.apply(this, arguments)
63
+ stream.once('close', done)
63
64
  stream.once('end', done)
64
65
  stream.once('error', done)
65
66
  return stream
@@ -74,6 +75,7 @@ function createWrapCreateWriteStream (config, tracer) {
74
75
  const tags = makeFSFlagTags('WriteStream', path, options, 'w', config, tracer)
75
76
  return tracer.trace('fs.operation', { tags, orphanable }, (span, done) => {
76
77
  const stream = createWriteStream.apply(this, arguments)
78
+ stream.once('close', done)
77
79
  stream.once('finish', done)
78
80
  stream.once('error', done)
79
81
  return stream
@@ -4,9 +4,6 @@ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
4
  const { storage } = require('../../datadog-core')
5
5
  const web = require('../../dd-trace/src/plugins/util/web')
6
6
  const { incomingHttpRequestStart } = require('../../dd-trace/src/appsec/gateway/channels')
7
- const tags = require('../../../ext/tags')
8
- const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
9
- const SERVICE_NAME = tags.SERVICE_NAME
10
7
 
11
8
  class HttpServerPlugin extends Plugin {
12
9
  static get name () {
@@ -20,11 +17,6 @@ class HttpServerPlugin extends Plugin {
20
17
  const store = storage.getStore()
21
18
  const span = web.startSpan(this.tracer, this.config, req, res, 'http.request')
22
19
 
23
- if (this.config.service) {
24
- span.setTag(SERVICE_NAME, this.config.service)
25
- }
26
-
27
- analyticsSampler.sample(span, this.config.measured, true)
28
20
  this.enter(span, store)
29
21
 
30
22
  const context = web.getContext(req)
@@ -1,4 +1,102 @@
1
- const jestEnvironment = require('./jest-environment')
2
- const jestJasmine2 = require('./jest-jasmine2')
1
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
2
+ const { storage } = require('../../datadog-core')
3
3
 
4
- module.exports = [].concat(jestEnvironment, jestJasmine2)
4
+ const {
5
+ CI_APP_ORIGIN,
6
+ TEST_STATUS,
7
+ JEST_TEST_RUNNER,
8
+ finishAllTraceSpans,
9
+ getTestEnvironmentMetadata,
10
+ getTestParentSpan,
11
+ getTestCommonTags,
12
+ TEST_PARAMETERS,
13
+ getCodeOwnersFileEntries,
14
+ getCodeOwnersForFilename,
15
+ TEST_CODE_OWNERS
16
+ } = require('../../dd-trace/src/plugins/util/test')
17
+
18
+ function getTestSpanMetadata (tracer, test) {
19
+ const childOf = getTestParentSpan(tracer)
20
+
21
+ const { suite, name, runner, testParameters } = test
22
+
23
+ const commonTags = getTestCommonTags(name, suite, tracer._version)
24
+
25
+ return {
26
+ childOf,
27
+ ...commonTags,
28
+ [JEST_TEST_RUNNER]: runner,
29
+ [TEST_PARAMETERS]: testParameters
30
+ }
31
+ }
32
+
33
+ class JestPlugin extends Plugin {
34
+ static get name () {
35
+ return 'jest'
36
+ }
37
+
38
+ constructor (...args) {
39
+ super(...args)
40
+
41
+ this.testEnvironmentMetadata = getTestEnvironmentMetadata('jest', this.config)
42
+ this.codeOwnersEntries = getCodeOwnersFileEntries()
43
+
44
+ this.addSub('ci:jest:test:start', (test) => {
45
+ const store = storage.getStore()
46
+ const span = this.startTestSpan(test)
47
+
48
+ this.enter(span, store)
49
+ })
50
+
51
+ this.addSub('ci:jest:test:end', (status) => {
52
+ const span = storage.getStore().span
53
+ span.setTag(TEST_STATUS, status)
54
+ span.finish()
55
+ finishAllTraceSpans(span)
56
+ this.exit()
57
+ })
58
+
59
+ this.addSub('ci:jest:test-suite:end', () => {
60
+ this.tracer._exporter._writer.flush()
61
+ })
62
+
63
+ this.addSub('ci:jest:test:err', (error) => {
64
+ if (error) {
65
+ const span = storage.getStore().span
66
+ span.setTag(TEST_STATUS, 'fail')
67
+ span.setTag('error', error)
68
+ }
69
+ })
70
+
71
+ this.addSub('ci:jest:test:skip', (test) => {
72
+ const span = this.startTestSpan(test)
73
+ span.setTag(TEST_STATUS, 'skip')
74
+ span.finish()
75
+ })
76
+ }
77
+
78
+ startTestSpan (test) {
79
+ const { childOf, ...testSpanMetadata } = getTestSpanMetadata(this.tracer, test)
80
+
81
+ const codeOwners = getCodeOwnersForFilename(test.suite, this.codeOwnersEntries)
82
+
83
+ if (codeOwners) {
84
+ testSpanMetadata[TEST_CODE_OWNERS] = codeOwners
85
+ }
86
+
87
+ const testSpan = this.tracer
88
+ .startSpan('jest.test', {
89
+ childOf,
90
+ tags: {
91
+ ...this.testEnvironmentMetadata,
92
+ ...testSpanMetadata
93
+ }
94
+ })
95
+
96
+ testSpan.context()._trace.origin = CI_APP_ORIGIN
97
+
98
+ return testSpan
99
+ }
100
+ }
101
+
102
+ module.exports = JestPlugin