dd-trace 5.45.0 → 5.47.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 (86) hide show
  1. package/LICENSE-3rdparty.csv +1 -2
  2. package/ci/init.js +8 -0
  3. package/ext/exporters.d.ts +2 -1
  4. package/ext/exporters.js +2 -1
  5. package/package.json +8 -9
  6. package/packages/datadog-instrumentations/orchestrion.yml +52 -0
  7. package/packages/datadog-instrumentations/src/cucumber.js +2 -1
  8. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  9. package/packages/datadog-instrumentations/src/helpers/register.js +41 -1
  10. package/packages/datadog-instrumentations/src/jest.js +11 -2
  11. package/packages/datadog-instrumentations/src/langchain.js +49 -53
  12. package/packages/datadog-instrumentations/src/mariadb.js +19 -0
  13. package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
  14. package/packages/datadog-instrumentations/src/mocha/utils.js +11 -3
  15. package/packages/datadog-instrumentations/src/orchestrion-config/index.js +5 -0
  16. package/packages/datadog-instrumentations/src/playwright.js +333 -46
  17. package/packages/datadog-instrumentations/src/router.js +1 -7
  18. package/packages/datadog-instrumentations/src/vitest.js +11 -3
  19. package/packages/datadog-plugin-cucumber/src/index.js +11 -4
  20. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +17 -5
  21. package/packages/datadog-plugin-jest/src/index.js +11 -4
  22. package/packages/datadog-plugin-langchain/src/index.js +18 -12
  23. package/packages/datadog-plugin-langchain/src/tracing.js +66 -6
  24. package/packages/datadog-plugin-mocha/src/index.js +17 -5
  25. package/packages/datadog-plugin-mongodb-core/src/index.js +24 -0
  26. package/packages/datadog-plugin-playwright/src/index.js +124 -10
  27. package/packages/datadog-plugin-vitest/src/index.js +13 -8
  28. package/packages/datadog-shimmer/src/shimmer.js +3 -42
  29. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +39 -15
  30. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +3 -3
  31. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +0 -3
  32. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +25 -12
  33. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +3 -32
  34. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +99 -57
  35. package/packages/dd-trace/src/appsec/rasp/command_injection.js +1 -1
  36. package/packages/dd-trace/src/appsec/rasp/index.js +4 -2
  37. package/packages/dd-trace/src/appsec/rasp/lfi.js +1 -1
  38. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +1 -1
  39. package/packages/dd-trace/src/appsec/rasp/ssrf.js +1 -1
  40. package/packages/dd-trace/src/appsec/rasp/utils.js +12 -7
  41. package/packages/dd-trace/src/appsec/recommended.json +256 -84
  42. package/packages/dd-trace/src/appsec/reporter.js +6 -4
  43. package/packages/dd-trace/src/appsec/telemetry/index.js +27 -3
  44. package/packages/dd-trace/src/appsec/telemetry/rasp.js +70 -6
  45. package/packages/dd-trace/src/appsec/telemetry/waf.js +0 -30
  46. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -0
  47. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +8 -3
  48. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +6 -4
  49. package/packages/dd-trace/src/config.js +9 -0
  50. package/packages/dd-trace/src/constants.js +1 -0
  51. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +102 -22
  52. package/packages/dd-trace/src/debugger/devtools_client/condition.js +263 -0
  53. package/packages/dd-trace/src/debugger/devtools_client/index.js +69 -36
  54. package/packages/dd-trace/src/debugger/devtools_client/lock.js +8 -0
  55. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +1 -7
  56. package/packages/dd-trace/src/debugger/devtools_client/send.js +2 -2
  57. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +15 -10
  58. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +3 -3
  59. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +69 -62
  60. package/packages/dd-trace/src/debugger/devtools_client/state.js +3 -2
  61. package/packages/dd-trace/src/debugger/index.js +3 -0
  62. package/packages/dd-trace/src/encode/0.4.js +24 -17
  63. package/packages/dd-trace/src/exporter.js +1 -0
  64. package/packages/dd-trace/src/exporters/common/docker.js +37 -7
  65. package/packages/dd-trace/src/exporters/common/request.js +1 -4
  66. package/packages/dd-trace/src/format.js +58 -60
  67. package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
  68. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +62 -3
  69. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -0
  70. package/packages/dd-trace/src/llmobs/plugins/vertexai.js +2 -1
  71. package/packages/dd-trace/src/llmobs/writers/spans/base.js +3 -3
  72. package/packages/dd-trace/src/log/index.js +2 -0
  73. package/packages/dd-trace/src/log/writer.js +19 -2
  74. package/packages/dd-trace/src/opentelemetry/span.js +4 -4
  75. package/packages/dd-trace/src/opentracing/propagation/text_map.js +17 -3
  76. package/packages/dd-trace/src/opentracing/span.js +10 -0
  77. package/packages/dd-trace/src/plugin_manager.js +2 -0
  78. package/packages/dd-trace/src/plugins/util/test.js +11 -0
  79. package/packages/dd-trace/src/profiler.js +1 -1
  80. package/packages/dd-trace/src/profiling/config.js +6 -0
  81. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -5
  82. package/packages/dd-trace/src/profiling/profiler.js +4 -3
  83. package/packages/dd-trace/src/profiling/profilers/wall.js +12 -8
  84. package/packages/dd-trace/src/proxy.js +5 -1
  85. package/packages/dd-trace/src/tagger.js +38 -26
  86. package/packages/dd-trace/src/util.js +1 -7
