dd-trace 5.0.0 → 5.2.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 (46) hide show
  1. package/LICENSE-3rdparty.csv +0 -3
  2. package/MIGRATING.md +15 -0
  3. package/README.md +11 -9
  4. package/package.json +4 -6
  5. package/packages/datadog-instrumentations/src/amqplib.js +1 -1
  6. package/packages/datadog-instrumentations/src/cucumber.js +3 -1
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  8. package/packages/datadog-instrumentations/src/jest.js +1 -0
  9. package/packages/datadog-instrumentations/src/mocha.js +9 -2
  10. package/packages/datadog-instrumentations/src/mquery.js +65 -0
  11. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +28 -1
  12. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +19 -1
  13. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +83 -10
  14. package/packages/datadog-plugin-cucumber/src/index.js +11 -7
  15. package/packages/datadog-plugin-cypress/src/plugin.js +60 -46
  16. package/packages/datadog-plugin-graphql/src/index.js +1 -6
  17. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  18. package/packages/datadog-plugin-jest/src/index.js +7 -1
  19. package/packages/datadog-plugin-mocha/src/index.js +11 -2
  20. package/packages/datadog-plugin-playwright/src/index.js +2 -0
  21. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  22. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +3 -3
  23. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +22 -17
  24. package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
  25. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +1 -0
  26. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +12 -1
  27. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  28. package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
  29. package/packages/dd-trace/src/appsec/reporter.js +2 -1
  30. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +4 -2
  31. package/packages/dd-trace/src/config.js +10 -6
  32. package/packages/dd-trace/src/datastreams/processor.js +30 -5
  33. package/packages/dd-trace/src/datastreams/writer.js +9 -0
  34. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +25 -2
  35. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -1
  36. package/packages/dd-trace/src/plugins/ci_plugin.js +9 -3
  37. package/packages/dd-trace/src/plugins/util/test.js +2 -0
  38. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  39. package/packages/dd-trace/src/profiling/config.js +19 -5
  40. package/packages/dd-trace/src/telemetry/index.js +8 -3
  41. package/packages/dd-trace/src/telemetry/send-data.js +2 -2
  42. package/packages/dd-trace/src/tracer.js +1 -0
  43. package/packages/utils/src/kebabcase.js +16 -0
  44. package/packages/utils/src/pick.js +11 -0
  45. package/packages/utils/src/uniq.js +5 -0
  46. package/scripts/st.js +105 -0
@@ -2,7 +2,8 @@
2
2
  const { truncateSpan, normalizeSpan } = require('./tags-processors')
3
3
  const { AgentEncoder } = require('./0.4')
4
4
  const { version: ddTraceVersion } = require('../../../../package.json')
5
- const id = require('../../../dd-trace/src/id')
5
+ const { ITR_CORRELATION_ID } = require('../../src/plugins/util/test')
6
+ const id = require('../../src/id')
6
7
  const {
7
8
  distributionMetric,
8
9
  TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
@@ -45,7 +46,13 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
45
46
  }
46
47
 
