dd-trace 4.18.0 → 5.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 (209) hide show
  1. package/CONTRIBUTING.md +98 -0
  2. package/LICENSE-3rdparty.csv +4 -5
  3. package/MIGRATING.md +15 -0
  4. package/README.md +20 -140
  5. package/ci/cypress/after-run.js +1 -0
  6. package/ci/cypress/after-spec.js +1 -0
  7. package/ci/init.js +1 -4
  8. package/ext/kinds.d.ts +1 -0
  9. package/ext/kinds.js +2 -1
  10. package/ext/tags.d.ts +2 -1
  11. package/ext/tags.js +6 -1
  12. package/index.d.ts +1523 -1460
  13. package/package.json +19 -19
  14. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  15. package/packages/datadog-core/src/utils/src/get.js +11 -0
  16. package/packages/datadog-core/src/utils/src/has.js +14 -0
  17. package/packages/datadog-core/src/utils/src/kebabcase.js +16 -0
  18. package/packages/datadog-core/src/utils/src/pick.js +11 -0
  19. package/packages/datadog-core/src/utils/src/set.js +16 -0
  20. package/packages/datadog-core/src/utils/src/uniq.js +5 -0
  21. package/packages/datadog-esbuild/index.js +1 -20
  22. package/packages/datadog-instrumentations/src/aerospike.js +47 -0
  23. package/packages/datadog-instrumentations/src/amqplib.js +2 -2
  24. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  25. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  26. package/packages/datadog-instrumentations/src/child_process.js +150 -0
  27. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  28. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  29. package/packages/datadog-instrumentations/src/cucumber.js +163 -46
  30. package/packages/datadog-instrumentations/src/dns.js +2 -1
  31. package/packages/datadog-instrumentations/src/express.js +20 -0
  32. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  33. package/packages/datadog-instrumentations/src/grpc/client.js +56 -36
  34. package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
  35. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  36. package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -3
  37. package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
  38. package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
  39. package/packages/datadog-instrumentations/src/http/client.js +12 -2
  40. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  41. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  42. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  43. package/packages/datadog-instrumentations/src/jest.js +239 -52
  44. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  45. package/packages/datadog-instrumentations/src/mocha.js +154 -18
  46. package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
  47. package/packages/datadog-instrumentations/src/mongoose.js +23 -10
  48. package/packages/datadog-instrumentations/src/mquery.js +65 -0
  49. package/packages/datadog-instrumentations/src/net.js +10 -2
  50. package/packages/datadog-instrumentations/src/next.js +35 -9
  51. package/packages/datadog-instrumentations/src/playwright.js +110 -16
  52. package/packages/datadog-instrumentations/src/restify.js +14 -1
  53. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  54. package/packages/datadog-plugin-aerospike/src/index.js +113 -0
  55. package/packages/datadog-plugin-amqplib/src/consumer.js +14 -1
  56. package/packages/datadog-plugin-amqplib/src/producer.js +13 -1
  57. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
  58. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +163 -27
  59. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +46 -8
  60. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +129 -22
  61. package/packages/datadog-plugin-child_process/src/index.js +91 -0
  62. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +125 -0
  63. package/packages/datadog-plugin-cucumber/src/index.js +70 -13
  64. package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
  65. package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
  66. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +625 -0
  67. package/packages/datadog-plugin-cypress/src/plugin.js +6 -454
  68. package/packages/datadog-plugin-cypress/src/support.js +50 -3
  69. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
  70. package/packages/datadog-plugin-graphql/src/index.js +1 -6
  71. package/packages/datadog-plugin-graphql/src/resolve.js +28 -18
  72. package/packages/datadog-plugin-grpc/src/client.js +16 -2
  73. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  74. package/packages/datadog-plugin-http/src/client.js +19 -2
  75. package/packages/datadog-plugin-jest/src/index.js +118 -12
  76. package/packages/datadog-plugin-jest/src/util.js +38 -16
  77. package/packages/datadog-plugin-kafkajs/src/consumer.js +76 -6
  78. package/packages/datadog-plugin-kafkajs/src/producer.js +64 -8
  79. package/packages/datadog-plugin-mocha/src/index.js +87 -17
  80. package/packages/datadog-plugin-next/src/index.js +40 -14
  81. package/packages/datadog-plugin-playwright/src/index.js +71 -8
  82. package/packages/datadog-plugin-rhea/src/consumer.js +16 -1
  83. package/packages/datadog-plugin-rhea/src/producer.js +10 -0
  84. package/packages/dd-trace/src/appsec/activation.js +29 -0
  85. package/packages/dd-trace/src/appsec/addresses.js +5 -1
  86. package/packages/dd-trace/src/appsec/api_security_sampler.js +61 -0
  87. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  88. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  89. package/packages/dd-trace/src/appsec/channels.js +7 -3
  90. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  91. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
  92. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
  93. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
  94. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +22 -17
  95. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -28
  96. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +10 -6
  97. package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
  98. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +90 -0
  99. package/packages/dd-trace/src/appsec/iast/context/kafka-ctx-plugin.js +14 -0
  100. package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
  101. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +13 -2
  102. package/packages/dd-trace/src/appsec/iast/index.js +15 -5
  103. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
  104. package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
  105. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -0
  106. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +10 -0
  107. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +53 -0
  108. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -46
  109. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +13 -9
  110. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +47 -0
  111. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +19 -6
  112. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +3 -1
  113. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +41 -3
  114. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
  115. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
  116. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
  117. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
  118. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
  119. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
  120. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
  121. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
  122. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  123. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +2 -0
  124. package/packages/dd-trace/src/appsec/index.js +49 -33
  125. package/packages/dd-trace/src/appsec/recommended.json +1763 -106
  126. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -1
  127. package/packages/dd-trace/src/appsec/remote_config/index.js +42 -16
  128. package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
  129. package/packages/dd-trace/src/appsec/reporter.js +51 -34
  130. package/packages/dd-trace/src/appsec/rule_manager.js +11 -8
  131. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  132. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
  133. package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
  134. package/packages/dd-trace/src/ci-visibility/{intelligent-test-runner/get-itr-configuration.js → early-flake-detection/get-known-tests.js} +17 -22
  135. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +25 -6
  136. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  137. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -0
  138. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  139. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +95 -37
  140. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +134 -61
  141. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +37 -4
  142. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +131 -0
  143. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  144. package/packages/dd-trace/src/config.js +561 -470
  145. package/packages/dd-trace/src/data_streams_context.js +1 -1
  146. package/packages/dd-trace/src/datastreams/pathway.js +58 -1
  147. package/packages/dd-trace/src/datastreams/processor.js +196 -27
  148. package/packages/dd-trace/src/datastreams/writer.js +11 -5
  149. package/packages/dd-trace/src/dogstatsd.js +3 -5
  150. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -6
  151. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  152. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  153. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  154. package/packages/dd-trace/src/exporters/common/request.js +21 -3
  155. package/packages/dd-trace/src/format.js +30 -2
  156. package/packages/dd-trace/src/id.js +12 -0
  157. package/packages/dd-trace/src/iitm.js +1 -1
  158. package/packages/dd-trace/src/log/channels.js +1 -1
  159. package/packages/dd-trace/src/noop/proxy.js +4 -0
  160. package/packages/dd-trace/src/noop/span.js +1 -0
  161. package/packages/dd-trace/src/opentelemetry/span.js +104 -4
  162. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  163. package/packages/dd-trace/src/opentracing/propagation/text_map.js +16 -7
  164. package/packages/dd-trace/src/opentracing/span.js +48 -4
  165. package/packages/dd-trace/src/opentracing/span_context.js +15 -6
  166. package/packages/dd-trace/src/opentracing/tracer.js +4 -3
  167. package/packages/dd-trace/src/plugin_manager.js +1 -1
  168. package/packages/dd-trace/src/plugins/ci_plugin.js +78 -19
  169. package/packages/dd-trace/src/plugins/database.js +1 -1
  170. package/packages/dd-trace/src/plugins/index.js +7 -0
  171. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  172. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  173. package/packages/dd-trace/src/plugins/util/git.js +104 -22
  174. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  175. package/packages/dd-trace/src/plugins/util/test.js +60 -10
  176. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  177. package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
  178. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  179. package/packages/dd-trace/src/priority_sampler.js +30 -38
  180. package/packages/dd-trace/src/profiler.js +5 -3
  181. package/packages/dd-trace/src/profiling/config.js +77 -24
  182. package/packages/dd-trace/src/profiling/exporters/agent.js +77 -31
  183. package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
  184. package/packages/dd-trace/src/profiling/profiler.js +33 -22
  185. package/packages/dd-trace/src/profiling/profilers/events.js +270 -0
  186. package/packages/dd-trace/src/profiling/profilers/shared.js +45 -0
  187. package/packages/dd-trace/src/profiling/profilers/space.js +18 -2
  188. package/packages/dd-trace/src/profiling/profilers/wall.js +146 -70
  189. package/packages/dd-trace/src/proxy.js +56 -24
  190. package/packages/dd-trace/src/ritm.js +1 -1
  191. package/packages/dd-trace/src/sampling_rule.js +130 -0
  192. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
  193. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  194. package/packages/dd-trace/src/span_processor.js +9 -1
  195. package/packages/dd-trace/src/span_sampler.js +6 -64
  196. package/packages/dd-trace/src/spanleak.js +98 -0
  197. package/packages/dd-trace/src/startup-log.js +7 -1
  198. package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
  199. package/packages/dd-trace/src/telemetry/index.js +182 -53
  200. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  201. package/packages/dd-trace/src/telemetry/send-data.js +65 -7
  202. package/packages/dd-trace/src/tracer.js +12 -5
  203. package/register.js +4 -0
  204. package/scripts/install_plugin_modules.js +11 -3
  205. package/scripts/st.js +105 -0
  206. package/packages/datadog-instrumentations/src/child-process.js +0 -30
  207. package/packages/dd-trace/src/plugins/util/exec.js +0 -13
  208. package/packages/diagnostics_channel/index.js +0 -3
  209. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -1,127 +1,5 @@
