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
@@ -48,10 +48,17 @@ const TEST_MODULE_ID = 'test_module_id'
48
48
  const TEST_SUITE_ID = 'test_suite_id'
49
49
  const TEST_TOOLCHAIN = 'test.toolchain'
50
50
  const TEST_SKIPPED_BY_ITR = 'test.skipped_by_itr'
51
+ // Browser used in browser test. Namespaced by test.configuration because it affects the fingerprint
52
+ const TEST_CONFIGURATION_BROWSER_NAME = 'test.configuration.browser_name'
53
+ // Early flake detection
54
+ const TEST_IS_NEW = 'test.is_new'
55
+ const TEST_EARLY_FLAKE_IS_RETRY = 'test.early_flake.is_retry'
56
+ const TEST_EARLY_FLAKE_IS_ENABLED = 'test.early_flake.is_enabled'
51
57
 
52
58
  const CI_APP_ORIGIN = 'ciapp-test'
53
59
 
54
60
  const JEST_TEST_RUNNER = 'test.jest.test_runner'
61
+ const JEST_DISPLAY_NAME = 'test.jest.display_name'
55
62
 
56
63
  const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
57
64
  const TEST_ITR_SKIPPING_ENABLED = 'test.itr.tests_skipping.enabled'
@@ -60,6 +67,7 @@ const TEST_ITR_SKIPPING_COUNT = 'test.itr.tests_skipping.count'
60
67
  const TEST_CODE_COVERAGE_ENABLED = 'test.code_coverage.enabled'
61
68
  const TEST_ITR_UNSKIPPABLE = 'test.itr.unskippable'
62
69
  const TEST_ITR_FORCED_RUN = 'test.itr.forced_run'
70
+ const ITR_CORRELATION_ID = 'itr_correlation_id'
63
71
 
64
72
  const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
65
73
 
@@ -67,11 +75,16 @@ const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
67
75
  const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
68
76
  const JEST_WORKER_COVERAGE_PAYLOAD_CODE = 61
69
77
 
