dd-trace 4.48.0 → 4.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 (138) hide show
  1. package/LICENSE-3rdparty.csv +3 -0
  2. package/index.d.ts +345 -8
  3. package/init.js +60 -47
  4. package/package.json +16 -7
  5. package/packages/datadog-code-origin/index.js +4 -4
  6. package/packages/datadog-core/index.js +1 -3
  7. package/packages/datadog-core/src/storage.js +21 -0
  8. package/packages/datadog-core/src/utils/src/parse-tags.js +33 -0
  9. package/packages/datadog-esbuild/index.js +4 -2
  10. package/packages/datadog-instrumentations/src/amqplib.js +65 -5
  11. package/packages/datadog-instrumentations/src/child_process.js +135 -27
  12. package/packages/datadog-instrumentations/src/express.js +1 -1
  13. package/packages/datadog-instrumentations/src/handlebars.js +40 -0
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
  15. package/packages/datadog-instrumentations/src/helpers/register.js +9 -0
  16. package/packages/datadog-instrumentations/src/jest.js +6 -2
  17. package/packages/datadog-instrumentations/src/kafkajs.js +123 -63
  18. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -2
  19. package/packages/datadog-instrumentations/src/multer.js +37 -0
  20. package/packages/datadog-instrumentations/src/openai.js +2 -2
  21. package/packages/datadog-instrumentations/src/pug.js +23 -0
  22. package/packages/datadog-instrumentations/src/router.js +2 -3
  23. package/packages/datadog-instrumentations/src/url.js +84 -0
  24. package/packages/datadog-instrumentations/src/utils/src/extract-package-and-module-path.js +7 -4
  25. package/packages/datadog-plugin-amqplib/src/consumer.js +6 -5
  26. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -0
  27. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  28. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +10 -7
  29. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +35 -0
  30. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +11 -9
  31. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +59 -45
  32. package/packages/datadog-plugin-cypress/src/support.js +1 -0
  33. package/packages/datadog-plugin-fastify/src/code_origin.js +2 -2
  34. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +10 -2
  35. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +8 -0
  36. package/packages/datadog-plugin-grpc/src/client.js +3 -0
  37. package/packages/datadog-plugin-grpc/src/server.js +5 -1
  38. package/packages/datadog-plugin-http/src/client.js +42 -1
  39. package/packages/datadog-plugin-http2/src/client.js +26 -1
  40. package/packages/datadog-plugin-jest/src/index.js +2 -1
  41. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +6 -3
  42. package/packages/datadog-plugin-kafkajs/src/consumer.js +10 -5
  43. package/packages/datadog-plugin-kafkajs/src/producer.js +10 -4
  44. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  45. package/packages/datadog-plugin-moleculer/src/server.js +2 -2
  46. package/packages/datadog-plugin-openai/src/index.js +9 -1015
  47. package/packages/datadog-plugin-openai/src/tracing.js +1023 -0
  48. package/packages/datadog-plugin-rhea/src/consumer.js +2 -1
  49. package/packages/datadog-plugin-vitest/src/index.js +2 -1
  50. package/packages/dd-trace/src/appsec/addresses.js +2 -0
  51. package/packages/dd-trace/src/appsec/api_security_sampler.js +50 -27
  52. package/packages/dd-trace/src/appsec/channels.js +3 -1
  53. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  54. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +33 -16
  55. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +18 -0
  56. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +55 -7
  57. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -2
  58. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  59. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -2
  60. package/packages/dd-trace/src/appsec/index.js +9 -6
  61. package/packages/dd-trace/src/appsec/rasp/command_injection.js +49 -0
  62. package/packages/dd-trace/src/appsec/rasp/index.js +3 -0
  63. package/packages/dd-trace/src/appsec/rasp/ssrf.js +4 -3
  64. package/packages/dd-trace/src/appsec/rasp/utils.js +3 -2
  65. package/packages/dd-trace/src/appsec/recommended.json +354 -158
  66. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  67. package/packages/dd-trace/src/appsec/remote_config/index.js +2 -7
  68. package/packages/dd-trace/src/appsec/reporter.js +6 -4
  69. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -3
  70. package/packages/dd-trace/src/appsec/waf/waf_manager.js +4 -0
  71. package/packages/dd-trace/src/azure_metadata.js +120 -0
  72. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +97 -0
  73. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +90 -0
  74. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +19 -1
  75. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +53 -0
  76. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +8 -1
  77. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +43 -0
  78. package/packages/dd-trace/src/config.js +88 -10
  79. package/packages/dd-trace/src/constants.js +8 -1
  80. package/packages/dd-trace/src/crashtracking/crashtracker.js +98 -0
  81. package/packages/dd-trace/src/crashtracking/index.js +15 -0
  82. package/packages/dd-trace/src/crashtracking/noop.js +8 -0
  83. package/packages/dd-trace/src/datastreams/pathway.js +1 -0
  84. package/packages/dd-trace/src/debugger/devtools_client/index.js +9 -13
  85. package/packages/dd-trace/src/debugger/devtools_client/send.js +15 -1
  86. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +57 -23
  87. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +12 -2
  88. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +31 -20
  89. package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +6 -0
  90. package/packages/dd-trace/src/debugger/devtools_client/state.js +11 -2
  91. package/packages/dd-trace/src/debugger/index.js +10 -3
  92. package/packages/dd-trace/src/llmobs/constants/tags.js +34 -0
  93. package/packages/dd-trace/src/llmobs/constants/text.js +6 -0
  94. package/packages/dd-trace/src/llmobs/constants/writers.js +13 -0
  95. package/packages/dd-trace/src/llmobs/index.js +103 -0
  96. package/packages/dd-trace/src/llmobs/noop.js +82 -0
  97. package/packages/dd-trace/src/llmobs/plugins/base.js +65 -0
  98. package/packages/dd-trace/src/llmobs/plugins/openai.js +205 -0
  99. package/packages/dd-trace/src/llmobs/sdk.js +377 -0
  100. package/packages/dd-trace/src/llmobs/span_processor.js +195 -0
  101. package/packages/dd-trace/src/llmobs/storage.js +7 -0
  102. package/packages/dd-trace/src/llmobs/tagger.js +322 -0
  103. package/packages/dd-trace/src/llmobs/util.js +176 -0
  104. package/packages/dd-trace/src/llmobs/writers/base.js +111 -0
  105. package/packages/dd-trace/src/llmobs/writers/evaluations.js +29 -0
  106. package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +23 -0
  107. package/packages/dd-trace/src/llmobs/writers/spans/agentless.js +17 -0
  108. package/packages/dd-trace/src/llmobs/writers/spans/base.js +52 -0
  109. package/packages/dd-trace/src/log/index.js +10 -13
  110. package/packages/dd-trace/src/log/log.js +52 -0
  111. package/packages/dd-trace/src/log/writer.js +50 -19
  112. package/packages/dd-trace/src/noop/proxy.js +3 -0
  113. package/packages/dd-trace/src/noop/span.js +4 -0
  114. package/packages/dd-trace/src/opentelemetry/span.js +16 -1
  115. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -0
  116. package/packages/dd-trace/src/opentracing/propagation/text_map.js +106 -32
  117. package/packages/dd-trace/src/opentracing/span.js +26 -0
  118. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  119. package/packages/dd-trace/src/opentracing/tracer.js +8 -1
  120. package/packages/dd-trace/src/payload-tagging/config/aws.json +71 -3
  121. package/packages/dd-trace/src/plugins/outbound.js +9 -0
  122. package/packages/dd-trace/src/plugins/tracing.js +3 -3
  123. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +121 -0
  124. package/packages/dd-trace/src/plugins/util/ip_extractor.js +0 -1
  125. package/packages/dd-trace/src/plugins/util/web.js +39 -11
  126. package/packages/dd-trace/src/priority_sampler.js +16 -0
  127. package/packages/dd-trace/src/profiling/config.js +3 -1
  128. package/packages/dd-trace/src/profiling/exporters/agent.js +7 -5
  129. package/packages/dd-trace/src/profiling/profilers/wall.js +2 -1
  130. package/packages/dd-trace/src/proxy.js +13 -1
  131. package/packages/dd-trace/src/span_processor.js +5 -0
  132. package/packages/dd-trace/src/telemetry/index.js +11 -1
  133. package/packages/dd-trace/src/telemetry/logs/index.js +16 -11
  134. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -8
  135. package/packages/dd-trace/src/telemetry/metrics.js +6 -1
  136. package/packages/dd-trace/src/util.js +16 -1
  137. package/version.js +4 -2
  138. /package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/{code-injection-sensitive-analyzer.js → tainted-range-based-sensitive-analyzer.js} +0 -0