1
- const {
2
- TEST_STATUS,
3
- TEST_IS_RUM_ACTIVE,
4
- TEST_CODE_OWNERS,
5
- getTestEnvironmentMetadata,
6
- CI_APP_ORIGIN,
7
- getTestParentSpan,
8
- getCodeOwnersFileEntries,
9
- getCodeOwnersForFilename,
10
- getTestCommonTags,
11
- getTestSessionCommonTags,
12
- getTestModuleCommonTags,
13
- getTestSuiteCommonTags,
14
- TEST_SUITE_ID,
15
- TEST_MODULE_ID,
16
- TEST_SESSION_ID,
17
- TEST_COMMAND,
18
- TEST_MODULE,
19
- TEST_SOURCE_START,
20
- finishAllTraceSpans,
21
- getCoveredFilenamesFromCoverage,
22
- getTestSuitePath,
23
- addIntelligentTestRunnerSpanTags,
24
- TEST_SKIPPED_BY_ITR,
25
- TEST_ITR_UNSKIPPABLE,
26
- TEST_ITR_FORCED_RUN
27
- } = require('../../dd-trace/src/plugins/util/test')
28
- const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
29
- const log = require('../../dd-trace/src/log')
30
1
  const NoopTracer = require('../../dd-trace/src/noop/tracer')