47
48
  _encodeTestSuite (bytes, content) {
48
- this._encodeMapPrefix(bytes, TEST_SUITE_KEYS_LENGTH)
49
+ let keysLength = TEST_SUITE_KEYS_LENGTH
50
+ const itrCorrelationId = content.meta[ITR_CORRELATION_ID]
51
+ if (itrCorrelationId) {
52
+ keysLength++
53
+ }
54
+
55
+ this._encodeMapPrefix(bytes, keysLength)
49
56
  this._encodeString(bytes, 'type')
50
57
  this._encodeString(bytes, content.type)
51
58
 
@@ -58,6 +65,12 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
58
65
  this._encodeString(bytes, 'test_suite_id')
59
66
  this._encodeId(bytes, content.span_id)
60
67
 
68
+ if (itrCorrelationId) {
69
+ this._encodeString(bytes, ITR_CORRELATION_ID)
70
+ this._encodeString(bytes, itrCorrelationId)
71
+ delete content.meta[ITR_CORRELATION_ID]
72
+ }
73
+
61
74
  this._encodeString(bytes, 'error')
62
75
  this._encodeNumber(bytes, content.error)
63
76
  this._encodeString(bytes, 'name')
@@ -144,6 +157,10 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
144
157
  if (content.meta.test_suite_id) {
145
158
  totalKeysLength = totalKeysLength + 1
146
159
  }
160
+ const itrCorrelationId = content.meta[ITR_CORRELATION_ID]
161
+ if (itrCorrelationId) {
162
+ totalKeysLength = totalKeysLength + 1
163
+ }
147
164
  this._encodeMapPrefix(bytes, totalKeysLength)
148
165
  if (content.type) {
149
166
  this._encodeString(bytes, 'type')
@@ -194,6 +211,12 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
194
211
  delete content.meta.test_suite_id
195
212
  }
196
213
 
214
+ if (itrCorrelationId) {
215
+ this._encodeString(bytes, ITR_CORRELATION_ID)
216
+ this._encodeString(bytes, itrCorrelationId)
217
+ delete content.meta[ITR_CORRELATION_ID]
218
+ }
219
+
197
220
  this._encodeString(bytes, 'meta')
198
221
  this._encodeMap(bytes, content.meta)
199
222
  this._encodeString(bytes, 'metrics')
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const pick = require('lodash.pick')
3
+ const pick = require('../../../../utils/src/pick')
4
4
  const id = require('../../id')
5
5
  const DatadogSpanContext = require('../span_context')
6
6
  const log = require('../../log')
@@ -15,7 +15,8 @@ const {
15
15
  TEST_MODULE,
16
16
  getTestSuiteCommonTags,
17
17
  TEST_STATUS,
18
- TEST_SKIPPED_BY_ITR
18
+ TEST_SKIPPED_BY_ITR,
19
+ ITR_CORRELATION_ID
19
20
  } = require('./util/test')
20
21
  const Plugin = require('./plugin')
21
22
  const { COMPONENT } = require('../constants')
@@ -53,11 +54,13 @@ module.exports = class CiPlugin extends Plugin {
53
54
  if (!this.tracer._exporter || !this.tracer._exporter.getSkippableSuites) {
54
55
  return onDone({ err: new Error('CI Visibility was not initialized correctly') })
55
56
  }
56
- this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites) => {
57
+ this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites, itrCorrelationId) => {
57
58
  if (err) {
58
59
  log.error(`Skippable suites could not be fetched. ${err.message}`)
60
+ } else {
61
+ this.itrCorrelationId = itrCorrelationId
59
62
  }
60
- onDone({ err, skippableSuites })
63
+ onDone({ err, skippableSuites, itrCorrelationId })
61
64
  })
62
65
  })
63
66
 