@@ -15,6 +15,7 @@ const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
15
15
  const { tagger } = require('./tagger')
16
16
  const { isFalse, isTrue } = require('../util')
17
17
  const { getAzureTagsFromMetadata, getAzureAppMetadata } = require('../azure_metadata')
18
+ const satisfies = require('semifies')
18
19
 
19
20
  class Config {
20
21
  constructor (options = {}) {
@@ -22,6 +23,7 @@ class Config {
22
23
  DD_AGENT_HOST,
23
24
  DD_ENV,
24
25
  DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED, // used for testing
26
+ DD_PROFILING_ASYNC_ID_ENABLED,
25
27
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
26
28
  DD_PROFILING_CPU_ENABLED,
27
29
  DD_PROFILING_DEBUG_SOURCE_MAPS,
@@ -179,6 +181,10 @@ class Config {
179
181
  this.timelineSamplingEnabled = isTrue(coalesce(options.timelineSamplingEnabled,
180
182
  DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED, true))
181
183
 
184
+ // Async ID gathering only works reliably on Node >= 22.10.0
185
+ this.asyncIdEnabled = isTrue(coalesce(options.asyncIdEnabled,
186
+ DD_PROFILING_ASYNC_ID_ENABLED, this.timelineEnabled && satisfies(process.versions.node, '>=22.10.0')))
187
+
182
188
  this.codeHotspotsEnabled = isTrue(coalesce(options.codeHotspotsEnabled,
183
189
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
184
190
  DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED, samplingContextsAvailable))
@@ -16,8 +16,6 @@ const perf = require('perf_hooks').performance
16
16
  const telemetryMetrics = require('../../telemetry/metrics')
17
17
  const profilersNamespace = telemetryMetrics.manager.namespace('profilers')
18
18
 
19
- const containerId = docker.id()
20
-
21
19
  const statusCodeCounters = []
22
20
  const requestCounter = profilersNamespace.count('profile_api.requests', [])
23
21
  const sizeDistribution = profilersNamespace.distribution('profile_api.bytes', [])
@@ -155,9 +153,7 @@ class AgentExporter extends EventSerializer {
155
153
  timeout: this._backoffTime * Math.pow(2, attempt)
156
154
  }
157
155
 
158
- if (containerId) {
159
- options.headers['Datadog-Container-ID'] = containerId
160
- }
156
+ docker.inject(options.headers)
161
157
 
162
158
  if (this._url.protocol === 'unix:') {
163
159
  options.socketPath = this._url.pathname
@@ -18,9 +18,9 @@ function maybeSourceMap (sourceMap, SourceMapper, debug) {
18
18
  ], debug)
19
19
  }
20
20
 
21
- function logError (logger, err) {
21
+ function logError (logger, ...args) {
22
22
  if (logger) {
23
- logger.error(err)
23
+ logger.error(...args)
24
24
  }
25
25
  }
26
26
 
@@ -52,7 +52,8 @@ class Profiler extends EventEmitter {
52
52
 
53
53
  start (options) {
54
54
  return this._start(options).catch((err) => {
55
- logError(options.logger, err)
55
+ logError(options.logger, 'Error starting profiler. For troubleshooting tips, see ' +
56
+ '<https://dtdg.co/nodejs-profiler-troubleshooting>', err)
56
57
  return false
57
58
  })
58
59
  }
@@ -70,12 +70,16 @@ function ensureChannelsActivated () {
70
70
  class NativeWallProfiler {
71
71
  constructor (options = {}) {
72
72
  this.type = 'wall'
73
- this._samplingIntervalMicros = options.samplingInterval || 1e6 / 99 // 99hz
74
- this._flushIntervalMillis = options.flushInterval || 60 * 1e3 // 60 seconds
73
+ // Currently there's a crash sometimes on worker threads trying to collect async IDs so for the
74
+ // time being we'll constrain it to only the main thread.
75
+ this._asyncIdEnabled = !!options.asyncIdEnabled && require('worker_threads').isMainThread
75
76
  this._codeHotspotsEnabled = !!options.codeHotspotsEnabled
77
+ this._cpuProfilingEnabled = !!options.cpuProfilingEnabled
76
78
  this._endpointCollectionEnabled = !!options.endpointCollectionEnabled
79
+ this._flushIntervalMillis = options.flushInterval || 60 * 1e3 // 60 seconds
80
+ this._samplingIntervalMicros = options.samplingInterval || 1e6 / 99 // 99hz
77
81
  this._timelineEnabled = !!options.timelineEnabled
78
- this._cpuProfilingEnabled = !!options.cpuProfilingEnabled
82
+ this._v8ProfilerBugWorkaroundEnabled = !!options.v8ProfilerBugWorkaroundEnabled
79
83
  // We need to capture span data into the sample context for either code hotspots
80
84
  // or endpoint collection.
81
85
  this._captureSpanData = this._codeHotspotsEnabled || this._endpointCollectionEnabled
@@ -84,7 +88,6 @@ class NativeWallProfiler {
84
88
  // timestamps require the sample contexts feature in the pprof wall profiler), or
85
89
  // cpu profiling is enabled.
86
90
  this._withContexts = this._captureSpanData || this._timelineEnabled || this._cpuProfilingEnabled
87
- this._v8ProfilerBugWorkaroundEnabled = !!options.v8ProfilerBugWorkaroundEnabled
88
91
  this._mapper = undefined
89
92
  this._pprof = undefined
90
93
 
@@ -127,13 +130,14 @@ class NativeWallProfiler {
127
130
  }
128
131
 
129
132
  this._pprof.time.start({
130
- intervalMicros: this._samplingIntervalMicros,
133
+ collectAsyncId: this._asyncIdEnabled,
134
+ collectCpuTime: this._cpuProfilingEnabled,
131
135
  durationMillis: this._flushIntervalMillis,
136
+ intervalMicros: this._samplingIntervalMicros,
137
+ lineNumbers: false,
132
138
  sourceMapper: this._mapper,
133
139
  withContexts: this._withContexts,
134
- lineNumbers: false,
135
- workaroundV8Bug: this._v8ProfilerBugWorkaroundEnabled,
136
- collectCpuTime: this._cpuProfilingEnabled
140
+ workaroundV8Bug: this._v8ProfilerBugWorkaroundEnabled
137
141
  })
138
142
 
139
143
  if (this._withContexts) {
@@ -70,7 +70,8 @@ class Tracer extends NoopProxy {
70
70
  this._modules = {
71
71
  appsec: new LazyModule(() => require('./appsec')),
72
72
  iast: new LazyModule(() => require('./appsec/iast')),
73
- llmobs: new LazyModule(() => require('./llmobs'))
73
+ llmobs: new LazyModule(() => require('./llmobs')),
74
+ rewriter: new LazyModule(() => require('./appsec/iast/taint-tracking/rewriter'))
74
75
  }
75
76
  }
76
77
 
@@ -178,6 +179,8 @@ class Tracer extends NoopProxy {
178
179
 
179
180
  this._enableOrDisableTracing(config)
180
181
 
182
+ this._modules.rewriter.enable(config)
183
+
181
184
  if (config.tracing) {
182
185
  if (config.isManualApiEnabled) {
183
186
  const TestApiManualPlugin = require('./ci-visibility/test-api-manual/test-api-manual-plugin')
@@ -247,6 +250,7 @@ class Tracer extends NoopProxy {
247
250
  if (config.iast.enabled) {
248
251
  this._modules.iast.enable(config, this._tracer)
249
252
  }
253
+ // This needs to be after the IAST module is enabled
250
254
  } else if (this._tracingInitialized) {
251
255
  this._modules.appsec.disable()
252
256
  this._modules.iast.disable()
@@ -1,43 +1,55 @@
1
1
  'use strict'
2
2
 
3
- const constants = require('./constants')
4
3
  const log = require('./log')
5
- const ERROR_MESSAGE = constants.ERROR_MESSAGE
6
- const ERROR_STACK = constants.ERROR_STACK
7
- const ERROR_TYPE = constants.ERROR_TYPE
4
+
5
+ function addNonEmpty (carrier, key, value) {
6
+ if (key !== '') {
7
+ carrier[key] = value
8
+ }
9
+ }
8
10
 
9
11
  function add (carrier, keyValuePairs) {
10
- if (!carrier || !keyValuePairs) return
12
+ if (!carrier) return
11
13
 
12
- if (Array.isArray(keyValuePairs)) {
13
- return keyValuePairs.forEach(tags => add(carrier, tags))
14
- }
15
14
  try {
16
15
  if (typeof keyValuePairs === 'string') {
17
- const segments = keyValuePairs.split(',')
18
- for (const segment of segments) {
19
- const separatorIndex = segment.indexOf(':')
20
-
21
- let value = ''
22
- let key = segment
23
- if (separatorIndex !== -1) {
24
- key = segment.slice(0, separatorIndex)
25
- value = segment.slice(separatorIndex + 1)
16
+ let valueStart = 0
17
+ let keyStart = 0
18
+
19
+ for (let i = 0; i < keyValuePairs.length; i++) {
20
+ const char = keyValuePairs[i]
21
+
22
+ if (char === ':') {
23
+ if (valueStart === 0) {
24
+ valueStart = i
25
+ }
26
+ } else if (char === ',') {
27
+ valueStart ||= i
28
+ addNonEmpty(
29
+ carrier,
30
+ keyValuePairs.slice(keyStart, valueStart).trim(),
31
+ keyValuePairs.slice(valueStart + 1, i).trim()
32
+ )
33
+ keyStart = i + 1
34
+ valueStart = 0
26
35
  }
36
+ }
27
37
 
28
- carrier[key.trim()] = value.trim()
38
+ if (keyValuePairs.at(-1) !== ',') {
39
+ valueStart ||= keyValuePairs.length
40
+ addNonEmpty(
41
+ carrier,
42
+ keyValuePairs.slice(keyStart, valueStart).trim(),
43
+ keyValuePairs.slice(valueStart + 1).trim()
44
+ )
29
45
  }
46
+ } else if (Array.isArray(keyValuePairs)) {
47
+ return keyValuePairs.forEach(tags => add(carrier, tags))
30
48
  } else {
31
- // HACK: to ensure otel.recordException does not influence trace.error
32
- if (ERROR_MESSAGE in keyValuePairs || ERROR_STACK in keyValuePairs || ERROR_TYPE in keyValuePairs) {
33
- if (!('doNotSetTraceError' in keyValuePairs)) {
34
- carrier.setTraceError = true
35
- }
36
- }
37
49
  Object.assign(carrier, keyValuePairs)
38
50
  }
39
- } catch (e) {
40
- log.error('Error adding tags', e)
51
+ } catch (error) {
52
+ log.error('Error adding tags', error)
41
53
  }
42
54
  }
43
55
 
@@ -13,13 +13,7 @@ function isFalse (str) {
13
13
  }
14
14
 
15
15
  function isError (value) {
16
- if (value instanceof Error) {
17
- return true
18
- }
19
- if (value && value.message) {
20
- return true
21
- }
22
- return false
16
+ return Boolean(value?.message || value instanceof Error)
23
17
  }
24
18
 
25
19
  // Matches a glob pattern to a given subject string