31
- const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
32
-
33
- const TEST_FRAMEWORK_NAME = 'cypress'
34
-
35
- const CYPRESS_STATUS_TO_TEST_STATUS = {
36
- passed: 'pass',
37
- failed: 'fail',
38
- pending: 'skip',
39
- skipped: 'skip'
40
- }
41
-
42
- function getTestSpanMetadata (tracer, testName, testSuite, cypressConfig) {
43
- const childOf = getTestParentSpan(tracer)
44
-
45
- const commonTags = getTestCommonTags(testName, testSuite, cypressConfig.version, TEST_FRAMEWORK_NAME)
46
-
47
- return {
48
- childOf,
49
- ...commonTags
50
- }
51
- }
52
-
53
- function getCypressVersion (details) {
54
- if (details && details.cypressVersion) {
55
- return details.cypressVersion
56
- }
57
- if (details && details.config && details.config.version) {
58
- return details.config.version
59
- }
60
- return ''
61
- }
62
-
63
- function getRootDir (details) {
64
- if (details && details.config) {
65
- return details.config.projectRoot || details.config.repoRoot || process.cwd()
66
- }
67
- return process.cwd()
68
- }
69
-
70
- function getCypressCommand (details) {
71
- if (!details) {
72
- return TEST_FRAMEWORK_NAME
73
- }
74
- return `${TEST_FRAMEWORK_NAME} ${details.specPattern || ''}`
75
- }
76
-
77
- function getSessionStatus (summary) {
78
- if (summary.totalFailed !== undefined && summary.totalFailed > 0) {
79
- return 'fail'
80
- }
81
- if (summary.totalSkipped !== undefined && summary.totalSkipped === summary.totalTests) {
82
- return 'skip'
83
- }
84
- return 'pass'
85
- }
86
-
87
- function getSuiteStatus (suiteStats) {
88
- if (suiteStats.failures !== undefined && suiteStats.failures > 0) {
89
- return 'fail'
90
- }
91
- if (suiteStats.tests !== undefined && suiteStats.tests === suiteStats.pending) {
92
- return 'skip'
93
- }
94
- return 'pass'
95
- }
96
-
97
- function getItrConfig (tracer, testConfiguration) {
98
- return new Promise(resolve => {
99
- if (!tracer._tracer._exporter || !tracer._tracer._exporter.getItrConfiguration) {
100
- return resolve({ err: new Error('CI Visibility was not initialized correctly') })
101
- }
102
-
103
- tracer._tracer._exporter.getItrConfiguration(testConfiguration, (err, itrConfig) => {
104
- resolve({ err, itrConfig })
105
- })
106
- })
107
- }
108
-
109
- function getSkippableTests (isSuitesSkippingEnabled, tracer, testConfiguration) {
110
- if (!isSuitesSkippingEnabled) {
111
- return Promise.resolve({ skippableTests: [] })
112
- }
113
- return new Promise(resolve => {
114
- if (!tracer._tracer._exporter || !tracer._tracer._exporter.getItrConfiguration) {
115
- return resolve({ err: new Error('CI Visibility was not initialized correctly') })
116
- }
117
- tracer._tracer._exporter.getSkippableSuites(testConfiguration, (err, skippableTests) => {
118
- resolve({
119
- err,
120
- skippableTests
121
- })
122
- })
123
- })
124
- }
2
+ const cypressPlugin = require('./cypress-plugin')
125
3
 