78
+ // Early flake detection util strings
79
+ const EFD_STRING = "Retried by Datadog's Early Flake Detection"
80
+ const EFD_TEST_NAME_REGEX = new RegExp(EFD_STRING + ' \\(#\\d+\\): ', 'g')
81
+
70
82
  module.exports = {
71
83
  TEST_CODE_OWNERS,
72
84
  TEST_FRAMEWORK,
73
85
  TEST_FRAMEWORK_VERSION,
74
86
  JEST_TEST_RUNNER,
87
+ JEST_DISPLAY_NAME,
75
88
  TEST_TYPE,
76
89
  TEST_NAME,
77
90
  TEST_SUITE,
@@ -86,6 +99,10 @@ module.exports = {
86
99
  JEST_WORKER_COVERAGE_PAYLOAD_CODE,
87
100
  TEST_SOURCE_START,
88
101
  TEST_SKIPPED_BY_ITR,
102
+ TEST_CONFIGURATION_BROWSER_NAME,
103
+ TEST_IS_NEW,
104
+ TEST_EARLY_FLAKE_IS_RETRY,
105
+ TEST_EARLY_FLAKE_IS_ENABLED,
89
106
  getTestEnvironmentMetadata,
90
107
  getTestParametersString,
91
108
  finishAllTraceSpans,
@@ -111,6 +128,7 @@ module.exports = {
111
128
  TEST_CODE_COVERAGE_LINES_PCT,
112
129
  TEST_ITR_UNSKIPPABLE,
113
130
  TEST_ITR_FORCED_RUN,
131
+ ITR_CORRELATION_ID,
114
132
  addIntelligentTestRunnerSpanTags,
115
133
  getCoveredFilenamesFromCoverage,
116
134
  resetCoverage,
@@ -119,7 +137,11 @@ module.exports = {
119
137
  getTestLineStart,
120
138
  getCallSites,
121
139
  removeInvalidMetadata,
122
- parseAnnotations
140
+ parseAnnotations,
141
+ EFD_STRING,
142
+ EFD_TEST_NAME_REGEX,
143
+ removeEfdStringFromTestName,
144
+ addEfdStringToTestName
123
145
  }
124
146
 
125
147
  // Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
@@ -251,7 +273,6 @@ function getTestCommonTags (name, suite, version, testFramework) {
251
273
  [SAMPLING_PRIORITY]: AUTO_KEEP,
252
274
  [TEST_NAME]: name,
253
275
  [TEST_SUITE]: suite,
254
- [TEST_SOURCE_FILE]: suite,
255
276
  [RESOURCE_NAME]: `${suite}.${name}`,
256
277
  [TEST_FRAMEWORK_VERSION]: version,
257
278
  [LIBRARY_VERSION]: ddTraceVersion
@@ -279,16 +300,36 @@ const POSSIBLE_CODEOWNERS_LOCATIONS = [
279
300
  '.gitlab/CODEOWNERS'
280
301
  ]
281
302
 
282
- function getCodeOwnersFileEntries (rootDir = process.cwd()) {
283
- let codeOwnersContent
284
-
285
- POSSIBLE_CODEOWNERS_LOCATIONS.forEach(location => {
303
+ function readCodeOwners (rootDir) {
304
+ for (const location of POSSIBLE_CODEOWNERS_LOCATIONS) {
286
305
  try {
287
- codeOwnersContent = fs.readFileSync(`${rootDir}/${location}`).toString()
306
+ return fs.readFileSync(path.join(rootDir, location)).toString()
288
307
  } catch (e) {
289
308
  // retry with next path
290
309
  }
291
- })
310
+ }
311
+ return ''
312
+ }
313
+
314
+ function getCodeOwnersFileEntries (rootDir) {
315
+ let codeOwnersContent
316
+ let usedRootDir = rootDir
317
+ let isTriedCwd = false
318
+
319
+ const processCwd = process.cwd()
320
+
321
+ if (!usedRootDir || usedRootDir === processCwd) {
322
+ usedRootDir = processCwd
323
+ isTriedCwd = true
324
+ }
325
+
326
+ codeOwnersContent = readCodeOwners(usedRootDir)
327
+
328
+ // If we haven't found CODEOWNERS in the provided root dir, we try with process.cwd()
329
+ if (!codeOwnersContent && !isTriedCwd) {
330
+ codeOwnersContent = readCodeOwners(processCwd)
331
+ }
332
+
292
333
  if (!codeOwnersContent) {
293
334
  return null
294
335
  }
@@ -397,8 +438,9 @@ function addIntelligentTestRunnerSpanTags (
397
438
  testModuleSpan.setTag(TEST_ITR_FORCED_RUN, 'true')
398
439
  }
399
440
 
400
- // If suites have been skipped we don't want to report the total coverage, as it will be wrong
401
- if (testCodeCoverageLinesTotal !== undefined && !isSuitesSkipped) {
441
+ // This will not be reported unless the user has manually added code coverage.
442
+ // This is always the case for Mocha and Cucumber, but not for Jest.
443
+ if (testCodeCoverageLinesTotal !== undefined) {
402
444
  testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
403
445
  testModuleSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
404
446
  }
@@ -520,3 +562,11 @@ function parseAnnotations (annotations) {
520
562
  return tags
521
563
  }, {})
522
564
  }
565
+
566
+ function addEfdStringToTestName (testName, numAttempt) {
567
+ return `${EFD_STRING} (#${numAttempt}): ${testName}`
568
+ }
569
+
570
+ function removeEfdStringFromTestName (testName) {
571
+ return testName.replace(EFD_TEST_NAME_REGEX, '')
572
+ }
@@ -0,0 +1,26 @@
1
+ const { URL } = require('url')
2
+
3
+ function filterSensitiveInfoFromRepository (repositoryUrl) {
4
+ if (!repositoryUrl) {
5
+ return ''
6
+ }
7
+ if (repositoryUrl.startsWith('git@')) {
8
+ return repositoryUrl
9
+ }
10
+
11
+ // Remove the username from ssh URLs
12
+ if (repositoryUrl.startsWith('ssh://')) {
13
+ const sshRegex = /^(ssh:\/\/)[^@/]*@/
14
+ return repositoryUrl.replace(sshRegex, '$1')
15
+ }
16
+
17
+ try {
18
+ const { protocol, host, pathname } = new URL(repositoryUrl)
19
+
20
+ return `${protocol}//${host}${pathname === '/' ? '' : pathname}`
21
+ } catch (e) {
22
+ return ''
23
+ }
24
+ }
25
+
26
+ module.exports = { filterSensitiveInfoFromRepository }
@@ -13,7 +13,7 @@ const {
13
13
  } = require('./tags')
14
14
 
15
15
  const { normalizeRef } = require('./ci')
16
- const { URL } = require('url')
16
+ const { filterSensitiveInfoFromRepository } = require('./url')
17
17
 
18
18
  function removeEmptyValues (tags) {
19
19
  return Object.keys(tags).reduce((filteredTags, tag) => {
@@ -27,23 +27,11 @@ function removeEmptyValues (tags) {
27
27
  }, {})
28
28
  }
29
29
 
30
- function filterSensitiveInfoFromRepository (repositoryUrl) {
31
- try {
32
- if (repositoryUrl.startsWith('git@')) {
33
- return repositoryUrl
34
- }
35
- const { protocol, hostname, pathname } = new URL(repositoryUrl)
36
-
37
- return `${protocol}//${hostname}${pathname}`
38
- } catch (e) {
39
- return repositoryUrl
40
- }
41
- }
42
-
43
- // The regex is extracted from
30
+ // The regex is inspired by
44
31
  // https://github.com/jonschlinkert/is-git-url/blob/396965ffabf2f46656c8af4c47bef1d69f09292e/index.js#L9C15-L9C87
32
+ // The `.git` suffix is optional in this version
45
33
  function validateGitRepositoryUrl (repoUrl) {
46
- return /(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\.git)(\/?|#[-\d\w._]+?)$/.test(repoUrl)
34
+ return /(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\/?|#[-\d\w._]+?)$/.test(repoUrl)
47
35
  }
48
36
 
49
37
  function validateGitCommitSha (gitCommitSha) {
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const uniq = require('lodash.uniq')
3
+ const uniq = require('../../../../datadog-core/src/utils/src/uniq')
4
4
  const analyticsSampler = require('../../analytics_sampler')
5
5
  const FORMAT_HTTP_HEADERS = 'http_headers'
6
6
  const log = require('../../log')
@@ -1,9 +1,8 @@
1
1
  'use strict'
2
2
 
3
- const RateLimiter = require('./rate_limiter')
4
3
  const Sampler = require('./sampler')
5
- const ext = require('../../../ext')
6
4
  const { setSamplingRules } = require('./startup-log')
5
+ const SamplingRule = require('./sampling_rule')
7
6
 
8
7
  const {
9
8
  SAMPLING_MECHANISM_DEFAULT,
@@ -16,14 +15,21 @@ const {
16
15
  DECISION_MAKER_KEY
17
16
  } = require('./constants')
18
17
 
19
- const SERVICE_NAME = ext.tags.SERVICE_NAME
20
- const SAMPLING_PRIORITY = ext.tags.SAMPLING_PRIORITY
21
- const MANUAL_KEEP = ext.tags.MANUAL_KEEP
22
- const MANUAL_DROP = ext.tags.MANUAL_DROP
23
- const USER_REJECT = ext.priority.USER_REJECT
24
- const AUTO_REJECT = ext.priority.AUTO_REJECT
25
- const AUTO_KEEP = ext.priority.AUTO_KEEP
26
- const USER_KEEP = ext.priority.USER_KEEP
18
+ const {
19
+ tags: {
20
+ MANUAL_KEEP,
21
+ MANUAL_DROP,
22
+ SAMPLING_PRIORITY,
23
+ SERVICE_NAME
24
+ },
25
+ priority: {
26
+ AUTO_REJECT,
27
+ AUTO_KEEP,
28
+ USER_REJECT,
29
+ USER_KEEP
30
+ }
31
+ } = require('../../../ext')
32
+
27
33
  const DEFAULT_KEY = 'service:,env:'
28
34
 
29
35
  const defaultSampler = new Sampler(AUTO_KEEP)
@@ -36,8 +42,7 @@ class PrioritySampler {
36
42
 
37
43
  configure (env, { sampleRate, rateLimit = 100, rules = [] } = {}) {
38
44
  this._env = env
39
- this._rules = this._normalizeRules(rules, sampleRate)
40
- this._limiter = new RateLimiter(rateLimit)
45
+ this._rules = this._normalizeRules(rules, sampleRate, rateLimit)
41
46
 
42
47
  setSamplingRules(this._rules)
43
48
  }
@@ -104,7 +109,7 @@ class PrioritySampler {
104
109
 
105
110
  _getPriorityFromAuto (span) {
106
111
  const context = this._getContext(span)
107
- const rule = this._findRule(context)
112
+ const rule = this._findRule(span)
108
113
 
109
114
  return rule
110
115
  ? this._getPriorityByRule(context, rule)
@@ -131,15 +136,14 @@ class PrioritySampler {
131
136
  context._trace[SAMPLING_RULE_DECISION] = rule.sampleRate
132
137
  context._sampling.mechanism = SAMPLING_MECHANISM_RULE
133
138
 
134
- return rule.sampler.isSampled(context) && this._isSampledByRateLimit(context) ? USER_KEEP : USER_REJECT
135
- }
139
+ const sampled = rule.sample()
140
+ const priority = sampled ? USER_KEEP : USER_REJECT
136
141
 
137
- _isSampledByRateLimit (context) {
138
- const allowed = this._limiter.isAllowed()
139
-
140
- context._trace[SAMPLING_LIMIT_DECISION] = this._limiter.effectiveRate()
142
+ if (sampled) {
143
+ context._trace[SAMPLING_LIMIT_DECISION] = rule.effectiveRate
144
+ }
141
145
 
142
- return allowed
146
+ return priority
143
147
  }
144
148
 
145
149
  _getPriorityByAgent (context) {
@@ -172,33 +176,21 @@ class PrioritySampler {
172
176
  }
173
177
  }
174
178
 
175
- _normalizeRules (rules, sampleRate) {
179
+ _normalizeRules (rules, sampleRate, rateLimit) {
176
180
  rules = [].concat(rules || [])
177
181
 
178
182
  return rules
179
- .concat({ sampleRate })
183
+ .concat({ sampleRate, maxPerSecond: rateLimit })
180
184
  .map(rule => ({ ...rule, sampleRate: parseFloat(rule.sampleRate) }))
181
185
  .filter(rule => !isNaN(rule.sampleRate))
182
- .map(rule => ({ ...rule, sampler: new Sampler(rule.sampleRate) }))
186
+ .map(SamplingRule.from)
183
187
  }
184
188
 
185
- _findRule (context) {
186
- for (let i = 0, l = this._rules.length; i < l; i++) {
187
- if (this._matchRule(context, this._rules[i])) return this._rules[i]
189
+ _findRule (span) {
190
+ for (const rule of this._rules) {
191
+ if (rule.match(span)) return rule
188
192
  }
189
193
  }
190
-
191
- _matchRule (context, rule) {
192
- const name = context._name
193
- const service = context._tags['service.name']
194
-
195
- if (rule.name instanceof RegExp && !rule.name.test(name)) return false
196
- if (typeof rule.name === 'string' && rule.name !== name) return false
197
- if (rule.service instanceof RegExp && !rule.service.test(service)) return false
198
- if (typeof rule.service === 'string' && rule.service !== service) return false
199
-
200
- return true
201
- }
202
194
  }
203
195
 
204
196
  function hasOwn (object, prop) {
@@ -8,7 +8,7 @@ process.once('beforeExit', () => { profiler.stop() })
8
8
 
9
9
  module.exports = {
10
10
  start: config => {
11
- const { service, version, env, url, hostname, port, tags } = config
11
+ const { service, version, env, url, hostname, port, tags, repositoryUrl, commitSHA } = config
12
12
  const { enabled, sourceMap, exporters } = config.profiling
13
13
  const logger = {
14
14
  debug: (message) => log.debug(message),
@@ -17,7 +17,7 @@ module.exports = {
17
17
  error: (message) => log.error(message)
18
18
  }
19
19
 
20
- profiler.start({
20
+ return profiler.start({
21
21
  enabled,
22
22
  service,
23
23
  version,
@@ -28,7 +28,9 @@ module.exports = {
28
28
  url,
29
29
  hostname,
30
30
  port,
31
- tags
31
+ tags,
32
+ repositoryUrl,
33
+ commitSHA
32
34
  })
33
35
  },
34
36
 
@@ -9,38 +9,43 @@ const { FileExporter } = require('./exporters/file')
9
9
  const { ConsoleLogger } = require('./loggers/console')
10
10
  const WallProfiler = require('./profilers/wall')
11
11
  const SpaceProfiler = require('./profilers/space')
12
+ const EventsProfiler = require('./profilers/events')
12
13
  const { oomExportStrategies, snapshotKinds } = require('./constants')
14
+ const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
13
15
  const { tagger } = require('./tagger')
14
16
  const { isFalse, isTrue } = require('../util')
15
17
 
16
18
  class Config {
17
19
  constructor (options = {}) {
18
20
  const {
19
- DD_PROFILING_ENABLED,
20
- DD_PROFILING_PROFILERS,
21
- DD_ENV,
22
- DD_TAGS,
23
- DD_SERVICE,
24
- DD_VERSION,
25
- DD_TRACE_AGENT_URL,
26
21
  DD_AGENT_HOST,
27
- DD_TRACE_AGENT_PORT,
22
+ DD_ENV,
23
+ DD_PROFILING_CODEHOTSPOTS_ENABLED,
28
24
  DD_PROFILING_DEBUG_SOURCE_MAPS,
29
- DD_PROFILING_UPLOAD_TIMEOUT,
25
+ DD_PROFILING_ENABLED,
26
+ DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
27
+ DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED,
28
+ DD_PROFILING_EXPERIMENTAL_CPU_ENABLED,
29
+ DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED,
30
+ DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES,
31
+ DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
32
+ DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
33
+ DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED,
34
+ DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED,
35
+ DD_PROFILING_HEAP_ENABLED,
36
+ DD_PROFILING_PPROF_PREFIX,
37
+ DD_PROFILING_PROFILERS,
30
38
  DD_PROFILING_SOURCE_MAP,
39
+ DD_PROFILING_TIMELINE_ENABLED,
31
40
  DD_PROFILING_UPLOAD_PERIOD,
32
- DD_PROFILING_PPROF_PREFIX,
33
- DD_PROFILING_HEAP_ENABLED,
41
+ DD_PROFILING_UPLOAD_TIMEOUT,
34
42
  DD_PROFILING_V8_PROFILER_BUG_WORKAROUND,
35
43
  DD_PROFILING_WALLTIME_ENABLED,
36
- DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED,
37
- DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
38
- DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
39
- DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES,
40
- DD_PROFILING_CODEHOTSPOTS_ENABLED,
41
- DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
42
- DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED,
43
- DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED
44
+ DD_SERVICE,
45
+ DD_TAGS,
46
+ DD_TRACE_AGENT_PORT,
47
+ DD_TRACE_AGENT_URL,
48
+ DD_VERSION
44
49
  } = process.env
45
50
 
46
51
  const enabled = isTrue(coalesce(options.enabled, DD_PROFILING_ENABLED, true))
@@ -70,6 +75,13 @@ class Config {
70
75
  tagger.parse(options.tags),
71
76
  tagger.parse({ env, host, service, version, functionname })
72
77
  )
78
+
79
+ // Add source code integration tags if available
80
+ if (options.repositoryUrl && options.commitSHA) {
81
+ this.tags[GIT_REPOSITORY_URL] = options.repositoryUrl
82
+ this.tags[GIT_COMMIT_SHA] = options.commitSHA
83
+ }
84
+
73
85
  this.logger = ensureLogger(options.logger)
74
86
  const logger = this.logger
75
87
  function logExperimentalVarDeprecation (shortVarName) {
@@ -81,14 +93,28 @@ class Config {
81
93
  logger.warn(`${deprecatedEnvVarName} is deprecated. Use DD_PROFILING_${shortVarName} instead.`)
82
94
  }
83
95
  }
96
+ // Profiler sampling contexts are not available on Windows, so features
97
+ // depending on those (code hotspots and endpoint collection) need to default
98
+ // to false on Windows.
99
+ const samplingContextsAvailable = process.platform !== 'win32'
100
+ function checkOptionAllowed (option, description, condition) {
101
+ if (option && !condition) {
102
+ throw new Error(`${description} not supported on ${process.platform}.`)
103
+ }
104
+ }
105
+ function checkOptionWithSamplingContextAllowed (option, description) {
106
+ checkOptionAllowed(option, description, samplingContextsAvailable)
107
+ }
108
+
84
109
  this.flushInterval = flushInterval
85
110
  this.uploadTimeout = uploadTimeout
86
111
  this.sourceMap = sourceMap
87
112
  this.debugSourceMaps = isTrue(coalesce(options.debugSourceMaps, DD_PROFILING_DEBUG_SOURCE_MAPS, false))
88
113
  this.endpointCollectionEnabled = isTrue(coalesce(options.endpointCollection,
89
114
  DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
90
- DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED, false))
115
+ DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED, samplingContextsAvailable))
91
116
  logExperimentalVarDeprecation('ENDPOINT_COLLECTION_ENABLED')
117
+ checkOptionWithSamplingContextAllowed(this.endpointCollectionEnabled, 'Endpoint collection')
92
118
 
93
119
  this.pprofPrefix = pprofPrefix
94
120
  this.v8ProfilerBugWorkaroundEnabled = isTrue(coalesce(options.v8ProfilerBugWorkaround,
@@ -105,8 +131,13 @@ class Config {
105
131
  new AgentExporter(this)
106
132
  ], this)
107
133
 
134
+ // OOM monitoring does not work well on Windows, so it is disabled by default.
135
+ const oomMonitoringSupported = process.platform !== 'win32'
136
+
108
137
  const oomMonitoringEnabled = isTrue(coalesce(options.oomMonitoring,
109
- DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED, true))
138
+ DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED, oomMonitoringSupported))
139
+ checkOptionAllowed(oomMonitoringEnabled, 'OOM monitoring', oomMonitoringSupported)
140
+
110
141
  const heapLimitExtensionSize = coalesce(options.oomHeapLimitExtensionSize,
111
142
  Number(DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE), 0)
112
143
  const maxHeapExtensionCount = coalesce(options.oomMaxHeapExtensionCount,
@@ -126,12 +157,27 @@ class Config {
126
157
 
127
158
  const profilers = options.profilers
128
159
  ? options.profilers
129
- : getProfilers({ DD_PROFILING_HEAP_ENABLED, DD_PROFILING_WALLTIME_ENABLED, DD_PROFILING_PROFILERS })
160
+ : getProfilers({
161
+ DD_PROFILING_HEAP_ENABLED,
162
+ DD_PROFILING_WALLTIME_ENABLED,
163
+ DD_PROFILING_PROFILERS
164
+ })
165
+
166
+ this.timelineEnabled = isTrue(coalesce(options.timelineEnabled,
167
+ DD_PROFILING_TIMELINE_ENABLED,
168
+ DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED, false))
169
+ logExperimentalVarDeprecation('TIMELINE_ENABLED')
170
+ checkOptionWithSamplingContextAllowed(this.timelineEnabled, 'Timeline view')
130
171
 
131
172
  this.codeHotspotsEnabled = isTrue(coalesce(options.codeHotspotsEnabled,
132
173
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
133
- DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, false))
174
+ DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, samplingContextsAvailable))
134
175
  logExperimentalVarDeprecation('CODEHOTSPOTS_ENABLED')
176
+ checkOptionWithSamplingContextAllowed(this.codeHotspotsEnabled, 'Code hotspots')
177
+
178
+ this.cpuProfilingEnabled = isTrue(coalesce(options.cpuProfilingEnabled,
179
+ DD_PROFILING_EXPERIMENTAL_CPU_ENABLED, false))
180
+ checkOptionWithSamplingContextAllowed(this.cpuProfilingEnabled, 'CPU profiling')
135
181
 
136
182
  this.profilers = ensureProfilers(profilers, this)
137
183
  }
@@ -139,7 +185,9 @@ class Config {
139
185
 
140
186
  module.exports = { Config }
141
187
 
142
- function getProfilers ({ DD_PROFILING_HEAP_ENABLED, DD_PROFILING_WALLTIME_ENABLED, DD_PROFILING_PROFILERS }) {
188
+ function getProfilers ({
189
+ DD_PROFILING_HEAP_ENABLED, DD_PROFILING_WALLTIME_ENABLED, DD_PROFILING_PROFILERS
190
+ }) {
143
191
  // First consider "legacy" DD_PROFILING_PROFILERS env variable, defaulting to wall + space
144
192
  // Use a Set to avoid duplicates
145
193
  const profilers = new Set(coalesce(DD_PROFILING_PROFILERS, 'wall,space').split(','))
@@ -240,6 +288,11 @@ function ensureProfilers (profilers, options) {
240
288
  }
241
289
  }
242
290
 
291
+ // Events profiler is a profiler for timeline events
292
+ if (options.timelineEnabled) {
293
+ profilers.push(new EventsProfiler(options))
294
+ }
295
+
243
296
  // Filter out any invalid profilers
244
297
  return profilers.filter(v => v)
245
298
  }