dd-trace 3.48.0 → 3.50.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 (44) hide show
  1. package/CONTRIBUTING.md +98 -0
  2. package/README.md +4 -102
  3. package/ci/cypress/after-run.js +1 -0
  4. package/package.json +2 -2
  5. package/packages/datadog-instrumentations/src/cucumber.js +156 -42
  6. package/packages/datadog-instrumentations/src/jest.js +84 -49
  7. package/packages/datadog-instrumentations/src/mocha.js +139 -13
  8. package/packages/datadog-plugin-amqplib/src/consumer.js +5 -2
  9. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +60 -50
  10. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +40 -17
  11. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +62 -26
  12. package/packages/datadog-plugin-cucumber/src/index.js +25 -9
  13. package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
  14. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +560 -0
  15. package/packages/datadog-plugin-cypress/src/plugin.js +6 -533
  16. package/packages/datadog-plugin-jest/src/index.js +4 -8
  17. package/packages/datadog-plugin-kafkajs/src/consumer.js +16 -0
  18. package/packages/datadog-plugin-mocha/src/index.js +38 -17
  19. package/packages/datadog-plugin-rhea/src/consumer.js +4 -1
  20. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +90 -0
  21. package/packages/dd-trace/src/appsec/iast/context/kafka-ctx-plugin.js +14 -0
  22. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +8 -0
  23. package/packages/dd-trace/src/appsec/iast/index.js +4 -4
  24. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
  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/index.js +10 -0
  27. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +53 -0
  28. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -46
  29. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +13 -9
  30. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +47 -0
  31. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +3 -1
  32. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +29 -2
  33. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  34. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  35. package/packages/dd-trace/src/appsec/remote_config/index.js +1 -0
  36. package/packages/dd-trace/src/config.js +3 -2
  37. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -1
  38. package/packages/dd-trace/src/opentracing/span.js +4 -4
  39. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -1
  40. package/packages/dd-trace/src/plugins/util/test.js +17 -1
  41. package/packages/dd-trace/src/profiling/exporters/agent.js +40 -31
  42. package/packages/dd-trace/src/telemetry/index.js +3 -0
  43. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  44. package/packages/dd-trace/src/telemetry/send-data.js +0 -3
@@ -14,6 +14,7 @@ function enable (config) {
14
14
  rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_HTTP_HEADER_TAGS, true)
15
15
  rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_LOGS_INJECTION, true)
16
16
  rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_SAMPLE_RATE, true)
17
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_ENABLED, true)
17
18
 
18
19
  const activation = Activation.fromConfig(config)
19
20
 
