dd-trace 5.35.0 → 5.36.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 (84) hide show
  1. package/index.d.ts +3 -7
  2. package/package.json +4 -4
  3. package/packages/datadog-core/index.js +1 -1
  4. package/packages/datadog-core/src/storage.js +76 -31
  5. package/packages/datadog-instrumentations/src/jest.js +3 -7
  6. package/packages/datadog-plugin-aerospike/src/index.js +1 -1
  7. package/packages/datadog-plugin-apollo/src/gateway/fetch.js +1 -1
  8. package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
  9. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -1
  10. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
  11. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -4
  12. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
  13. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  14. package/packages/datadog-plugin-couchbase/src/index.js +2 -2
  15. package/packages/datadog-plugin-cucumber/src/index.js +11 -11
  16. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -1
  17. package/packages/datadog-plugin-cypress/src/support.js +36 -29
  18. package/packages/datadog-plugin-grpc/src/client.js +1 -1
  19. package/packages/datadog-plugin-grpc/src/server.js +1 -1
  20. package/packages/datadog-plugin-hapi/src/index.js +1 -1
  21. package/packages/datadog-plugin-http/src/client.js +1 -1
  22. package/packages/datadog-plugin-http/src/server.js +1 -1
  23. package/packages/datadog-plugin-http2/src/client.js +3 -3
  24. package/packages/datadog-plugin-http2/src/server.js +1 -1
  25. package/packages/datadog-plugin-jest/src/index.js +6 -11
  26. package/packages/datadog-plugin-langchain/src/tracing.js +1 -1
  27. package/packages/datadog-plugin-mariadb/src/index.js +3 -3
  28. package/packages/datadog-plugin-mocha/src/index.js +13 -13
  29. package/packages/datadog-plugin-next/src/index.js +4 -4
  30. package/packages/datadog-plugin-openai/src/tracing.js +1 -1
  31. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  32. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  33. package/packages/datadog-plugin-router/src/index.js +2 -2
  34. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  35. package/packages/datadog-plugin-vitest/src/index.js +11 -11
  36. package/packages/dd-trace/src/appsec/graphql.js +6 -6
  37. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +1 -1
  38. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +6 -6
  39. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +2 -2
  40. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +5 -5
  41. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +2 -2
  42. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -2
  43. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +2 -2
  44. package/packages/dd-trace/src/appsec/iast/index.js +2 -2
  45. package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
  46. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -8
  47. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +1 -1
  48. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +65 -0
  49. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +14 -5
  50. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +80 -2
  51. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  52. package/packages/dd-trace/src/appsec/index.js +4 -4
  53. package/packages/dd-trace/src/appsec/rasp/command_injection.js +1 -1
  54. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
  55. package/packages/dd-trace/src/appsec/rasp/lfi.js +1 -1
  56. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +2 -2
  57. package/packages/dd-trace/src/appsec/rasp/ssrf.js +1 -1
  58. package/packages/dd-trace/src/appsec/reporter.js +3 -3
  59. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  60. package/packages/dd-trace/src/appsec/waf/index.js +1 -1
  61. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +2 -0
  62. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +17 -10
  63. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
  64. package/packages/dd-trace/src/config.js +2 -0
  65. package/packages/dd-trace/src/data_streams_context.js +2 -2
  66. package/packages/dd-trace/src/exporters/common/agents.js +1 -1
  67. package/packages/dd-trace/src/exporters/common/request.js +3 -3
  68. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +1 -1
  69. package/packages/dd-trace/src/log/writer.js +3 -3
  70. package/packages/dd-trace/src/noop/span.js +1 -1
  71. package/packages/dd-trace/src/opentracing/propagation/text_map.js +5 -4
  72. package/packages/dd-trace/src/opentracing/span.js +1 -1
  73. package/packages/dd-trace/src/plugin_manager.js +3 -1
  74. package/packages/dd-trace/src/plugins/apollo.js +1 -1
  75. package/packages/dd-trace/src/plugins/ci_plugin.js +35 -1
  76. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  77. package/packages/dd-trace/src/plugins/plugin.js +8 -8
  78. package/packages/dd-trace/src/plugins/tracing.js +3 -3
  79. package/packages/dd-trace/src/plugins/util/git.js +3 -3
  80. package/packages/dd-trace/src/plugins/util/test.js +5 -1
  81. package/packages/dd-trace/src/profiling/exporters/agent.js +3 -3
  82. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  83. package/packages/dd-trace/src/scope.js +5 -5
  84. package/packages/dd-trace/src/tracer.js +0 -14
