dd-trace 3.20.0 → 3.22.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 (122) hide show
  1. package/index.d.ts +8 -1
  2. package/package.json +6 -5
  3. package/packages/datadog-instrumentations/src/cucumber.js +13 -0
  4. package/packages/datadog-instrumentations/src/grpc/client.js +9 -5
  5. package/packages/datadog-instrumentations/src/grpc/server.js +8 -4
  6. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  7. package/packages/datadog-instrumentations/src/helpers/register.js +4 -0
  8. package/packages/datadog-instrumentations/src/http/client.js +2 -1
  9. package/packages/datadog-instrumentations/src/http/server.js +14 -0
  10. package/packages/datadog-instrumentations/src/http2/client.js +4 -0
  11. package/packages/datadog-instrumentations/src/jest.js +20 -17
  12. package/packages/datadog-instrumentations/src/next.js +6 -1
  13. package/packages/datadog-instrumentations/src/playwright.js +1 -1
  14. package/packages/datadog-instrumentations/src/sequelize.js +51 -0
  15. package/packages/datadog-plugin-amqp10/src/consumer.js +1 -3
  16. package/packages/datadog-plugin-amqp10/src/producer.js +1 -3
  17. package/packages/datadog-plugin-amqplib/src/client.js +4 -3
  18. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -3
  19. package/packages/datadog-plugin-amqplib/src/producer.js +1 -3
  20. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -0
  21. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +2 -1
  22. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +4 -2
  23. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +4 -3
  24. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -1
  25. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -0
  26. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +2 -1
  27. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +2 -1
  28. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +8 -1
  29. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +7 -1
  30. package/packages/datadog-plugin-cucumber/src/index.js +2 -2
  31. package/packages/datadog-plugin-cypress/src/plugin.js +150 -30
  32. package/packages/datadog-plugin-cypress/src/support.js +6 -3
  33. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -3
  34. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -3
  35. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -3
  36. package/packages/datadog-plugin-http/src/client.js +70 -67
  37. package/packages/datadog-plugin-http2/src/client.js +50 -46
  38. package/packages/datadog-plugin-jest/src/index.js +5 -4
  39. package/packages/datadog-plugin-jest/src/util.js +10 -1
  40. package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -4
  41. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -3
  42. package/packages/datadog-plugin-memcached/src/index.js +2 -3
  43. package/packages/datadog-plugin-mocha/src/index.js +4 -2
  44. package/packages/datadog-plugin-pg/src/index.js +1 -1
  45. package/packages/datadog-plugin-redis/src/index.js +2 -13
  46. package/packages/datadog-plugin-rhea/src/consumer.js +1 -3
  47. package/packages/datadog-plugin-rhea/src/producer.js +1 -5
  48. package/packages/dd-trace/src/appsec/blocked_templates.js +2 -101
  49. package/packages/dd-trace/src/appsec/blocking.js +60 -11
  50. package/packages/dd-trace/src/appsec/channels.js +3 -2
  51. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +7 -5
  52. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +2 -1
  53. package/packages/dd-trace/src/appsec/iast/analyzers/index.js +3 -0
  54. package/packages/dd-trace/src/appsec/iast/analyzers/insecure-cookie-analyzer.js +31 -0
  55. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +2 -1
  56. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +26 -5
  57. package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +47 -0
  58. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +65 -4
  59. package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +26 -0
  60. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +35 -3
  61. package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +2 -1
  62. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -1
  63. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  64. package/packages/dd-trace/src/appsec/iast/path-line.js +16 -8
  65. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +19 -4
  66. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/range-utils.js +37 -0
  67. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +29 -0
  68. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +35 -0
  69. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +118 -0
  70. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +49 -0
  71. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +146 -0
  72. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +113 -0
  73. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +10 -0
  74. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -109
  75. package/packages/dd-trace/src/appsec/recommended.json +45 -46
  76. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +3 -1
  77. package/packages/dd-trace/src/appsec/remote_config/index.js +4 -0
  78. package/packages/dd-trace/src/appsec/rule_manager.js +49 -6
  79. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -7
  80. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -1
  81. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -6
  82. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +10 -4
  83. package/packages/dd-trace/src/config.js +86 -9
  84. package/packages/dd-trace/src/constants.js +3 -1
  85. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +11 -3
  86. package/packages/dd-trace/src/exporters/common/util.js +9 -0
  87. package/packages/dd-trace/src/exporters/common/writer.js +3 -2
  88. package/packages/dd-trace/src/git_metadata_tagger.js +17 -0
  89. package/packages/dd-trace/src/git_properties.js +32 -0
  90. package/packages/dd-trace/src/plugin_manager.js +2 -0
  91. package/packages/dd-trace/src/plugins/cache.js +7 -0
  92. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -0
  93. package/packages/dd-trace/src/plugins/client.js +3 -2
  94. package/packages/dd-trace/src/plugins/consumer.js +14 -2
  95. package/packages/dd-trace/src/plugins/database.js +2 -2
  96. package/packages/dd-trace/src/plugins/inbound.js +7 -0
  97. package/packages/dd-trace/src/plugins/{outgoing.js → outbound.js} +2 -2
  98. package/packages/dd-trace/src/plugins/producer.js +19 -2
  99. package/packages/dd-trace/src/plugins/server.js +2 -2
  100. package/packages/dd-trace/src/plugins/storage.js +2 -0
  101. package/packages/dd-trace/src/plugins/tracing.js +11 -0
  102. package/packages/dd-trace/src/plugins/util/ci.js +63 -8
  103. package/packages/dd-trace/src/plugins/util/tags.js +5 -1
  104. package/packages/dd-trace/src/profiling/config.js +4 -2
  105. package/packages/dd-trace/src/profiling/constants.js +0 -1
  106. package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
  107. package/packages/dd-trace/src/proxy.js +4 -0
  108. package/packages/dd-trace/src/serverless.js +25 -0
  109. package/packages/dd-trace/src/service-naming/index.js +30 -0
  110. package/packages/dd-trace/src/service-naming/schemas/definition.js +24 -0
  111. package/packages/dd-trace/src/service-naming/schemas/index.js +6 -0
  112. package/packages/dd-trace/src/service-naming/schemas/util.js +5 -0
  113. package/packages/dd-trace/src/service-naming/schemas/v0/index.js +5 -0
  114. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +64 -0
  115. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +33 -0
  116. package/packages/dd-trace/src/service-naming/schemas/v1/index.js +5 -0
  117. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +52 -0
  118. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +21 -0
  119. package/packages/dd-trace/src/span_processor.js +3 -0
  120. package/packages/dd-trace/src/tracer.js +3 -2
  121. package/version.js +9 -0
  122. package/packages/dd-trace/src/plugins/incoming.js +0 -7