126
4
  const noopTask = {
127
5
  'dd:testSuiteStart': () => {
@@ -139,8 +17,6 @@ const noopTask = {
139
17
  }
140
18
 
141
19
  module.exports = (on, config) => {
142
- let isTestsSkipped = false
143
- const skippedTests = []
144
20
  const tracer = require('../../dd-trace')
145
21
 
146
22
  // The tracer was not init correctly for whatever reason (such as invalid DD_SITE)
@@ -149,334 +25,10 @@ module.exports = (on, config) => {
149
25
  return on('task', noopTask)
150
26
  }
151
27
 
152
- const testEnvironmentMetadata = getTestEnvironmentMetadata(TEST_FRAMEWORK_NAME)
153
-
154
- const {
155
- 'git.repository_url': repositoryUrl,
156
- 'git.commit.sha': sha,
157
- 'os.version': osVersion,
158
- 'os.platform': osPlatform,
159
- 'os.architecture': osArchitecture,
160
- 'runtime.name': runtimeName,
161
- 'runtime.version': runtimeVersion,
162
- 'git.branch': branch
163
- } = testEnvironmentMetadata
164
-
165
- const finishedTestsByFile = {}
166
-
167
- const testConfiguration = {
168
- repositoryUrl,
169
- sha,
170
- osVersion,
171
- osPlatform,
172
- osArchitecture,
173
- runtimeName,
174
- runtimeVersion,
175
- branch,
176
- testLevel: 'test'
177
- }
178
-
179
- const codeOwnersEntries = getCodeOwnersFileEntries()
180
-
181
- let activeSpan = null
182
- let testSessionSpan = null
183
- let testModuleSpan = null
184
- let testSuiteSpan = null
185
- let command = null
186
- let frameworkVersion
187
- let rootDir
188
- let isSuitesSkippingEnabled = false
189
- let isCodeCoverageEnabled = false
190
- let testsToSkip = []
191
- const unskippableSuites = []
192
- let hasForcedToRunSuites = false
193
- let hasUnskippableSuites = false
194
-
195
- function getTestSpan (testName, testSuite, isUnskippable, isForcedToRun) {
196
- const testSuiteTags = {
197
- [TEST_COMMAND]: command,
198
- [TEST_COMMAND]: command,
199
- [TEST_MODULE]: TEST_FRAMEWORK_NAME
200
- }
201
- if (testSuiteSpan) {
202
- testSuiteTags[TEST_SUITE_ID] = testSuiteSpan.context().toSpanId()
203
- }
204
- if (testSessionSpan && testModuleSpan) {
205
- testSuiteTags[TEST_SESSION_ID] = testSessionSpan.context().toTraceId()
206
- testSuiteTags[TEST_MODULE_ID] = testModuleSpan.context().toSpanId()
207
- }
208
-
209
- const {
210
- childOf,
211
- resource,
212
- ...testSpanMetadata
213
- } = getTestSpanMetadata(tracer, testName, testSuite, config)
214
-
215
- const codeOwners = getCodeOwnersForFilename(testSuite, codeOwnersEntries)
216
-
217
- if (codeOwners) {
218
- testSpanMetadata[TEST_CODE_OWNERS] = codeOwners
219
- }
220
-
221
- if (isUnskippable) {
222
- hasUnskippableSuites = true
223
- testSpanMetadata[TEST_ITR_UNSKIPPABLE] = 'true'
224
- }
225
-
226
- if (isForcedToRun) {
227
- hasForcedToRunSuites = true
228
- testSpanMetadata[TEST_ITR_FORCED_RUN] = 'true'
229
- }
230
-
231
- return tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test`, {
232
- childOf,
233
- tags: {
234
- [COMPONENT]: TEST_FRAMEWORK_NAME,
235
- [ORIGIN_KEY]: CI_APP_ORIGIN,
236
- ...testSpanMetadata,
237
- ...testEnvironmentMetadata,
238
- ...testSuiteTags
239
- }
240
- })
241
- }
242
-
243
- on('before:run', (details) => {
244
- return getItrConfig(tracer, testConfiguration).then(({ err, itrConfig }) => {
245
- if (err) {
246
- log.error(err)
247
- } else {
248
- isSuitesSkippingEnabled = itrConfig.isSuitesSkippingEnabled
249
- isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
250
- }
251
-
252
- return getSkippableTests(isSuitesSkippingEnabled, tracer, testConfiguration).then(({ err, skippableTests }) => {
253
- if (err) {
254
- log.error(err)
255
- } else {
256
- testsToSkip = skippableTests || []
257
- }
258
-
259
- // `details.specs` are test files
260
- details.specs.forEach(({ absolute, relative }) => {
261
- const isUnskippableSuite = isMarkedAsUnskippable({ path: absolute })
262
- if (isUnskippableSuite) {
263
- unskippableSuites.push(relative)
264
- }
265
- })
266
-
267
- const childOf = getTestParentSpan(tracer)
268
- rootDir = getRootDir(details)
269
-
270
- command = getCypressCommand(details)
271
- frameworkVersion = getCypressVersion(details)
272
-
273
- const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
274
- const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, TEST_FRAMEWORK_NAME)
275
-
276
- testSessionSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_session`, {
277
- childOf,
278
- tags: {
279
- [COMPONENT]: TEST_FRAMEWORK_NAME,
280
- ...testEnvironmentMetadata,
281
- ...testSessionSpanMetadata
282
- }
283
- })
284
- testModuleSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_module`, {
285
- childOf: testSessionSpan,
286
- tags: {
287
- [COMPONENT]: TEST_FRAMEWORK_NAME,
288
- ...testEnvironmentMetadata,
289
- ...testModuleSpanMetadata
290
- }
291
- })
292
- return details
293
- })
294
- })
295
- })
296
- on('after:spec', (spec, { tests, stats }) => {
297
- const cypressTests = tests || []
298
- const finishedTests = finishedTestsByFile[spec.relative] || []
299
-
300
- // Get tests that didn't go through `dd:afterEach`
301
- // and create a skipped test span for each of them
302
- cypressTests.filter(({ title }) => {
303
- const cypressTestName = title.join(' ')
304
- const isTestFinished = finishedTests.find(({ testName }) => cypressTestName === testName)
305
-
306
- return !isTestFinished
307
- }).forEach(({ title }) => {
308
- const cypressTestName = title.join(' ')
309
- const isSkippedByItr = testsToSkip.find(test =>
310
- cypressTestName === test.name && spec.relative === test.suite
311
- )
312
- const skippedTestSpan = getTestSpan(cypressTestName, spec.relative)
313
- skippedTestSpan.setTag(TEST_STATUS, 'skip')
314
- if (isSkippedByItr) {
315
- skippedTestSpan.setTag(TEST_SKIPPED_BY_ITR, 'true')
316
- }
317
- skippedTestSpan.finish()
318
- })
319
-
320
- // Make sure that reported test statuses are the same as Cypress reports.
321
- // This is not always the case, such as when an `after` hook fails:
322
- // Cypress will report the last run test as failed, but we don't know that yet at `dd:afterEach`
323
- let latestError
324
- finishedTests.forEach((finishedTest) => {
325
- const cypressTest = cypressTests.find(test => test.title.join(' ') === finishedTest.testName)
326
- if (!cypressTest) {
327
- return
328
- }
329
- if (cypressTest.displayError) {
330
- latestError = new Error(cypressTest.displayError)
331
- }
332
- const cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state]
333
- // update test status
334
- if (cypressTestStatus !== finishedTest.testStatus) {
335
- finishedTest.testSpan.setTag(TEST_STATUS, cypressTestStatus)
336
- finishedTest.testSpan.setTag('error', latestError)
337
- }
338
- finishedTest.testSpan.finish(finishedTest.finishTime)
339
- })
340
-
341
- if (testSuiteSpan) {
342
- const status = getSuiteStatus(stats)
343
- testSuiteSpan.setTag(TEST_STATUS, status)
344
-
345
- if (latestError) {
346
- testSuiteSpan.setTag('error', latestError)
347
- }
348
- testSuiteSpan.finish()
349
- testSuiteSpan = null
350
- }
351
- })
352
-
353
- on('after:run', (suiteStats) => {
354
- if (testSessionSpan && testModuleSpan) {
355
- const testStatus = getSessionStatus(suiteStats)
356
- testModuleSpan.setTag(TEST_STATUS, testStatus)
357
- testSessionSpan.setTag(TEST_STATUS, testStatus)
358
-
359
- addIntelligentTestRunnerSpanTags(
360
- testSessionSpan,
361
- testModuleSpan,
362
- {
363
- isSuitesSkipped: isTestsSkipped,
364
- isSuitesSkippingEnabled,
365
- isCodeCoverageEnabled,
366
- skippingType: 'test',
367
- skippingCount: skippedTests.length,
368
- hasForcedToRunSuites,
369
- hasUnskippableSuites
370
- }
371
- )
372
-
373
- testModuleSpan.finish()
374
- testSessionSpan.finish()
375
-
376
- finishAllTraceSpans(testSessionSpan)
377
- }
378
-
379
- return new Promise(resolve => {
380
- const exporter = tracer._tracer._exporter
381
- if (!exporter) {
382
- return resolve(null)
383
- }
384
- if (exporter.flush) {
385
- exporter.flush(() => {
386
- resolve(null)
387
- })
388
- } else if (exporter._writer) {
389
- exporter._writer.flush(() => {
390
- resolve(null)
391
- })
392
- }
393
- })
394
- })
395
- on('task', {
396
- 'dd:testSuiteStart': (suite) => {
397
- if (testSuiteSpan) {
398
- return null
399
- }
400
- const testSuiteSpanMetadata = getTestSuiteCommonTags(command, frameworkVersion, suite, TEST_FRAMEWORK_NAME)
401
- testSuiteSpan = tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_suite`, {
402
- childOf: testModuleSpan,
403
- tags: {
404
- [COMPONENT]: TEST_FRAMEWORK_NAME,
405
- ...testEnvironmentMetadata,
406
- ...testSuiteSpanMetadata
407
- }
408
- })
409
- return null
410
- },
411
- 'dd:beforeEach': (test) => {
412
- const { testName, testSuite } = test
413
- const shouldSkip = !!testsToSkip.find(test => {
414
- return testName === test.name && testSuite === test.suite
415
- })
416
- const isUnskippable = unskippableSuites.includes(testSuite)
417
- const isForcedToRun = shouldSkip && isUnskippable
418
-
419
- // skip test
420
- if (shouldSkip && !isUnskippable) {
421
- skippedTests.push(test)
422
- isTestsSkipped = true
423
- return { shouldSkip: true }
424
- }
425
-
426
- if (!activeSpan) {
427
- activeSpan = getTestSpan(testName, testSuite, isUnskippable, isForcedToRun)
428
- }
429
-
430
- return activeSpan ? { traceId: activeSpan.context().toTraceId() } : {}
431
- },
432
- 'dd:afterEach': ({ test, coverage }) => {
433
- const { state, error, isRUMActive, testSourceLine, testSuite, testName } = test
434
- if (activeSpan) {
435
- if (coverage && isCodeCoverageEnabled && tracer._tracer._exporter && tracer._tracer._exporter.exportCoverage) {
436
- const coverageFiles = getCoveredFilenamesFromCoverage(coverage)
437
- const relativeCoverageFiles = coverageFiles.map(file => getTestSuitePath(file, rootDir))
438
- const { _traceId, _spanId } = testSuiteSpan.context()
439
- const formattedCoverage = {
440
- sessionId: _traceId,
441
- suiteId: _spanId,
442
- testId: activeSpan.context()._spanId,
443
- files: relativeCoverageFiles
444
- }
445
- tracer._tracer._exporter.exportCoverage(formattedCoverage)
446
- }
447
- const testStatus = CYPRESS_STATUS_TO_TEST_STATUS[state]
448
- activeSpan.setTag(TEST_STATUS, testStatus)
28
+ cypressPlugin.init(tracer, config)
449
29
 
450
- if (error) {
451
- activeSpan.setTag('error', error)
452
- }
453
- if (isRUMActive) {
454
- activeSpan.setTag(TEST_IS_RUM_ACTIVE, 'true')
455
- }
456
- if (testSourceLine) {
457
- activeSpan.setTag(TEST_SOURCE_START, testSourceLine)
458
- }
459
- const finishedTest = {
460
- testName,
461
- testStatus,
462
- finishTime: activeSpan._getTime(), // we store the finish time here
463
- testSpan: activeSpan
464
- }
465
- if (finishedTestsByFile[testSuite]) {
466
- finishedTestsByFile[testSuite].push(finishedTest)
467
- } else {
468
- finishedTestsByFile[testSuite] = [finishedTest]
469
- }
470
- // test spans are finished at after:spec
471
- }
472
- activeSpan = null
473
- return null
474
- },
475
- 'dd:addTags': (tags) => {
476
- if (activeSpan) {
477
- activeSpan.addTags(tags)
478
- }
479
- return null
480
- }
481
- })
30
+ on('before:run', cypressPlugin.beforeRun.bind(cypressPlugin))
31
+ on('after:spec', cypressPlugin.afterSpec.bind(cypressPlugin))
32
+ on('after:run', cypressPlugin.afterRun.bind(cypressPlugin))
33
+ on('task', cypressPlugin.getTasks())
482
34
  }