@@ -209,10 +209,12 @@ class Config {
209
209
 
210
210
  const inServerlessEnvironment = inAWSLambda || isGCPFunction || isAzureFunctionConsumptionPlan
211
211
 
212
+ const isJestWorker = !!process.env.JEST_WORKER_ID
213
+
212
214
  const DD_INSTRUMENTATION_TELEMETRY_ENABLED = coalesce(
213
215
  process.env.DD_TRACE_TELEMETRY_ENABLED, // for backward compatibility
214
216
  process.env.DD_INSTRUMENTATION_TELEMETRY_ENABLED, // to comply with instrumentation telemetry specs
215
- !inServerlessEnvironment
217
+ !(inServerlessEnvironment || isJestWorker)
216
218
  )
217
219
  const DD_TELEMETRY_HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
218
220
  ? Math.floor(parseFloat(process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL) * 1000)
@@ -611,7 +613,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
611
613
  this.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
612
614
  this.lookup = options.lookup
613
615
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
614
- // Disabled for CI Visibility's agentless
615
616
  this.telemetry = {
616
617
  enabled: isTrue(DD_INSTRUMENTATION_TELEMETRY_ENABLED),
617
618
  heartbeatInterval: DD_TELEMETRY_HEARTBEAT_INTERVAL,
@@ -173,7 +173,7 @@ class TextMapPropagator {
173
173
  ts.forVendor('dd', state => {
174
174
  state.set('s', priority)
175
175
  if (mechanism) {
176
- state.set('t.dm', mechanism)
176
+ state.set('t.dm', `-${mechanism}`)
177
177
  }
178
178
 
179
179
  if (typeof origin === 'string') {
@@ -29,8 +29,8 @@ const OTEL_ENABLED = !!process.env.DD_TRACE_OTEL_ENABLED
29
29
  const ALLOWED = ['string', 'number', 'boolean']
30
30
 
31
31
  const integrationCounters = {
32
- span_created: {},
33
- span_finished: {}
32
+ spans_created: {},
33
+ spans_finished: {}
34
34
  }
35
35
 
36
36
  const finishCh = channel('dd-trace:span:finish')
@@ -72,7 +72,7 @@ class DatadogSpan {
72
72
  this._name = operationName
73
73
  this._integrationName = fields.integrationName || 'opentracing'
74
74
 
75
- getIntegrationCounter('span_created', this._integrationName).inc()
75
+ getIntegrationCounter('spans_created', this._integrationName).inc()
76
76
 
77
77
  this._spanContext = this._createContext(parent, fields)
78
78
  this._spanContext._name = operationName
@@ -172,7 +172,7 @@ class DatadogSpan {
172
172
  }
173
173
  }
174
174
 
175
- getIntegrationCounter('span_finished', this._integrationName).inc()
175
+ getIntegrationCounter('spans_finished', this._integrationName).inc()
176
176
 
177
177
  if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
178
178
  runtimeMetrics.decrement('runtime.node.spans.unfinished')
@@ -51,7 +51,7 @@ module.exports = class CiPlugin extends Plugin {
51
51
  })
52
52
 
53
53
  this.addSub(`ci:${this.constructor.id}:test-suite:skippable`, ({ onDone }) => {
54
- if (!this.tracer._exporter || !this.tracer._exporter.getSkippableSuites) {
54
+ if (!this.tracer._exporter?.getSkippableSuites) {
55
55
  return onDone({ err: new Error('CI Visibility was not initialized correctly') })
56
56
  }
57
57
  this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites, itrCorrelationId) => {
@@ -74,6 +74,10 @@ const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
74
74
  const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
75
75
  const JEST_WORKER_COVERAGE_PAYLOAD_CODE = 61
76
76
 
77
+ // Early flake detection util strings
78
+ const EFD_STRING = "Retried by Datadog's Early Flake Detection"
79
+ const EFD_TEST_NAME_REGEX = new RegExp(EFD_STRING + ' \\(#\\d+\\): ', 'g')
80
+
77
81
  module.exports = {
78
82
  TEST_CODE_OWNERS,
79
83
  TEST_FRAMEWORK,
@@ -131,7 +135,11 @@ module.exports = {
131
135
  getTestLineStart,
132
136
  getCallSites,
133
137
  removeInvalidMetadata,
134
- parseAnnotations
138
+ parseAnnotations,
139
+ EFD_STRING,
140
+ EFD_TEST_NAME_REGEX,
141
+ removeEfdStringFromTestName,
142
+ addEfdStringToTestName
135
143
  }
136
144
 
137
145
  // Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
@@ -552,3 +560,11 @@ function parseAnnotations (annotations) {
552
560
  return tags
553
561
  }, {})
554
562
  }
563
+
564
+ function addEfdStringToTestName (testName, numAttempt) {
565
+ return `${EFD_STRING} (#${numAttempt}): ${testName}`
566
+ }
567
+
568
+ function removeEfdStringFromTestName (testName) {
569
+ return testName.replace(EFD_TEST_NAME_REGEX, '')
570
+ }
@@ -61,45 +61,50 @@ class AgentExporter {
61
61
  }
62
62
 
63
63
  export ({ profiles, start, end, tags }) {
64
- const types = Object.keys(profiles)
65
-
66
- const fields = [
67
- ['recording-start', start.toISOString()],
68
- ['recording-end', end.toISOString()],
69
- ['language', 'javascript'],
70
- ['runtime', 'nodejs'],
71
- ['runtime_version', process.version],
72
- ['profiler_version', version],
73
- ['format', 'pprof'],
74
-
75
- ['tags[]', 'language:javascript'],
76
- ['tags[]', 'runtime:nodejs'],
77
- ['tags[]', `runtime_version:${process.version}`],
78
- ['tags[]', `process_id:${process.pid}`],
79
- ['tags[]', `profiler_version:${version}`],
80
- ['tags[]', 'format:pprof'],
81
- ...Object.entries(tags).map(([key, value]) => ['tags[]', `${key}:${value}`])
82
- ]
64
+ const fields = []
83
65
 
84
- this._logger.debug(() => {
85
- const body = fields.map(([key, value]) => ` ${key}: ${value}`).join('\n')
86
- return `Building agent export report: ${'\n' + body}`
66
+ function typeToFile (type) {
67
+ return `${type}.pprof`
68
+ }
69
+
70
+ const event = JSON.stringify({
71
+ attachments: Object.keys(profiles).map(typeToFile),
72
+ start: start.toISOString(),
73
+ end: end.toISOString(),
74
+ family: 'node',
75
+ version: '4',
76
+ tags_profiler: [
77
+ 'language:javascript',
78
+ 'runtime:nodejs',
79
+ `runtime_arch:${process.arch}`,
80
+ `runtime_os:${process.platform}`,
81
+ `runtime_version:${process.version}`,
82
+ `process_id:${process.pid}`,
83
+ `profiler_version:${version}`,
84
+ 'format:pprof',
85
+ ...Object.entries(tags).map(([key, value]) => `${key}:${value}`)
86
+ ].join(',')
87
87
  })
88
88
 
89
- for (let index = 0; index < types.length; index++) {
90
- const type = types[index]
91
- const buffer = profiles[type]
89
+ fields.push(['event', event, {
90
+ filename: 'event.json',
91
+ contentType: 'application/json'
92
+ }])
93
+
94
+ this._logger.debug(() => {
95
+ return `Building agent export report:\n${event}`
96
+ })
92
97
 
98
+ for (const [type, buffer] of Object.entries(profiles)) {
93
99
  this._logger.debug(() => {
94
100
  const bytes = buffer.toString('hex').match(/../g).join(' ')
95
101
  return `Adding ${type} profile to agent export: ` + bytes
96
102
  })
97
103
 
98
- fields.push([`types[${index}]`, type])
99
- fields.push([`data[${index}]`, buffer, {
100
- filename: `${type}.pb.gz`,
101
- contentType: 'application/octet-stream',
102
- knownLength: buffer.length
104
+ const filename = typeToFile(type)
105
+ fields.push([filename, buffer, {
106
+ filename,
107
+ contentType: 'application/octet-stream'
103
108
  }])
104
109
  }
105
110
 
@@ -121,7 +126,11 @@ class AgentExporter {
121
126
  const options = {
122
127
  method: 'POST',
123
128
  path: '/profiling/v1/input',
124
- headers: form.getHeaders(),
129
+ headers: {
130
+ 'DD-EVP-ORIGIN': 'dd-trace-js',
131
+ 'DD-EVP-ORIGIN-VERSION': version,
132
+ ...form.getHeaders()
133
+ },
125
134
  timeout: this._backoffTime * Math.pow(2, attempt)
126
135
  }
127
136
 
@@ -6,6 +6,7 @@ const dependencies = require('./dependencies')
6
6
  const { sendData } = require('./send-data')
7
7
  const { errors } = require('../startup-log')
8
8
  const { manager: metricsManager } = require('./metrics')
9
+ const logs = require('./logs')
9
10
 
10
11
  const telemetryStartChannel = dc.channel('datadog:telemetry:start')
11
12
  const telemetryStopChannel = dc.channel('datadog:telemetry:stop')
@@ -226,6 +227,7 @@ function createPayload (currReqType, currPayload = {}) {
226
227
  function heartbeat (config, application, host) {
227
228
  heartbeatTimeout = setTimeout(() => {
228
229
  metricsManager.send(config, application, host)
230
+ logs.send(config, application, host)
229
231
 
230
232
  const { reqType, payload } = createPayload('app-heartbeat')
231
233
  sendData(config, application, host, reqType, payload, updateRetryData)
@@ -259,6 +261,7 @@ function start (aConfig, thePluginManager) {
259
261
  integrations = getIntegrations()
260
262
 
261
263
  dependencies.start(config, application, host, getRetryData, updateRetryData)
264
+ logs.start(config)
262
265
 
263
266
  sendData(config, application, host, 'app-started', appStarted(config))
264
267
 
@@ -52,9 +52,9 @@ function stop () {
52
52
  function send (config, application, host) {
53
53
  if (!enabled) return
54
54
 
55
- const logs = { 'logs': logCollector.drain() }
55
+ const logs = logCollector.drain()
56
56
  if (logs) {
57
- sendData(config, application, host, 'logs', logs)
57
+ sendData(config, application, host, 'logs', { logs })
58
58
  }
59
59
  }
60
60
 
@@ -27,9 +27,6 @@ function getAgentlessTelemetryEndpoint (site) {
27
27
  if (site === 'datad0g.com') { // staging
28
28
  return 'https://all-http-intake.logs.datad0g.com'
29
29
  }
30
- if (site === 'datadoghq.eu') {
31
- return 'https://instrumentation-telemetry-intake.eu1.datadoghq.com'
32
- }
33
30
  return `https://instrumentation-telemetry-intake.${site}`
34
31
  }
35
32