@@ -0,0 +1,33 @@
1
+ 'use strict'
2
+
3
+ const digitRegex = /^\d+$/
4
+
5
+ /**
6
+ * Converts a flat object of tags into a nested object. For example:
7
+ * { 'a.b.c': 'value' } -> { a: { b: { c: 'value' } } }
8
+ * Also supports array-keys. For example:
9
+ * { 'a.0.b': 'value' } -> { a: [{ b: 'value' }] }
10
+ *
11
+ * @param {Object} tags - Key/value pairs of tags
12
+ * @returns Object - Parsed tags
13
+ */
14
+ module.exports = tags => {
15
+ const parsedTags = {}
16
+ for (const [tag, value] of Object.entries(tags)) {
17
+ const keys = tag.split('.')
18
+ let current = parsedTags
19
+ let depth = 0
20
+ for (const key of keys) {
21
+ if (!current[key]) {
22
+ if (depth === keys.length - 1) {
23
+ current[key] = value
24
+ break
25
+ }
26
+ current[key] = keys[depth + 1]?.match(digitRegex) ? [] : {}
27
+ }
28
+ current = current[key]
29
+ depth++
30
+ }
31
+ }
32
+ return parsedTags
33
+ }
@@ -96,7 +96,9 @@ module.exports.setup = function (build) {
96
96
 
97
97
  let pathToPackageJson
98
98
  try {
99
- pathToPackageJson = require.resolve(`${extracted.pkg}/package.json`, { paths: [args.resolveDir] })
99
+ // we can't use require.resolve('pkg/package.json') as ESM modules don't make the file available
100
+ pathToPackageJson = require.resolve(`${extracted.pkg}`, { paths: [args.resolveDir] })
101
+ pathToPackageJson = extractPackageAndModulePath(pathToPackageJson).pkgJson
100
102
  } catch (err) {
101
103
  if (err.code === 'MODULE_NOT_FOUND') {
102
104
  if (!internal) {
@@ -111,7 +113,7 @@ module.exports.setup = function (build) {
111
113
  }
112
114
  }
113
115
 
114
- const packageJson = require(pathToPackageJson)
116
+ const packageJson = JSON.parse(fs.readFileSync(pathToPackageJson).toString())
115
117
 
116
118
  if (DEBUG) console.log(`RESOLVE: ${args.path}@${packageJson.version}`)
117
119
 
@@ -25,6 +25,70 @@ addHook({ name: 'amqplib', file: 'lib/defs.js', versions: [MIN_VERSION] }, defs
25
25
  return defs
26
26
  })
27
27
 
28
+ addHook({ name: 'amqplib', file: 'lib/channel_model.js', versions: [MIN_VERSION] }, x => {
29
+ shimmer.wrap(x.Channel.prototype, 'get', getMessage => function (queue, options) {
30
+ return getMessage.apply(this, arguments).then(message => {
31
+ if (message === null) {
32
+ return message
33
+ }
34
+ startCh.publish({ method: 'basic.get', message, fields: message.fields, queue })
35
+ // finish right away
36
+ finishCh.publish()
37
+ return message
38
+ })
39
+ })
40
+ shimmer.wrap(x.Channel.prototype, 'consume', consume => function (queue, callback, options) {
41
+ if (!startCh.hasSubscribers) {
42
+ return consume.apply(this, arguments)
43
+ }
44
+ arguments[1] = (message, ...args) => {
45
+ if (message === null) {
46
+ return callback(message, ...args)
47
+ }
48
+ startCh.publish({ method: 'basic.deliver', message, fields: message.fields, queue })
49
+ const result = callback(message, ...args)
50
+ finishCh.publish()
51
+ return result
52
+ }
53
+ return consume.apply(this, arguments)
54
+ })
55
+ return x
56
+ })
57
+
58
+ addHook({ name: 'amqplib', file: 'lib/callback_model.js', versions: [MIN_VERSION] }, channel => {
59
+ shimmer.wrap(channel.Channel.prototype, 'get', getMessage => function (queue, options, callback) {
60
+ if (!startCh.hasSubscribers) {
61
+ return getMessage.apply(this, arguments)
62
+ }
63
+ arguments[2] = (error, message, ...args) => {
64
+ if (error !== null || message === null) {
65
+ return callback(error, message, ...args)
66
+ }
67
+ startCh.publish({ method: 'basic.get', message, fields: message.fields, queue })
68
+ const result = callback(error, message, ...args)
69
+ finishCh.publish()
70
+ return result
71
+ }
72
+ return getMessage.apply(this, arguments)
73
+ })
74
+ shimmer.wrap(channel.Channel.prototype, 'consume', consume => function (queue, callback) {
75
+ if (!startCh.hasSubscribers) {
76
+ return consume.apply(this, arguments)
77
+ }
78
+ arguments[1] = (message, ...args) => {
79
+ if (message === null) {
80
+ return callback(message, ...args)
81
+ }
82
+ startCh.publish({ method: 'basic.deliver', message, fields: message.fields, queue })
83
+ const result = callback(message, ...args)
84
+ finishCh.publish()
85
+ return result
86
+ }
87
+ return consume.apply(this, arguments)
88
+ })
89
+ return channel
90
+ })
91
+
28
92
  addHook({ name: 'amqplib', file: 'lib/channel.js', versions: [MIN_VERSION] }, channel => {
29
93
  shimmer.wrap(channel.Channel.prototype, 'sendImmediately', sendImmediately => function (method, fields) {
30
94
  return instrument(sendImmediately, this, arguments, methods[method], fields)
@@ -33,15 +97,11 @@ addHook({ name: 'amqplib', file: 'lib/channel.js', versions: [MIN_VERSION] }, ch
33
97
  shimmer.wrap(channel.Channel.prototype, 'sendMessage', sendMessage => function (fields) {
34
98
  return instrument(sendMessage, this, arguments, 'basic.publish', fields, arguments[2])
35
99
  })
36
-
37
- shimmer.wrap(channel.BaseChannel.prototype, 'dispatchMessage', dispatchMessage => function (fields, message) {
38
- return instrument(dispatchMessage, this, arguments, 'basic.deliver', fields, message)
39
- })
40
100
  return channel
41
101
  })
42
102
 
43
103
  function instrument (send, channel, args, method, fields, message) {
44
- if (!startCh.hasSubscribers) {
104
+ if (!startCh.hasSubscribers || method === 'basic.get') {
45
105
  return send.apply(channel, args)
46
106
  }
47
107
 
@@ -13,19 +13,38 @@ const childProcessChannel = dc.tracingChannel('datadog:child_process:execution')
13
13
 
14
14
  // ignored exec method because it calls to execFile directly
15
15
  const execAsyncMethods = ['execFile', 'spawn']
16
- const execSyncMethods = ['execFileSync', 'spawnSync']
17
16
 
18
17
  const names = ['child_process', 'node:child_process']
19
18
 
20
19
  // child_process and node:child_process returns the same object instance, we only want to add hooks once
21
20
  let patched = false
21
+
22
+ function throwSyncError (error) {
23
+ throw error
24
+ }
25
+
26
+ function returnSpawnSyncError (error, context) {
27
+ context.result = {
28
+ error,
29
+ status: null,
30
+ signal: null,
31
+ output: null,
32
+ stdout: null,
33
+ stderr: null,
34
+ pid: 0
35
+ }
36
+
37
+ return context.result
38
+ }
39
+
22
40
  names.forEach(name => {
23
41
  addHook({ name }, childProcess => {
24
42
  if (!patched) {
25
43
  patched = true
26
- shimmer.massWrap(childProcess, execAsyncMethods, wrapChildProcessAsyncMethod())
27
- shimmer.massWrap(childProcess, execSyncMethods, wrapChildProcessSyncMethod())
28
- shimmer.wrap(childProcess, 'execSync', wrapChildProcessSyncMethod(true))
44
+ shimmer.massWrap(childProcess, execAsyncMethods, wrapChildProcessAsyncMethod(childProcess.ChildProcess))
45
+ shimmer.wrap(childProcess, 'execSync', wrapChildProcessSyncMethod(throwSyncError, true))
46
+ shimmer.wrap(childProcess, 'execFileSync', wrapChildProcessSyncMethod(throwSyncError))
47
+ shimmer.wrap(childProcess, 'spawnSync', wrapChildProcessSyncMethod(returnSpawnSyncError))
29
48
  }
30
49
 
31
50
  return childProcess
@@ -34,17 +53,21 @@ names.forEach(name => {
34
53
 
35
54
  function normalizeArgs (args, shell) {
36
55
  const childProcessInfo = {
37
- command: args[0]
56
+ command: args[0],
57
+ file: args[0]
38
58
  }
39
59
 
40
60
  if (Array.isArray(args[1])) {
41
61
  childProcessInfo.command = childProcessInfo.command + ' ' + args[1].join(' ')
62
+ childProcessInfo.fileArgs = args[1]
63
+
42
64
  if (args[2] !== null && typeof args[2] === 'object') {
43
65
  childProcessInfo.options = args[2]
44
66
  }
45
67
  } else if (args[1] !== null && typeof args[1] === 'object') {
46
68
  childProcessInfo.options = args[1]
47
69
  }
70
+
48
71
  childProcessInfo.shell = shell ||
49
72
  childProcessInfo.options?.shell === true ||
50
73
  typeof childProcessInfo.options?.shell === 'string'
@@ -52,7 +75,21 @@ function normalizeArgs (args, shell) {
52
75
  return childProcessInfo
53
76
  }
54
77
 
55
- function wrapChildProcessSyncMethod (shell = false) {
78
+ function createContextFromChildProcessInfo (childProcessInfo) {
79
+ const context = {
80
+ command: childProcessInfo.command,
81
+ file: childProcessInfo.file,
82
+ shell: childProcessInfo.shell
83
+ }
84
+
85
+ if (childProcessInfo.fileArgs) {
86
+ context.fileArgs = childProcessInfo.fileArgs
87
+ }
88
+
89
+ return context
90
+ }
91
+
92
+ function wrapChildProcessSyncMethod (returnError, shell = false) {
56
93
  return function wrapMethod (childProcessMethod) {
57
94
  return function () {
58
95
  if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
@@ -63,14 +100,30 @@ function wrapChildProcessSyncMethod (shell = false) {
63
100
 
64
101
  const innerResource = new AsyncResource('bound-anonymous-fn')
65
102
  return innerResource.runInAsyncScope(() => {
66
- return childProcessChannel.traceSync(
67
- childProcessMethod,
68
- {
69
- command: childProcessInfo.command,
70
- shell: childProcessInfo.shell
71
- },
72
- this,
73
- ...arguments)
103
+ const context = createContextFromChildProcessInfo(childProcessInfo)
104
+ const abortController = new AbortController()
105
+
106
+ childProcessChannel.start.publish({ ...context, abortController })
107
+
108
+ try {
109
+ if (abortController.signal.aborted) {
110
+ const error = abortController.signal.reason || new Error('Aborted')
111
+ // expected behaviors on error are different
112
+ return returnError(error, context)
113
+ }
114
+
115
+ const result = childProcessMethod.apply(this, arguments)
116
+ context.result = result
117
+
118
+ return result
119
+ } catch (err) {
120
+ context.error = err
121
+ childProcessChannel.error.publish(context)
122
+
123
+ throw err
124
+ } finally {
125
+ childProcessChannel.end.publish(context)
126
+ }
74
127
  })
75
128
  }
76
129
  }
@@ -84,18 +137,52 @@ function wrapChildProcessCustomPromisifyMethod (customPromisifyMethod, shell) {
84
137
 
85
138
  const childProcessInfo = normalizeArgs(arguments, shell)
86
139
 
87
- return childProcessChannel.tracePromise(
88
- customPromisifyMethod,
89
- {
90
- command: childProcessInfo.command,
91
- shell: childProcessInfo.shell
92
- },
93
- this,
94
- ...arguments)
140
+ const context = createContextFromChildProcessInfo(childProcessInfo)
141
+
142
+ const { start, end, asyncStart, asyncEnd, error } = childProcessChannel
143
+ const abortController = new AbortController()
144
+
145
+ start.publish({
146
+ ...context,
147
+ abortController
148
+ })
149
+
150
+ let result
151
+ if (abortController.signal.aborted) {
152
+ result = Promise.reject(abortController.signal.reason || new Error('Aborted'))
153
+ } else {
154
+ try {
155
+ result = customPromisifyMethod.apply(this, arguments)
156
+ } catch (error) {
157
+ error.publish({ ...context, error })
158
+ throw error
159
+ } finally {
160
+ end.publish(context)
161
+ }
162
+ }
163
+
164
+ function reject (err) {
165
+ context.error = err
166
+ error.publish(context)
167
+ asyncStart.publish(context)
168
+
169
+ asyncEnd.publish(context)
170
+ return Promise.reject(err)
171
+ }
172
+
173
+ function resolve (result) {
174
+ context.result = result
175
+ asyncStart.publish(context)
176
+
177
+ asyncEnd.publish(context)
178
+ return result
179
+ }
180
+
181
+ return Promise.prototype.then.call(result, resolve, reject)
95
182
  }
96
183
  }
97
184
 
98
- function wrapChildProcessAsyncMethod (shell = false) {
185
+ function wrapChildProcessAsyncMethod (ChildProcess, shell = false) {
99
186
  return function wrapMethod (childProcessMethod) {
100
187
  function wrappedChildProcessMethod () {
101
188
  if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
@@ -112,9 +199,31 @@ function wrapChildProcessAsyncMethod (shell = false) {
112
199
 
113
200
  const innerResource = new AsyncResource('bound-anonymous-fn')
114
201
  return innerResource.runInAsyncScope(() => {
115
- childProcessChannel.start.publish({ command: childProcessInfo.command, shell: childProcessInfo.shell })
202
+ const context = createContextFromChildProcessInfo(childProcessInfo)
203
+ const abortController = new AbortController()
204
+
205
+ childProcessChannel.start.publish({ ...context, abortController })
206
+
207
+ let childProcess
208
+ if (abortController.signal.aborted) {
209
+ childProcess = new ChildProcess()
210
+ childProcess.on('error', () => {}) // Original method does not crash when non subscribers
211
+
212
+ process.nextTick(() => {
213
+ const error = abortController.signal.reason || new Error('Aborted')
214
+ childProcess.emit('error', error)
215
+
216
+ const cb = arguments[arguments.length - 1]
217
+ if (typeof cb === 'function') {
218
+ cb(error)
219
+ }
220
+
221
+ childProcess.emit('close')
222
+ })
223
+ } else {
224
+ childProcess = childProcessMethod.apply(this, arguments)
225
+ }
116
226
 
117
- const childProcess = childProcessMethod.apply(this, arguments)
118
227
  if (childProcess) {
119
228
  let errorExecuted = false
120
229
 
@@ -129,8 +238,7 @@ function wrapChildProcessAsyncMethod (shell = false) {
129
238
  childProcessChannel.error.publish()
130
239
  }
131
240
  childProcessChannel.asyncEnd.publish({
132
- command: childProcessInfo.command,
133
- shell: childProcessInfo.shell,
241
+ ...context,
134
242
  result: code
135
243
  })
136
244
  })
@@ -29,7 +29,7 @@ function wrapResponseJson (json) {
29
29
  obj = arguments[1]
30
30
  }
31
31
 
32
- responseJsonChannel.publish({ req: this.req, body: obj })
32
+ responseJsonChannel.publish({ req: this.req, res: this, body: obj })
33
33
  }
34
34
 
35
35
  return json.apply(this, arguments)
@@ -0,0 +1,40 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { channel, addHook } = require('./helpers/instrument')
5
+
6
+ const handlebarsCompileCh = channel('datadog:handlebars:compile:start')
7
+ const handlebarsRegisterPartialCh = channel('datadog:handlebars:register-partial:start')
8
+
9
+ function wrapCompile (compile) {
10
+ return function wrappedCompile (source) {
11
+ if (handlebarsCompileCh.hasSubscribers) {
12
+ handlebarsCompileCh.publish({ source })
13
+ }
14
+
15
+ return compile.apply(this, arguments)
16
+ }
17
+ }
18
+
19
+ function wrapRegisterPartial (registerPartial) {
20
+ return function wrappedRegisterPartial (name, partial) {
21
+ if (handlebarsRegisterPartialCh.hasSubscribers) {
22
+ handlebarsRegisterPartialCh.publish({ partial })
23
+ }
24
+
25
+ return registerPartial.apply(this, arguments)
26
+ }
27
+ }
28
+
29
+ addHook({ name: 'handlebars', file: 'dist/cjs/handlebars/compiler/compiler.js', versions: ['>=4.0.0'] }, compiler => {
30
+ shimmer.wrap(compiler, 'compile', wrapCompile)
31
+ shimmer.wrap(compiler, 'precompile', wrapCompile)
32
+
33
+ return compiler
34
+ })
35
+
36
+ addHook({ name: 'handlebars', file: 'dist/cjs/handlebars/base.js', versions: ['>=4.0.0'] }, base => {
37
+ shimmer.wrap(base.HandlebarsEnvironment.prototype, 'registerPartial', wrapRegisterPartial)
38
+
39
+ return base
40
+ })
@@ -51,6 +51,7 @@ module.exports = {
51
51
  'generic-pool': () => require('../generic-pool'),
52
52
  graphql: () => require('../graphql'),
53
53
  grpc: () => require('../grpc'),
54
+ handlebars: () => require('../handlebars'),
54
55
  hapi: () => require('../hapi'),
55
56
  http: () => require('../http'),
56
57
  http2: () => require('../http2'),
@@ -79,6 +80,7 @@ module.exports = {
79
80
  'mongodb-core': () => require('../mongodb-core'),
80
81
  mongoose: () => require('../mongoose'),
81
82
  mquery: () => require('../mquery'),
83
+ multer: () => require('../multer'),
82
84
  mysql: () => require('../mysql'),
83
85
  mysql2: () => require('../mysql2'),
84
86
  net: () => require('../net'),
@@ -90,6 +92,7 @@ module.exports = {
90
92
  'node:http2': () => require('../http2'),
91
93
  'node:https': () => require('../http'),
92
94
  'node:net': () => require('../net'),
95
+ 'node:url': () => require('../url'),
93
96
  nyc: () => require('../nyc'),
94
97
  oracledb: () => require('../oracledb'),
95
98
  openai: () => require('../openai'),
@@ -103,6 +106,7 @@ module.exports = {
103
106
  'promise-js': () => require('../promise-js'),
104
107
  promise: () => require('../promise'),
105
108
  protobufjs: () => require('../protobufjs'),
109
+ pug: () => require('../pug'),
106
110
  q: () => require('../q'),
107
111
  qs: () => require('../qs'),
108
112
  redis: () => require('../redis'),
@@ -114,6 +118,7 @@ module.exports = {
114
118
  sharedb: () => require('../sharedb'),
115
119
  tedious: () => require('../tedious'),
116
120
  undici: () => require('../undici'),
121
+ url: () => require('../url'),
117
122
  vitest: { esmFirst: true, fn: () => require('../vitest') },
118
123
  when: () => require('../when'),
119
124
  winston: () => require('../winston'),
@@ -22,6 +22,15 @@ const disabledInstrumentations = new Set(
22
22
  DD_TRACE_DISABLED_INSTRUMENTATIONS ? DD_TRACE_DISABLED_INSTRUMENTATIONS.split(',') : []
23
23
  )
24
24
 
25
+ // Check for DD_TRACE_<INTEGRATION>_ENABLED environment variables
26
+ for (const [key, value] of Object.entries(process.env)) {
27
+ const match = key.match(/^DD_TRACE_(.+)_ENABLED$/)
28
+ if (match && (value.toLowerCase() === 'false' || value === '0')) {
29
+ const integration = match[1].toLowerCase()
30
+ disabledInstrumentations.add(integration)
31
+ }
32
+ }
33
+
25
34
  const loadChannel = channel('dd-trace:instrumentation:load')
26
35
 
27
36
  // Globals
@@ -127,6 +127,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
127
127
 
128
128
  if (repositoryRoot) {
129
129
  this.testSourceFile = getTestSuitePath(context.testPath, repositoryRoot)
130
+ this.repositoryRoot = repositoryRoot
130
131
  }
131
132
 
132
133
  this.isEarlyFlakeDetectionEnabled = this.testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled
@@ -667,10 +668,13 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
667
668
  * controls whether coverage is reported.
668
669
  */
669
670
  if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
671
+ const root = environment.repositoryRoot || environment.rootDir
672
+
670
673
  const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
671
- .map(filename => getTestSuitePath(filename, environment.rootDir))
674
+ .map(filename => getTestSuitePath(filename, root))
675
+
672
676
  asyncResource.runInAsyncScope(() => {
673
- testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSuite })
677
+ testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile })
674
678
  })
675
679
  }
676
680
  testSuiteFinishCh.publish({ status, errorMessage })