@@ -1,4 +1,43 @@
1
1
  /* eslint-disable */
2
+ let isEarlyFlakeDetectionEnabled = false
3
+ let knownTestsForSuite = []
4
+ let suiteTests = []
5
+ let earlyFlakeDetectionNumRetries = 0
6
+
7
+ function isNewTest (test) {
8
+ return !knownTestsForSuite.includes(test.fullTitle())
9
+ }
10
+
11
+ function retryTest (test, suiteTests) {
12
+ for (let retryIndex = 0; retryIndex < earlyFlakeDetectionNumRetries; retryIndex++) {
13
+ const clonedTest = test.clone()
14
+ // TODO: signal in framework logs that this is a retry.
15
+ // TODO: Change it so these tests are allowed to fail.
16
+ // TODO: figure out if reported duration is skewed.
17
+ suiteTests.unshift(clonedTest)
18
+ clonedTest._ddIsNew = true
19
+ clonedTest._ddIsEfdRetry = true
20
+ }
21
+ }
22
+
23
+
24
+ const oldRunTests = Cypress.mocha.getRunner().runTests
25
+ Cypress.mocha.getRunner().runTests = function (suite, fn) {
26
+ if (!isEarlyFlakeDetectionEnabled) {
27
+ return oldRunTests.apply(this, arguments)
28
+ }
29
+ // We copy the new tests at the beginning of the suite run (runTests), so that they're run
30
+ // multiple times.
31
+ suite.tests.forEach(test => {
32
+ if (!test._ddIsNew && !test.isPending() && isNewTest(test)) {
33
+ test._ddIsNew = true
34
+ retryTest(test, suite.tests)
35
+ }
36
+ })
37
+
38
+ return oldRunTests.apply(this, [suite, fn])
39
+ }
40
+
2
41
  beforeEach(function () {
3
42
  cy.task('dd:beforeEach', {
4
43
  testName: Cypress.mocha.getRunner().suite.ctx.currentTest.fullTitle(),
@@ -11,8 +50,14 @@ beforeEach(function () {
11
50
  })
12
51
  })
13
52
 
14
- before(() => {
15
- cy.task('dd:testSuiteStart', Cypress.mocha.getRootSuite().file)
53
+ before(function () {
54
+ cy.task('dd:testSuiteStart', Cypress.mocha.getRootSuite().file).then((suiteConfig) => {
55
+ if (suiteConfig) {
56
+ isEarlyFlakeDetectionEnabled = suiteConfig.isEarlyFlakeDetectionEnabled
57
+ knownTestsForSuite = suiteConfig.knownTestsForSuite
58
+ earlyFlakeDetectionNumRetries = suiteConfig.earlyFlakeDetectionNumRetries
59
+ }
60
+ })
16
61
  })
17
62
 
18
63
  after(() => {
@@ -24,7 +69,7 @@ after(() => {
24
69
  })
25
70
 
26
71
 
27
- afterEach(() => {
72
+ afterEach(function () {
28
73
  cy.window().then(win => {
29
74
  const currentTest = Cypress.mocha.getRunner().suite.ctx.currentTest
30
75
  const testInfo = {
@@ -32,6 +77,8 @@ afterEach(() => {
32
77
  testSuite: Cypress.mocha.getRootSuite().file,
33
78
  state: currentTest.state,
34
79
  error: currentTest.err,
80
+ isNew: currentTest._ddIsNew,
81
+ isEfdRetry: currentTest._ddIsEfdRetry
35
82
  }
36
83
  try {
37
84
  testInfo.testSourceLine = Cypress.mocha.getRunner().currentRunnable.invocationDetails.line
@@ -28,6 +28,8 @@ class GoogleCloudPubsubConsumerPlugin extends ConsumerPlugin {
28
28
  finish (message) {
29
29
  const span = this.activeSpan
30
30
 
31
+ if (!span) return
32
+
31
33
  if (message.message._handled) {
32
34
  span.setTag('pubsub.ack', 1)
33
35
  }
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const pick = require('../../datadog-core/src/utils/src/pick')
3
4
  const CompositePlugin = require('../../dd-trace/src/plugins/composite')
4
5
  const log = require('../../dd-trace/src/log')
5
6
  const GraphQLExecutePlugin = require('./execute')
@@ -63,10 +64,4 @@ function getHooks (config) {
63
64
  return { execute, parse, validate }
64
65
  }
65
66
 
66
- // non-lodash pick
67
-
68
- function pick (obj, selectors) {
69
- return Object.fromEntries(Object.entries(obj).filter(([key]) => selectors.includes(key)))
70
- }
71
-
72
67
  module.exports = GraphQLPlugin
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
4
+ const dc = require('dc-polyfill')
4
5
 
5
6
  const collapsedPathSym = Symbol('collapsedPaths')
6
7
 
@@ -14,8 +15,6 @@ class GraphQLResolvePlugin extends TracingPlugin {
14
15
  if (!shouldInstrument(this.config, path)) return
15
16
  const computedPathString = path.join('.')
16
17
 
17
- addResolver(context, info, args)
18
-
19
18
  if (this.config.collapse) {
20
19
  if (!context[collapsedPathSym]) {
21
20
  context[collapsedPathSym] = {}
@@ -55,6 +54,10 @@ class GraphQLResolvePlugin extends TracingPlugin {
55
54
  span.setTag(`graphql.variables.${name}`, variables[name])
56
55
  })
57
56
  }
57
+
58
+ if (this.resolverStartCh.hasSubscribers) {
59
+ this.resolverStartCh.publish({ context, resolverInfo: getResolverInfo(info, args) })
60
+ }
58
61
  }
59
62
 
60
63
  constructor (...args) {
@@ -69,6 +72,8 @@ class GraphQLResolvePlugin extends TracingPlugin {
69
72
  field.finishTime = span._getTime ? span._getTime() : 0
70
73
  field.error = field.error || err
71
74
  })
75
+
76
+ this.resolverStartCh = dc.channel('datadog:graphql:resolver:start')
72
77
  }
73
78
 
74
79
  configure (config) {
@@ -109,28 +114,33 @@ function withCollapse (responsePathAsArray) {
109
114
  }
110
115
  }
111
116
 
112
- function addResolver (context, info, args) {
113
- if (info.rootValue && !info.rootValue[info.fieldName]) {
114
- return
115
- }
117
+ function getResolverInfo (info, args) {
118
+ let resolverInfo = null
119
+ const resolverVars = {}
116
120
 
117
- if (!context.resolvers) {
118
- context.resolvers = {}
121
+ if (args && Object.keys(args).length) {
122
+ Object.assign(resolverVars, args)
119
123
  }
120
124
 
121
- const resolvers = context.resolvers
125
+ const directives = info.fieldNodes?.[0]?.directives
126
+ if (Array.isArray(directives)) {
127
+ for (const directive of directives) {
128
+ const argList = {}
129
+ for (const argument of directive['arguments']) {
130
+ argList[argument.name.value] = argument.value.value
131
+ }
122
132
 
123
- if (!resolvers[info.fieldName]) {
124
- if (args && Object.keys(args).length) {
125
- resolvers[info.fieldName] = [args]
126
- } else {
127
- resolvers[info.fieldName] = []
128
- }
129
- } else {
130
- if (args && Object.keys(args).length) {
131
- resolvers[info.fieldName].push(args)
133
+ if (Object.keys(argList).length) {
134
+ resolverVars[directive.name.value] = argList
135
+ }
132
136
  }
133
137
  }
138
+
139
+ if (Object.keys(resolverVars).length) {
140
+ resolverInfo = { [info.fieldName]: resolverVars }
141
+ }
142
+
143
+ return resolverInfo
134
144
  }
135
145
 
136
146
  module.exports = GraphQLResolvePlugin
@@ -41,7 +41,6 @@ class GrpcClientPlugin extends ClientPlugin {
41
41
  'grpc.status.code': 0
42
42
  }
43
43
  }, false)
44
-
45
44
  // needed as precursor for peer.service
46
45
  if (method.service && method.package) {
47
46
  span.setTag('rpc.service', method.package + '.' + method.service)
@@ -68,7 +67,7 @@ class GrpcClientPlugin extends ClientPlugin {
68
67
  this.addError(error, span)
69
68
  }
70
69
 
71
- finish ({ span, result }) {
70
+ finish ({ span, result, peer }) {
72
71
  if (!span) return
73
72
 
74
73
  const { code, metadata } = result || {}
@@ -80,6 +79,21 @@ class GrpcClientPlugin extends ClientPlugin {
80
79
  addMetadataTags(span, metadata, metadataFilter, 'response')
81
80
  }
82
81
 
82
+ if (peer) {
83
+ // The only scheme we want to support here is ipv[46]:port, although
84
+ // more are supported by the library
85
+ // https://github.com/grpc/grpc/blob/v1.60.0/doc/naming.md
86
+ const parts = peer.split(':')
87
+ if (parts[parts.length - 1].match(/^\d+/)) {
88
+ const port = parts[parts.length - 1]
89
+ const ip = parts.slice(0, -1).join(':')
90
+ span.setTag('network.destination.ip', ip)
91
+ span.setTag('network.destination.port', port)
92
+ } else {
93
+ span.setTag('network.destination.ip', peer)
94
+ }
95
+ }
96
+
83
97
  this.tagPeerService(span)
84
98
  span.finish()
85
99
  }