@@ -95,6 +98,9 @@ module.exports = class CiPlugin extends Plugin {
95
98
  const testCommand = this.testSessionSpan.context()._tags[TEST_COMMAND]
96
99
  skippedSuites.forEach((testSuite) => {
97
100
  const testSuiteMetadata = getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, this.constructor.id)
101
+ if (this.itrCorrelationId) {
102
+ testSuiteMetadata[ITR_CORRELATION_ID] = this.itrCorrelationId
103
+ }
98
104
 
99
105
  this.tracer.startSpan(`${this.constructor.id}.test_suite`, {
100
106
  childOf: this.testModuleSpan,
@@ -60,6 +60,7 @@ const TEST_ITR_SKIPPING_COUNT = 'test.itr.tests_skipping.count'
60
60
  const TEST_CODE_COVERAGE_ENABLED = 'test.code_coverage.enabled'
61
61
  const TEST_ITR_UNSKIPPABLE = 'test.itr.unskippable'
62
62
  const TEST_ITR_FORCED_RUN = 'test.itr.forced_run'
63
+ const ITR_CORRELATION_ID = 'itr_correlation_id'
63
64
 
64
65
  const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
65
66
 
@@ -111,6 +112,7 @@ module.exports = {
111
112
  TEST_CODE_COVERAGE_LINES_PCT,
112
113
  TEST_ITR_UNSKIPPABLE,
113
114
  TEST_ITR_FORCED_RUN,
115
+ ITR_CORRELATION_ID,
114
116
  addIntelligentTestRunnerSpanTags,
115
117
  getCoveredFilenamesFromCoverage,
116
118
  resetCoverage,
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const uniq = require('lodash.uniq')
3
+ const uniq = require('../../../../utils/src/uniq')
4
4
  const analyticsSampler = require('../../analytics_sampler')
5
5
  const FORMAT_HTTP_HEADERS = 'http_headers'
6
6
  const log = require('../../log')
@@ -40,6 +40,7 @@ class Config {
40
40
  DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
41
41
  DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
42
42
  DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES,
43
+ DD_PROFILING_TIMELINE_ENABLED,
43
44
  DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED,
44
45
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
45
46
  DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
@@ -96,11 +97,15 @@ class Config {
96
97
  // depending on those (code hotspots and endpoint collection) need to default
97
98
  // to false on Windows.
98
99
  const samplingContextsAvailable = process.platform !== 'win32'
99
- function checkOptionAllowed (option, description) {
100
- if (option && !samplingContextsAvailable) {
100
+ function checkOptionAllowed (option, description, condition) {
101
+ if (option && !condition) {
101
102
  throw new Error(`${description} not supported on ${process.platform}.`)
102
103
  }
103
104
  }
105
+ function checkOptionWithSamplingContextAllowed (option, description) {
106
+ checkOptionAllowed(option, description, samplingContextsAvailable)
107
+ }
108
+
104
109
  this.flushInterval = flushInterval
105
110
  this.uploadTimeout = uploadTimeout
106
111
  this.sourceMap = sourceMap
@@ -109,7 +114,7 @@ class Config {
109
114
  DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
110
115
  DD_PROFILING_EXPERIMENTAL_ENDPOINT_COLLECTION_ENABLED, samplingContextsAvailable))
111
116
  logExperimentalVarDeprecation('ENDPOINT_COLLECTION_ENABLED')
112
- checkOptionAllowed(this.endpointCollectionEnabled, 'Endpoint collection')
117
+ checkOptionWithSamplingContextAllowed(this.endpointCollectionEnabled, 'Endpoint collection')
113
118
 
114
119
  this.pprofPrefix = pprofPrefix
115
120
  this.v8ProfilerBugWorkaroundEnabled = isTrue(coalesce(options.v8ProfilerBugWorkaround,
@@ -126,8 +131,13 @@ class Config {
126
131
  new AgentExporter(this)
127
132
  ], this)
128
133
 
134
+ // OOM monitoring does not work well on Windows, so it is disabled by default.
135
+ const oomMonitoringSupported = process.platform !== 'win32'
136
+
129
137
  const oomMonitoringEnabled = isTrue(coalesce(options.oomMonitoring,
130
- DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED, true))
138
+ DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED, oomMonitoringSupported))
139
+ checkOptionAllowed(oomMonitoringEnabled, 'OOM monitoring', oomMonitoringSupported)
140
+
131
141
  const heapLimitExtensionSize = coalesce(options.oomHeapLimitExtensionSize,
132
142
  Number(DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE), 0)
133
143
  const maxHeapExtensionCount = coalesce(options.oomMaxHeapExtensionCount,
@@ -154,16 +164,20 @@ class Config {
154
164
  })
155
165
 
156
166
  this.timelineEnabled = isTrue(coalesce(options.timelineEnabled,
167
+ DD_PROFILING_TIMELINE_ENABLED,
157
168
  DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED, false))
169
+ logExperimentalVarDeprecation('TIMELINE_ENABLED')
170
+ checkOptionWithSamplingContextAllowed(this.timelineEnabled, 'Timeline view')
158
171
 
159
172
  this.codeHotspotsEnabled = isTrue(coalesce(options.codeHotspotsEnabled,
160
173
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
161
174
  DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, samplingContextsAvailable))
162
175
  logExperimentalVarDeprecation('CODEHOTSPOTS_ENABLED')
163
- checkOptionAllowed(this.codeHotspotsEnabled, 'Code hotspots')
176
+ checkOptionWithSamplingContextAllowed(this.codeHotspotsEnabled, 'Code hotspots')
164
177
 
165
178
  this.cpuProfilingEnabled = isTrue(coalesce(options.cpuProfilingEnabled,
166
179
  DD_PROFILING_EXPERIMENTAL_CPU_ENABLED, false))
180
+ checkOptionWithSamplingContextAllowed(this.cpuProfilingEnabled, 'CPU profiling')
167
181
 
168
182
  this.profilers = ensureProfilers(profilers, this)
169
183
  }
@@ -140,8 +140,7 @@ function appStarted (config) {
140
140
  return app
141
141
  }
142
142
 
143
- function onBeforeExit () {
144
- process.removeListener('beforeExit', onBeforeExit)
143
+ function appClosing () {
145
144
  const { reqType, payload } = createPayload('app-closing')
146
145
  sendData(config, application, host, reqType, payload)
147
146
  // we flush before shutting down. Only in CI Visibility
@@ -150,6 +149,11 @@ function onBeforeExit () {
150
149
  }
151
150
  }
152
151
 
152
+ function onBeforeExit () {
153
+ process.removeListener('beforeExit', onBeforeExit)
154
+ appClosing()
155
+ }
156
+
153
157
  function createAppObject (config) {
154
158
  return {
155
159
  service_name: config.service,
@@ -339,5 +343,6 @@ module.exports = {
339
343
  start,
340
344
  stop,
341
345
  updateIntegrations,
342
- updateConfig
346
+ updateConfig,
347
+ appClosing
343
348
  }
@@ -1,6 +1,7 @@
1
1
 
2
2
  const request = require('../exporters/common/request')
3
3
  const log = require('../log')
4
+ const { isTrue } = require('../util')
4
5
 
5
6
  let agentTelemetry = true
6
7
 
@@ -49,13 +50,12 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
49
50
  const {
50
51
  hostname,
51
52
  port,
52
- experimental,
53
53
  isCiVisibility
54
54
  } = config
55
55
 
56
56
  let url = config.url
57
57
 
58
- const isCiVisibilityAgentlessMode = isCiVisibility && experimental?.exporter === 'datadog'
58
+ const isCiVisibilityAgentlessMode = isCiVisibility && isTrue(process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED)
59
59
 
60
60
  if (isCiVisibilityAgentlessMode) {
61
61
  try {
@@ -135,6 +135,7 @@ class DatadogTracer extends Tracer {
135
135
 
136
136
  setUrl (url) {
137
137
  this._exporter.setUrl(url)
138
+ this._dataStreamsProcessor.setUrl(url)
138
139
  }
139
140
 
140
141
  scope () {
@@ -0,0 +1,16 @@
1
+ 'use strict'
2
+
3
+ module.exports = str => {
4
+ if (typeof str !== 'string') {
5
+ throw new TypeError('Expected a string')
6
+ }
7
+
8
+ return str
9
+ .trim()
10
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
11
+ .replace(/\s+/g, '-')
12
+ .replace(/^-+|-+$/g, '')
13
+ .replace(/_/g, '-')
14
+ .replace(/-{2,}/g, '-')
15
+ .toLowerCase()
16
+ }
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ module.exports = (object, props) => {
4
+ const result = {}
5
+ props.forEach(prop => {
6
+ if (prop in object) {
7
+ result[prop] = object[prop]
8
+ }
9
+ })
10
+ return result
11
+ }
@@ -0,0 +1,5 @@
1
+ 'use strict'
2
+
3
+ module.exports = function (arr) {
4
+ return [...new Set(arr)]
5
+ }
package/scripts/st.js ADDED
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console, no-fallthrough */
3
+ 'use strict'
4
+
5
+ const path = require('path')
6
+ const { writeFileSync } = require('fs')
7
+ const { execSync } = require('child_process')
8
+
9
+ const ddtracePath = path.join(__dirname, '..')
10
+ const defaultTestPath = process.env.DD_ST_PATH || path.join(ddtracePath, '..', 'system-tests')
11
+
12
+ const { buildAll, npm, testDir, testArgs } = parseArgs()
13
+
14
+ const binariesPath = path.join(testDir, 'binaries')
15
+
16
+ if (npm) {
17
+ console.log('Using NPM package:', npm)
18
+
19
+ writeFileSync(path.join(binariesPath, 'nodejs-load-from-npm'), npm)
20
+ } else {
21
+ console.log('Using local repo')
22
+
23
+ const packName = execSync(`npm pack ${ddtracePath}`, {
24
+ cwd: binariesPath,
25
+ stdio: [null, null, 'inherit'],
26
+ encoding: 'utf8'
27
+ }).slice(0, -1) // remove trailing newline
28
+
29
+ writeFileSync(path.join(binariesPath, 'nodejs-load-from-npm'), `/binaries/${packName}`)
30
+ }
31
+
32
+ try {
33
+ execSync(`./build.sh ${buildAll ? '' : '-i weblog'} && ./run.sh ${testArgs}`, {
34
+ cwd: testDir,
35
+ stdio: [null, 'inherit', 'inherit']
36
+ })
37
+ } catch (err) {
38
+ process.exit(err.status || 1)
39
+ }
40
+
41
+ function parseArgs () {
42
+ const args = {
43
+ buildAll: false,
44
+ npm: null,
45
+ testDir: defaultTestPath,
46
+ testArgs: ''
47
+ }
48
+
49
+ for (let i = 2; i < process.argv.length; i++) {
50
+ switch (process.argv[i]) {
51
+ case '-b':
52
+ case '--build-all':
53
+ args.buildAll = true
54
+ break
55
+
56
+ case '-h':
57
+ case '--help':
58
+ helpAndExit()
59
+ break
60
+
61
+ case '-n':
62
+ case '--npm': {
63
+ const arg = process.argv[i + 1]
64
+ if (!arg || arg[0] === '-') {
65
+ args.npm = 'dd-trace'
66
+ } else {
67
+ args.npm = arg
68
+ i++
69
+ }
70
+ break
71
+ }
72
+
73
+ case '-t':
74
+ case '--test-dir': {
75
+ const arg = process.argv[++i]
76
+ if (!arg || arg[0] === '-') helpAndExit()
77
+ args.testDir = arg
78
+ break
79
+ }
80
+
81
+ case '--':
82
+ args.testArgs = process.argv.slice(i + 1).join(' ')
83
+ return args
84
+
85
+ default:
86
+ console.log('Unknown option:', process.argv[i], '\n')
87
+ helpAndExit()
88
+ }
89
+ }
90
+
91
+ return args
92
+ }
93
+
94
+ function helpAndExit () {
95
+ console.log('Usage: node st.js [options...] [-- test-args]')
96
+ console.log('Options:')
97
+ console.log(' -b, --build-all Rebuild all images (default: only build weblog)')
98
+ console.log(' -h, --help Print this message')
99
+ console.log(' -n, --npm [package] Build a remote package instead of the local repo (default: "dd-trace")')
100
+ console.log(' Can be a package name (e.g. "dd-trace@4.2.0") or a git URL (e.g.')
101
+ console.log(' "git+https://github.com/DataDog/dd-trace-js.git#mybranch")')
102
+ console.log(' -t, --test-dir <path> Specify the system-tests directory (default: "dd-trace/../system-tests/")')
103
+ console.log(' -- <test-args> Passed to system-tests run.sh (e.g. "-- SCENARIO_NAME tests/path_to_test.py")')
104
+ process.exit()
105
+ }