@@ -325,6 +325,7 @@ class TextMapPropagator {
325
325
  if (context === null) {
326
326
  context = extractedContext
327
327
  if (this._config.tracePropagationExtractFirst) {
328
+ this._extractBaggageItems(carrier, context)
328
329
  return context
329
330
  }
330
331
  } else {
@@ -344,10 +345,7 @@ class TextMapPropagator {
344
345
  }
345
346
  }
346
347
 
347
- if (this._hasPropagationStyle('extract', 'baggage') && carrier.baggage) {
348
- context = context || new DatadogSpanContext()
349
- this._extractBaggageItems(carrier, context)
350
- }
348
+ this._extractBaggageItems(carrier, context)
351
349
 
352
350
  return context || this._extractSqsdContext(carrier)
353
351
  }
@@ -596,6 +594,9 @@ class TextMapPropagator {
596
594
  }
597
595
 
598
596
  _extractBaggageItems (carrier, spanContext) {
597
+ if (!this._hasPropagationStyle('extract', 'baggage')) return
598
+ if (!carrier || !carrier.baggage) return
599
+ if (!spanContext) return
599
600
  const baggages = carrier.baggage.split(',')
600
601
  for (const keyValue of baggages) {
601
602
  if (!keyValue.includes('=')) {
@@ -65,7 +65,7 @@ class DatadogSpan {
65
65
  this._debug = debug
66
66
  this._processor = processor
67
67
  this._prioritySampler = prioritySampler
68
- this._store = storage.getHandle()
68
+ this._store = storage('legacy').getHandle()
69
69
  this._duration = undefined
70
70
 
71
71
  this._events = []
@@ -143,6 +143,7 @@ module.exports = class PluginManager {
143
143
  ciVisibilityTestSessionName,
144
144
  ciVisAgentlessLogSubmissionEnabled,
145
145
  isTestDynamicInstrumentationEnabled,
146
+ isServiceUserProvided,
146
147
  middlewareTracingEnabled
147
148
  } = this._tracerConfig
148
149
 
@@ -155,7 +156,8 @@ module.exports = class PluginManager {
155
156
  headers: headerTags || [],
156
157
  ciVisibilityTestSessionName,
157
158
  ciVisAgentlessLogSubmissionEnabled,
158
- isTestDynamicInstrumentationEnabled
159
+ isTestDynamicInstrumentationEnabled,
160
+ isServiceUserProvided
159
161
  }
160
162
 
161
163
  if (logInjection !== undefined) {
@@ -7,7 +7,7 @@ class ApolloBasePlugin extends TracingPlugin {
7
7
  static get kind () { return 'server' }
8
8
 
9
9
  bindStart (ctx) {
10
- const store = storage.getStore()
10
+ const store = storage('legacy').getStore()
11
11
  const childOf = store ? store.span : null
12
12
 
13
13
  const span = this.startSpan(this.getOperationName(), {
@@ -45,6 +45,7 @@ module.exports = class CiPlugin extends Plugin {
45
45
  constructor (...args) {
46
46
  super(...args)
47
47
 
48
+ this.fileLineToProbeId = new Map()
48
49
  this.rootDir = process.cwd() // fallback in case :session:start events are not emitted
49
50
 
50
51
  this.addSub(`ci:${this.constructor.id}:library-configuration`, ({ onDone }) => {
@@ -335,7 +336,22 @@ module.exports = class CiPlugin extends Plugin {
335
336
  })
336
337
  }
337
338
 
338
- removeDiProbe (probeId) {
339
+ removeAllDiProbes () {
340
+ if (this.fileLineToProbeId.size === 0) {
341
+ return Promise.resolve()
342
+ }
343
+ log.debug('Removing all Dynamic Instrumentation probes')
344
+ return Promise.all(Array.from(this.fileLineToProbeId.keys())
345
+ .map((fileLine) => {
346
+ const [file, line] = fileLine.split(':')
347
+ return this.removeDiProbe({ file, line })
348
+ }))
349
+ }
350
+
351
+ removeDiProbe ({ file, line }) {
352
+ const probeId = this.fileLineToProbeId.get(`${file}:${line}`)
353
+ log.warn(`Removing probe from ${file}:${line}, with id: ${probeId}`)
354
+ this.fileLineToProbeId.delete(probeId)
339
355
  return this.di.removeProbe(probeId)
340
356
  }
341
357
 
@@ -346,9 +362,27 @@ module.exports = class CiPlugin extends Plugin {
346
362
  log.warn('Could not add breakpoint for dynamic instrumentation')
347
363
  return
348
364
  }
365
+ log.debug('Adding breakpoint for Dynamic Instrumentation')
366
+
367
+ this.testErrorStackIndex = stackIndex
368
+ const activeProbeKey = `${file}:${line}`
369
+
370
+ if (this.fileLineToProbeId.has(activeProbeKey)) {
371
+ log.warn('Probe already set for this line')
372
+ const oldProbeId = this.fileLineToProbeId.get(activeProbeKey)
373
+ return {
374
+ probeId: oldProbeId,
375
+ setProbePromise: Promise.resolve(),
376
+ stackIndex,
377
+ file,
378
+ line
379
+ }
380
+ }
349
381
 
350
382
  const [probeId, setProbePromise] = this.di.addLineProbe({ file, line }, this.onDiBreakpointHit.bind(this))
351
383
 
384
+ this.fileLineToProbeId.set(activeProbeKey, probeId)
385
+
352
386
  return {
353
387
  probeId,
354
388
  setProbePromise,
@@ -40,7 +40,7 @@ module.exports = class LogPlugin extends Plugin {
40
40
  super(...args)
41
41
 
42
42
  this.addSub(`apm:${this.constructor.id}:log`, (arg) => {
43
- const store = storage.getStore()
43
+ const store = storage('legacy').getStore()
44
44
  const span = store && store.span
45
45
 
46
46
  // NOTE: This needs to run whether or not there is a span
@@ -10,7 +10,7 @@ class Subscription {
10
10
  constructor (event, handler) {
11
11
  this._channel = dc.channel(event)
12
12
  this._handler = (message, name) => {
13
- const store = storage.getStore()
13
+ const store = storage('legacy').getStore()
14
14
  if (!store || !store.noop) {
15
15
  handler(message, name)
16
16
  }
@@ -30,7 +30,7 @@ class StoreBinding {
30
30
  constructor (event, transform) {
31
31
  this._channel = dc.channel(event)
32
32
  this._transform = data => {
33
- const store = storage.getStore()
33
+ const store = storage('legacy').getStore()
34
34
 
35
35
  return !store || !store.noop
36
36
  ? transform(data)
@@ -39,11 +39,11 @@ class StoreBinding {
39
39
  }
40
40
 
41
41
  enable () {
42
- this._channel.bindStore(storage, this._transform)
42
+ this._channel.bindStore(storage('legacy'), this._transform)
43
43
  }
44
44
 
45
45
  disable () {
46
- this._channel.unbindStore(storage, this._transform)
46
+ this._channel.unbindStore(storage('legacy'))
47
47
  }
48
48
  }
49
49
 
@@ -62,14 +62,14 @@ module.exports = class Plugin {
62
62
  }
63
63
 
64
64
  enter (span, store) {
65
- store = store || storage.getStore()
66
- storage.enterWith({ ...store, span })
65
+ store = store || storage('legacy').getStore()
66
+ storage('legacy').enterWith({ ...store, span })
67
67
  }
68
68
 
69
69
  // TODO: Implement filters on resource name for all plugins.
70
70
  /** Prevents creation of spans here and for all async descendants. */
71
71
  skip () {
72
- storage.enterWith({ noop: true })
72
+ storage('legacy').enterWith({ noop: true })
73
73
  }
74
74
 
75
75
  addSub (channelName, handler) {
@@ -91,7 +91,7 @@ module.exports = class Plugin {
91
91
  }
92
92
 
93
93
  addError (error) {
94
- const store = storage.getStore()
94
+ const store = storage('legacy').getStore()
95
95
 
96
96
  if (!store || !store.span) return
97
97
 
@@ -16,7 +16,7 @@ class TracingPlugin extends Plugin {
16
16
  }
17
17
 
18
18
  get activeSpan () {
19
- const store = storage.getStore()
19
+ const store = storage('legacy').getStore()
20
20
 
21
21
  return store && store.span
22
22
  }
@@ -102,7 +102,7 @@ class TracingPlugin extends Plugin {
102
102
  }
103
103
 
104
104
  startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}, enter = true) {
105
- const store = storage.getStore()
105
+ const store = storage('legacy').getStore()
106
106
  if (store && childOf === undefined) {
107
107
  childOf = store.span
108
108
  }
@@ -126,7 +126,7 @@ class TracingPlugin extends Plugin {
126
126
 
127
127
  // TODO: Remove this after migration to TracingChannel is done.
128
128
  if (enter) {
129
- storage.enterWith({ ...store, span })
129
+ storage('legacy').enterWith({ ...store, span })
130
130
  }
131
131
 
132
132
  return span
@@ -37,8 +37,8 @@ function sanitizedExec (
37
37
  durationMetric,
38
38
  errorMetric
39
39
  ) {
40
- const store = storage.getStore()
41
- storage.enterWith({ noop: true })
40
+ const store = storage('legacy').getStore()
41
+ storage('legacy').enterWith({ noop: true })
42
42
 
43
43
  let startTime
44
44
  if (operationMetric) {
@@ -64,7 +64,7 @@ function sanitizedExec (
64
64
  log.error('Git plugin error executing command', err)
65
65
  return ''
66
66
  } finally {
67
- storage.enterWith(store)
67
+ storage('legacy').enterWith(store)
68
68
  }
69
69
  }
70
70
 
@@ -108,6 +108,8 @@ const TEST_LEVEL_EVENT_TYPES = [
108
108
  'test_session_end'
109
109
  ]
110
110
 
111
+ const DD_TEST_IS_USER_PROVIDED_SERVICE = '_dd.test.is_user_provided_service'
112
+
111
113
  // Dynamic instrumentation - Test optimization integration tags
112
114
  const DI_ERROR_DEBUG_INFO_CAPTURED = 'error.debug_info_captured'
113
115
  const DI_DEBUG_ERROR_PREFIX = '_dd.debug.error'
@@ -199,7 +201,8 @@ module.exports = {
199
201
  DI_DEBUG_ERROR_SNAPSHOT_ID_SUFFIX,
200
202
  DI_DEBUG_ERROR_FILE_SUFFIX,
201
203
  DI_DEBUG_ERROR_LINE_SUFFIX,
202
- getFormattedError
204
+ getFormattedError,
205
+ DD_TEST_IS_USER_PROVIDED_SERVICE
203
206
  }
204
207
 
205
208
  // Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
@@ -275,6 +278,7 @@ function getTestEnvironmentMetadata (testFramework, config) {
275
278
 
276
279
  const metadata = {
277
280
  [TEST_FRAMEWORK]: testFramework,
281
+ [DD_TEST_IS_USER_PROVIDED_SERVICE]: (config && config.isServiceUserProvided) ? 'true' : 'false',
278
282
  ...gitMetadata,
279
283
  ...ciMetadata,
280
284
  ...userProvidedGitMetadata,
@@ -40,8 +40,8 @@ function countStatusCode (statusCode) {
40
40
  function sendRequest (options, form, callback) {
41
41
  const request = options.protocol === 'https:' ? httpsRequest : httpRequest
42
42
 
43
- const store = storage.getStore()
44
- storage.enterWith({ noop: true })
43
+ const store = storage('legacy').getStore()
44
+ storage('legacy').enterWith({ noop: true })
45
45
  requestCounter.inc()
46
46
  const start = perf.now()
47
47
  const req = request(options, res => {
@@ -65,7 +65,7 @@ function sendRequest (options, form, callback) {
65
65
  sizeDistribution.track(form.size())
66
66
  form.pipe(req)
67
67
  }
68
- storage.enterWith(store)
68
+ storage('legacy').enterWith(store)
69
69
  }
70
70
 
71
71
  function getBody (stream, callback) {
@@ -25,7 +25,7 @@ const ProfilingContext = Symbol('NativeWallProfiler.ProfilingContext')
25
25
  let kSampleCount
26
26
 
27
27
  function getActiveSpan () {
28
- const store = storage.getStore()
28
+ const store = storage('legacy').getStore()
29
29
  return store && store.span
30
30
  }
31
31
 
@@ -8,7 +8,7 @@ const originals = new WeakMap()
8
8
 
9
9
  class Scope {
10
10
  active () {
11
- const store = storage.getStore()
11
+ const store = storage('legacy').getStore()
12
12
 
13
13
  return (store && store.span) || null
14
14
  }
@@ -16,10 +16,10 @@ class Scope {
16
16
  activate (span, callback) {
17
17
  if (typeof callback !== 'function') return callback
18
18
 
19
- const oldStore = storage.getStore()
20
- const newStore = span ? storage.getStore(span._store) : oldStore
19
+ const oldStore = storage('legacy').getStore()
20
+ const newStore = span ? storage('legacy').getStore(span._store) : oldStore
21
21
 
22
- storage.enterWith({ ...newStore, span })
22
+ storage('legacy').enterWith({ ...newStore, span })
23
23
 
24
24
  try {
25
25
  return callback()
@@ -30,7 +30,7 @@ class Scope {
30
30
 
31
31
  throw e
32
32
  } finally {
33
- storage.enterWith(oldStore)
33
+ storage('legacy').enterWith(oldStore)
34
34
  }
35
35
  }
36
36
 
@@ -3,13 +3,11 @@
3
3
  const Tracer = require('./opentracing/tracer')
4
4
  const tags = require('../../../ext/tags')
5
5
  const Scope = require('./scope')
6
- const { storage } = require('../../datadog-core')
7
6
  const { isError } = require('./util')
8
7
  const { setStartupLogConfig } = require('./startup-log')
9
8
  const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
10
9
  const { DataStreamsProcessor } = require('./datastreams/processor')
11
10
  const { DsmPathwayCodec } = require('./datastreams/pathway')
12
- const { DD_MAJOR } = require('../../../version')
13
11
  const DataStreamsContext = require('./data_streams_context')
14
12
  const { DataStreamsCheckpointer } = require('./data_streams')
15
13
  const { flushStartupLogs } = require('../../datadog-instrumentations/src/check_require_cache')
@@ -60,10 +58,6 @@ class DatadogTracer extends Tracer {
60
58
  childOf: this.scope().active()
61
59
  }, options)
62
60
 
63
- if (!options.childOf && options.orphanable === false && DD_MAJOR < 4) {
64
- return fn(null, () => {})
65
- }
66
-
67
61
  const span = this.startSpan(name, options)
68
62
 
69
63
  addTags(span, options)
@@ -106,19 +100,11 @@ class DatadogTracer extends Tracer {
106
100
  const tracer = this
107
101
 
108
102
  return function () {
109
- const store = storage.getStore()
110
-
111
- if (store && store.noop) return fn.apply(this, arguments)
112
-
113
103
  let optionsObj = options
114
104
  if (typeof optionsObj === 'function' && typeof fn === 'function') {
115
105
  optionsObj = optionsObj.apply(this, arguments)
116
106
  }
117
107
 
118
- if (optionsObj && optionsObj.orphanable === false && !tracer.scope().active() && DD_MAJOR < 4) {
119
- return fn.apply(this, arguments)
120
- }
121
-
122
108
  const lastArgId = arguments.length - 1
123
109
  const cb = arguments[lastArgId]
124
110