@@ -17,13 +17,16 @@ const {
17
17
  TEST_COMMAND,
18
18
  TEST_MODULE,
19
19
  TEST_SOURCE_START,
20
- finishAllTraceSpans
20
+ finishAllTraceSpans,
21
+ getCoveredFilenamesFromCoverage,
22
+ getTestSuitePath,
23
+ addIntelligentTestRunnerSpanTags
21
24
  } = require('../../dd-trace/src/plugins/util/test')
25
+ const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
26
+ const log = require('../../dd-trace/src/log')
22
27
 
23
28
  const TEST_FRAMEWORK_NAME = 'cypress'
24
29
 
25
- const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
26
-
27
30
  const CYPRESS_STATUS_TO_TEST_STATUS = {
28
31
  passed: 'pass',
29
32
  failed: 'fail',
@@ -52,6 +55,13 @@ function getCypressVersion (details) {
52
55
  return ''
53
56
  }
54
57
 
58
+ function getRootDir (details) {
59
+ if (details && details.config) {
60
+ return details.config.projectRoot || details.config.repoRoot || process.cwd()
61
+ }
62
+ return process.cwd()
63
+ }
64
+
55
65
  function getCypressCommand (details) {
56
66
  if (!details) {
57
67
  return TEST_FRAMEWORK_NAME
@@ -79,10 +89,62 @@ function getSuiteStatus (suiteStats) {
79
89
  return 'pass'
80
90
  }
81
91
 
92
+ function getItrConfig (tracer, testConfiguration) {
93
+ return new Promise(resolve => {
94
+ if (!tracer._tracer._exporter || !tracer._tracer._exporter.getItrConfiguration) {
95
+ return resolve({ err: new Error('CI Visibility was not initialized correctly') })
96
+ }
97
+
98
+ tracer._tracer._exporter.getItrConfiguration(testConfiguration, (err, itrConfig) => {
99
+ resolve({ err, itrConfig })
100
+ })
101
+ })
102
+ }
103
+
104
+ function getSkippableTests (isSuitesSkippingEnabled, tracer, testConfiguration) {
105
+ if (!isSuitesSkippingEnabled) {
106
+ return Promise.resolve({ skippableTests: [] })
107
+ }
108
+ return new Promise(resolve => {
109
+ if (!tracer._tracer._exporter || !tracer._tracer._exporter.getItrConfiguration) {
110
+ return resolve({ err: new Error('CI Visibility was not initialized correctly') })
111
+ }
112
+ tracer._tracer._exporter.getSkippableSuites(testConfiguration, (err, skippableTests) => {
113
+ resolve({
114
+ err,
115
+ skippableTests
116
+ })
117
+ })
118
+ })
119
+ }
120
+
82
121
  module.exports = (on, config) => {
83
122
  const tracer = require('../../dd-trace')
84
123
  const testEnvironmentMetadata = getTestEnvironmentMetadata(TEST_FRAMEWORK_NAME)
85
124
 
125
+ const {
126
+ 'git.repository_url': repositoryUrl,
127
+ 'git.commit.sha': sha,
128
+ 'os.version': osVersion,
129
+ 'os.platform': osPlatform,
130
+ 'os.architecture': osArchitecture,
131
+ 'runtime.name': runtimeName,
132
+ 'runtime.version': runtimeVersion,
133
+ 'git.branch': branch
134
+ } = testEnvironmentMetadata
135
+
136
+ const testConfiguration = {
137
+ repositoryUrl,
138
+ sha,
139
+ osVersion,
140
+ osPlatform,
141
+ osArchitecture,
142
+ runtimeName,
143
+ runtimeVersion,
144
+ branch,
145
+ testLevel: 'test'
146
+ }
147
+
86
148
  const codeOwnersEntries = getCodeOwnersFileEntries()
87
149
 
88
150
  let activeSpan = null
@@ -91,31 +153,54 @@ module.exports = (on, config) => {
91
153
  let testSuiteSpan = null
92
154
  let command = null
93
155
  let frameworkVersion
156
+ let rootDir
157
+ let isSuitesSkippingEnabled = false
158
+ let isCodeCoverageEnabled = false
159
+ let testsToSkip = []
94
160
 
95
161
  on('before:run', (details) => {
96
- const childOf = getTestParentSpan(tracer)
162
+ return getItrConfig(tracer, testConfiguration).then(({ err, itrConfig }) => {
163
+ if (err) {
164
+ log.error(err)
165
+ } else {
166
+ isSuitesSkippingEnabled = itrConfig.isSuitesSkippingEnabled
167
+ isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
168
+ }
97
169
 
98
- command = getCypressCommand(details)
99
- frameworkVersion = getCypressVersion(details)
170
+ getSkippableTests(isSuitesSkippingEnabled, tracer, testConfiguration).then(({ err, skippableTests }) => {
171
+ if (err) {
172
+ log.error(err)
173
+ } else {
174
+ testsToSkip = skippableTests || []
175
+ }
100
176
 
101
- const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
102
- const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
177
+ const childOf = getTestParentSpan(tracer)
178
+ rootDir = getRootDir(details)
103
179
 
104
- testSessionSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_session`, {
105
- childOf,
106
- tags: {
107
- [COMPONENT]: TEST_FRAMEWORK_NAME,
108
- ...testEnvironmentMetadata,
109
- ...testSessionSpanMetadata
110
- }
111
- })
112
- testModuleSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_module`, {
113
- childOf: testSessionSpan,
114
- tags: {
115
- [COMPONENT]: TEST_FRAMEWORK_NAME,
116
- ...testEnvironmentMetadata,
117
- ...testModuleSpanMetadata
118
- }
180
+ command = getCypressCommand(details)
181
+ frameworkVersion = getCypressVersion(details)
182
+
183
+ const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
184
+ const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
185
+
186
+ testSessionSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_session`, {
187
+ childOf,
188
+ tags: {
189
+ [COMPONENT]: TEST_FRAMEWORK_NAME,
190
+ ...testEnvironmentMetadata,
191
+ ...testSessionSpanMetadata
192
+ }
193
+ })
194
+ testModuleSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_module`, {
195
+ childOf: testSessionSpan,
196
+ tags: {
197
+ [COMPONENT]: TEST_FRAMEWORK_NAME,
198
+ ...testEnvironmentMetadata,
199
+ ...testModuleSpanMetadata
200
+ }
201
+ })
202
+ return details
203
+ })
119
204
  })
120
205
  })
121
206
 
@@ -125,6 +210,16 @@ module.exports = (on, config) => {
125
210
  testModuleSpan.setTag(TEST_STATUS, testStatus)
126
211
  testSessionSpan.setTag(TEST_STATUS, testStatus)
127
212
 
213
+ addIntelligentTestRunnerSpanTags(
214
+ testSessionSpan,
215
+ testModuleSpan,
216
+ {
217
+ isSuitesSkipped: !!testsToSkip.length,
218
+ isSuitesSkippingEnabled,
219
+ isCodeCoverageEnabled
220
+ }
221
+ )
222
+
128
223
  testModuleSpan.finish()
129
224
  testSessionSpan.finish()
130
225
 
@@ -132,9 +227,15 @@ module.exports = (on, config) => {
132
227
  }
133
228
 
134
229
  return new Promise(resolve => {
135
- tracer._tracer._exporter._writer.flush(() => {
136
- resolve(null)
137
- })
230
+ if (tracer._tracer._exporter.flush) {
231
+ tracer._tracer._exporter.flush(() => {
232
+ resolve(null)
233
+ })
234
+ } else {
235
+ tracer._tracer._exporter._writer.flush(() => {
236
+ resolve(null)
237
+ })
238
+ }
138
239
  })
139
240
  })
140
241
  on('task', {
@@ -153,9 +254,9 @@ module.exports = (on, config) => {
153
254
  })
154
255
  return null
155
256
  },
156
- 'dd:testSuiteFinish': (suiteStats) => {
257
+ 'dd:testSuiteFinish': (stats) => {
157
258
  if (testSuiteSpan) {
158
- const status = getSuiteStatus(suiteStats)
259
+ const status = getSuiteStatus(stats)
159
260
  testSuiteSpan.setTag(TEST_STATUS, status)
160
261
  testSuiteSpan.finish()
161
262
  testSuiteSpan = null
@@ -164,6 +265,12 @@ module.exports = (on, config) => {
164
265
  },
165
266
  'dd:beforeEach': (test) => {
166
267
  const { testName, testSuite } = test
268
+ // skip test
269
+ if (testsToSkip.find(test => {
270
+ return testName === test.name && testSuite === test.suite
271
+ })) {
272
+ return { shouldSkip: true }
273
+ }
167
274
 
168
275
  const testSuiteTags = {
169
276
  [TEST_COMMAND]: command,
@@ -202,11 +309,24 @@ module.exports = (on, config) => {
202
309
  }
203
310
  })
204
311
  }
205
- return activeSpan ? activeSpan.context().toTraceId() : null
312
+ return activeSpan ? { traceId: activeSpan.context().toTraceId() } : {}
206
313
  },
207
- 'dd:afterEach': (test) => {
314
+ 'dd:afterEach': ({ test, coverage }) => {
208
315
  const { state, error, isRUMActive, testSourceLine } = test
209
316
  if (activeSpan) {
317
+ if (coverage && tracer._tracer._exporter.exportCoverage && isCodeCoverageEnabled) {
318
+ const coverageFiles = getCoveredFilenamesFromCoverage(coverage)
319
+ const relativeCoverageFiles = coverageFiles.map(file => getTestSuitePath(file, rootDir))
320
+ const { _traceId, _spanId } = testSuiteSpan.context()
321
+ const formattedCoverage = {
322
+ sessionId: _traceId,
323
+ suiteId: _spanId,
324
+ testId: activeSpan.context()._spanId,
325
+ files: relativeCoverageFiles
326
+ }
327
+ tracer._tracer._exporter.exportCoverage(formattedCoverage)
328
+ }
329
+
210
330
  activeSpan.setTag(TEST_STATUS, CYPRESS_STATUS_TO_TEST_STATUS[state])
211
331
  if (error) {
212
332
  activeSpan.setTag('error', error)
@@ -1,10 +1,13 @@
1
1
  /* eslint-disable */
2
- beforeEach(() => {
2
+ beforeEach(function () {
3
3
  cy.task('dd:beforeEach', {
4
4
  testName: Cypress.mocha.getRunner().suite.ctx.currentTest.fullTitle(),
5
5
  testSuite: Cypress.mocha.getRootSuite().file
6
- }).then(traceId => {
6
+ }).then(({ traceId, shouldSkip }) => {
7
7
  Cypress.env('traceId', traceId)
8
+ if (shouldSkip) {
9
+ this.skip()
10
+ }
8
11
  })
9
12
  })
10
13
 
@@ -36,6 +39,6 @@ afterEach(() => {
36
39
  if (win.DD_RUM) {
37
40
  testInfo.isRUMActive = true
38
41
  }
39
- cy.task('dd:afterEach', testInfo)
42
+ cy.task('dd:afterEach', { test: testInfo, coverage: win.__coverage__ })
40
43
  })
41
44
  })
@@ -4,15 +4,16 @@ const ClientPlugin = require('../../dd-trace/src/plugins/client')
4
4
 
5
5
  class GoogleCloudPubsubClientPlugin extends ClientPlugin {
6
6
  static get id () { return 'google-cloud-pubsub' }
7
+ static get type () { return 'messaging' }
7
8
  static get operation () { return 'request' }
8
9
 
9
10
  start ({ request, api, projectId }) {
10
11
  if (api === 'publish') return
11
12
 
12
- this.startSpan('pubsub.request', {
13
- service: this.config.service || `${this.tracer._service}-pubsub`,
13
+ this.startSpan(this.operationName(), {
14
+ service: this.config.service || this.serviceName(),
14
15
  resource: [api, request.name].filter(x => x).join(' '),
15
- kind: 'client',
16
+ kind: this.constructor.kind,
16
17
  meta: {
17
18
  'pubsub.method': api,
18
19
  'gcloud.project_id': projectId
@@ -11,11 +11,9 @@ class GoogleCloudPubsubConsumerPlugin extends ConsumerPlugin {
11
11
  const topic = subscription.metadata && subscription.metadata.topic
12
12
  const childOf = this.tracer.extract('text_map', message.attributes) || null
13
13
 
14
- this.startSpan('pubsub.receive', {
14
+ this.startSpan({
15
15
  childOf,
16
- service: this.config.service,
17
16
  resource: topic,
18
- kind: 'consumer',
19
17
  type: 'worker',
20
18
  meta: {
21
19
  'gcloud.project_id': subscription.pubsub.projectId,
@@ -11,10 +11,8 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
11
11
 
12
12
  const messages = request.messages || []
13
13
  const topic = request.topic
14
- const span = this.startSpan('pubsub.request', { // TODO: rename
15
- service: this.config.service || `${this.tracer._service}-pubsub`,
14
+ const span = this.startSpan({ // TODO: rename
16
15
  resource: `${api} ${topic}`,
17
- kind: 'producer',
18
16
  meta: {
19
17
  'gcloud.project_id': projectId,
20
18
  'pubsub.method': api, // TODO: remove
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const Plugin = require('../../dd-trace/src/plugins/plugin')
3
+ const ClientPlugin = require('../../dd-trace/src/plugins/client')
4
4
  const { storage } = require('../../datadog-core')
5
5
  const tags = require('../../../ext/tags')
6
6
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
@@ -9,96 +9,99 @@ const HTTP_HEADERS = formats.HTTP_HEADERS
9
9
  const urlFilter = require('../../dd-trace/src/plugins/util/urlfilter')
10
10
  const log = require('../../dd-trace/src/log')
11
11
  const url = require('url')
12
- const { COMPONENT, ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
12
+ const { CLIENT_PORT_KEY, COMPONENT, ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
13
13
 
14
14
  const HTTP_STATUS_CODE = tags.HTTP_STATUS_CODE
15
15
  const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS
16
16
  const HTTP_RESPONSE_HEADERS = tags.HTTP_RESPONSE_HEADERS
17
17
 
18
- class HttpClientPlugin extends Plugin {
18
+ class HttpClientPlugin extends ClientPlugin {
19
19
  static get id () {
20
20
  return 'http'
21
21
  }
22
22
 
23
- constructor (...args) {
24
- super(...args)
25
-
26
- this.addSub('apm:http:client:request:start', ({ args, http }) => {
27
- const store = storage.getStore()
28
- const options = args.options
29
- const agent = options.agent || options._defaultAgent || http.globalAgent
30
- const protocol = options.protocol || agent.protocol || 'http:'
31
- const hostname = options.hostname || options.host || 'localhost'
32
- const host = options.port ? `${hostname}:${options.port}` : hostname
33
- const path = options.path ? options.path.split(/[?#]/)[0] : '/'
34
- const uri = `${protocol}//${host}${path}`
35
- const allowed = this.config.filter(uri)
36
-
37
- const method = (options.method || 'GET').toUpperCase()
38
- const childOf = store && allowed ? store.span : null
39
- const span = this.tracer.startSpan('http.request', {
40
- childOf,
41
- tags: {
42
- [COMPONENT]: this.constructor.id,
43
- 'span.kind': 'client',
44
- 'service.name': getServiceName(this.tracer, this.config, options),
45
- 'resource.name': method,
46
- 'span.type': 'http',
47
- 'http.method': method,
48
- 'http.url': uri
49
- }
50
- })
23
+ addTraceSub (eventName, handler) {
24
+ this.addSub(`apm:${this.constructor.id}:client:${this.operation}:${eventName}`, handler)
25
+ }
51
26
 
52
- // TODO: Figure out a better way to do this for any span.
53
- if (!allowed) {
54
- span._spanContext._trace.record = false
27
+ start ({ args, http }) {
28
+ const store = storage.getStore()
29
+ const options = args.options
30
+ const agent = options.agent || options._defaultAgent || http.globalAgent
31
+ const protocol = options.protocol || agent.protocol || 'http:'
32
+ const hostname = options.hostname || options.host || 'localhost'
33
+ const host = options.port ? `${hostname}:${options.port}` : hostname
34
+ const path = options.path ? options.path.split(/[?#]/)[0] : '/'
35
+ const uri = `${protocol}//${host}${path}`
36
+ const allowed = this.config.filter(uri)
37
+
38
+ const method = (options.method || 'GET').toUpperCase()
39
+ const childOf = store && allowed ? store.span : null
40
+ // TODO delegate to super.startspan
41
+ const span = this.startSpan('http.request', {
42
+ childOf,
43
+ meta: {
44
+ [COMPONENT]: this.constructor.id,
45
+ 'span.kind': 'client',
46
+ 'service.name': getServiceName(this.tracer, this.config, options),
47
+ 'resource.name': method,
48
+ 'span.type': 'http',
49
+ 'http.method': method,
50
+ 'http.url': uri,
51
+ 'out.host': hostname
52
+ },
53
+ metrics: {
54
+ [CLIENT_PORT_KEY]: parseInt(options.port)
55
55
  }
56
+ })
56
57
 
57
- if (!(hasAmazonSignature(options) || !this.config.propagationFilter(uri))) {
58
- this.tracer.inject(span, HTTP_HEADERS, options.headers)
59
- }
58
+ // TODO: Figure out a better way to do this for any span.
59
+ if (!allowed) {
60
+ span._spanContext._trace.record = false
61
+ }
60
62
 
61
- analyticsSampler.sample(span, this.config.measured)
62
- this.enter(span, store)
63
- })
63
+ if (!(hasAmazonSignature(options) || !this.config.propagationFilter(uri))) {
64
+ this.tracer.inject(span, HTTP_HEADERS, options.headers)
65
+ }
64
66
 
65
- this.addSub('apm:http:client:request:finish', ({ req, res }) => {
66
- const span = storage.getStore().span
67
- if (res) {
68
- span.setTag(HTTP_STATUS_CODE, res.statusCode)
67
+ analyticsSampler.sample(span, this.config.measured)
68
+ this.enter(span, store)
69
+ }
69
70
 
70
- if (!this.config.validateStatus(res.statusCode)) {
71
- span.setTag('error', 1)
72
- }
71
+ finish ({ req, res }) {
72
+ const span = storage.getStore().span
73
+ if (res) {
74
+ span.setTag(HTTP_STATUS_CODE, res.statusCode)
73
75
 
74
- addResponseHeaders(res, span, this.config)
76
+ if (!this.config.validateStatus(res.statusCode)) {
77
+ span.setTag('error', 1)
75
78
  }
76
79
 
77
- addRequestHeaders(req, span, this.config)
80
+ addResponseHeaders(res, span, this.config)
81
+ }
78
82
 
79
- this.config.hooks.request(span, req, res)
80
- span.finish()
81
- })
83
+ addRequestHeaders(req, span, this.config)
82
84
 
83
- this.addSub('apm:http:client:request:error', errorHandler)
85
+ this.config.hooks.request(span, req, res)
86
+ span.finish()
84
87
  }
85
88
 
86
- configure (config) {
87
- return super.configure(normalizeClientConfig(config))
88
- }
89
- }
89
+ error (err) {
90
+ const span = storage.getStore().span
90
91
 
91
- function errorHandler (err) {
92
- const span = storage.getStore().span
92
+ if (err) {
93
+ span.addTags({
94
+ [ERROR_TYPE]: err.name,
95
+ [ERROR_MESSAGE]: err.message || err.code,
96
+ [ERROR_STACK]: err.stack
97
+ })
98
+ } else {
99
+ span.setTag('error', 1)
100
+ }
101
+ }
93
102
 
94
- if (err) {
95
- span.addTags({
96
- [ERROR_TYPE]: err.name,
97
- [ERROR_MESSAGE]: err.message || err.code,
98
- [ERROR_STACK]: err.stack
99
- })
100
- } else {
101
- span.setTag('error', 1)
103
+ configure (config) {
104
+ return super.configure(normalizeClientConfig(config))
102
105
  }
103
106
  }
104
107
 
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { storage } = require('../../datadog-core')
4
- const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const ClientPlugin = require('../../dd-trace/src/plugins/client')
5
5
 
6
6
  const URL = require('url').URL
7
7
  const log = require('../../dd-trace/src/log')
@@ -24,7 +24,7 @@ const HTTP2_HEADER_PATH = ':path'
24
24
  const HTTP2_HEADER_STATUS = ':status'
25
25
  const HTTP2_METHOD_GET = 'GET'
26
26
 
27
- class Http2ClientPlugin extends Plugin {
27
+ class Http2ClientPlugin extends ClientPlugin {
28
28
  static get id () {
29
29
  return 'http2'
30
30
  }
@@ -32,46 +32,6 @@ class Http2ClientPlugin extends Plugin {
32
32
  constructor (...args) {
33
33
  super(...args)
34
34
 
35
- this.addSub('apm:http2:client:request:start', ({ authority, options, headers = {} }) => {
36
- const sessionDetails = extractSessionDetails(authority, options)
37
- const path = headers[HTTP2_HEADER_PATH] || '/'
38
- const pathname = path.split(/[?#]/)[0]
39
- const method = headers[HTTP2_HEADER_METHOD] || HTTP2_METHOD_GET
40
- const uri = `${sessionDetails.protocol}//${sessionDetails.host}:${sessionDetails.port}${pathname}`
41
- const allowed = this.config.filter(uri)
42
-
43
- const store = storage.getStore()
44
- const childOf = store && allowed ? store.span : null
45
- const span = this.tracer.startSpan('http.request', {
46
- childOf,
47
- tags: {
48
- [COMPONENT]: this.constructor.id,
49
- [CLIENT_PORT_KEY]: parseInt(sessionDetails.port),
50
- [SPAN_KIND]: CLIENT,
51
- 'service.name': getServiceName(this.tracer, this.config, sessionDetails),
52
- 'resource.name': method,
53
- 'span.type': 'http',
54
- 'http.method': method,
55
- 'http.url': uri
56
- }
57
- })
58
-
59
- // TODO: Figure out a better way to do this for any span.
60
- if (!allowed) {
61
- span._spanContext._trace.record = false
62
- }
63
-
64
- addHeaderTags(span, headers, HTTP_REQUEST_HEADERS, this.config)
65
-
66
- if (!hasAmazonSignature(headers, path)) {
67
- this.tracer.inject(span, HTTP_HEADERS, headers)
68
- }
69
-
70
- analyticsSampler.sample(span, this.config.measured)
71
-
72
- this.enter(span, store)
73
- })
74
-
75
35
  this.addSub('apm:http2:client:response', (headers) => {
76
36
  const span = storage.getStore().span
77
37
  const status = headers && headers[HTTP2_HEADER_STATUS]
@@ -84,14 +44,58 @@ class Http2ClientPlugin extends Plugin {
84
44
 
85
45
  addHeaderTags(span, headers, HTTP_RESPONSE_HEADERS, this.config)
86
46
  })
47
+ }
87
48
 
88
- this.addSub('apm:http2:client:request:finish', () => {
89
- const span = storage.getStore().span
49
+ addTraceSub (eventName, handler) {
50
+ this.addSub(`apm:${this.constructor.id}:client:${this.operation}:${eventName}`, handler)
51
+ }
90
52
 
91
- span.finish()
53
+ start ({ authority, options, headers = {} }) {
54
+ const sessionDetails = extractSessionDetails(authority, options)
55
+ const path = headers[HTTP2_HEADER_PATH] || '/'
56
+ const pathname = path.split(/[?#]/)[0]
57
+ const method = headers[HTTP2_HEADER_METHOD] || HTTP2_METHOD_GET
58
+ const uri = `${sessionDetails.protocol}//${sessionDetails.host}:${sessionDetails.port}${pathname}`
59
+ const allowed = this.config.filter(uri)
60
+
61
+ const store = storage.getStore()
62
+ const childOf = store && allowed ? store.span : null
63
+ const span = this.startSpan('http.request', {
64
+ childOf,
65
+ meta: {
66
+ [COMPONENT]: this.constructor.id,
67
+ [SPAN_KIND]: CLIENT,
68
+ 'service.name': getServiceName(this.tracer, this.config, sessionDetails),
69
+ 'resource.name': method,
70
+ 'span.type': 'http',
71
+ 'http.method': method,
72
+ 'http.url': uri,
73
+ 'out.host': sessionDetails.host
74
+ },
75
+ metrics: {
76
+ [CLIENT_PORT_KEY]: parseInt(sessionDetails.port)
77
+ }
92
78
  })
93
79
 
94
- this.addSub('apm:http2:client:request:error', this.addError)
80
+ // TODO: Figure out a better way to do this for any span.
81
+ if (!allowed) {
82
+ span._spanContext._trace.record = false
83
+ }
84
+
85
+ addHeaderTags(span, headers, HTTP_REQUEST_HEADERS, this.config)
86
+
87
+ if (!hasAmazonSignature(headers, path)) {
88
+ this.tracer.inject(span, HTTP_HEADERS, headers)
89
+ }
90
+
91
+ analyticsSampler.sample(span, this.config.measured)
92
+
93
+ this.enter(span, store)
94
+ }
95
+
96
+ finish () {
97
+ const span = storage.getStore().span
98
+ span.finish()
95
99
  }
96
100
 
97
101
  configure (config) {
@@ -118,8 +118,8 @@ class JestPlugin extends CiPlugin {
118
118
 
119
119
  this.addSub('ci:jest:worker-report:coverage', data => {
120
120
  const formattedCoverages = JSON.parse(data).map(coverage => ({
121
- traceId: id(coverage.traceId),
122
- spanId: id(coverage.spanId),
121
+ sessionId: id(coverage.sessionId),
122
+ suiteId: id(coverage.suiteId),
123
123
  files: coverage.files
124
124
  }))
125
125
  formattedCoverages.forEach(formattedCoverage => {
@@ -150,9 +150,10 @@ class JestPlugin extends CiPlugin {
150
150
  * fetching the ITR config.
151
151
  */
152
152
  this.addSub('ci:jest:test-suite:code-coverage', (coverageFiles) => {
153
+ const { _traceId, _spanId } = this.testSuiteSpan.context()
153
154
  const formattedCoverage = {
154
- traceId: this.testSuiteSpan.context()._traceId,
155
- spanId: this.testSuiteSpan.context()._spanId,
155
+ sessionId: _traceId,
156
+ suiteId: _spanId,
156
157
  files: coverageFiles
157
158
  }
158
159
  this.tracer._exporter.exportCoverage(formattedCoverage)
@@ -1,3 +1,5 @@
1
+ const { getTestSuitePath } = require('../../dd-trace/src/plugins/util/test')
2
+
1
3
  /**
2
4
  * There are two ways to call `test.each` in `jest`:
3
5
  * 1. With an array of arrays: https://jestjs.io/docs/api#1-testeachtablename-fn-timeout
@@ -45,4 +47,11 @@ function getJestTestName (test) {
45
47
  return titles.join(' ')
46
48
  }
47
49
 
48
- module.exports = { getFormattedJestTestParameters, getJestTestName }
50
+ function getJestSuitesToRun (skippableSuites, originalTests, rootDir) {
51
+ return originalTests.filter(({ path: testPath }) => {
52
+ const relativePath = getTestSuitePath(testPath, rootDir)
53
+ return !skippableSuites.includes(relativePath)
54
+ })
55
+ }
56
+
57
+ module.exports = { getFormattedJestTestParameters, getJestTestName, getJestSuitesToRun }