dd-trace 5.23.1 → 5.25.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 (156) hide show
  1. package/LICENSE-3rdparty.csv +1 -1
  2. package/ext/types.d.ts +1 -0
  3. package/ext/types.js +1 -0
  4. package/index.d.ts +361 -0
  5. package/package.json +18 -13
  6. package/packages/datadog-code-origin/index.js +38 -0
  7. package/packages/datadog-core/index.js +2 -2
  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/avsc.js +37 -0
  12. package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
  13. package/packages/datadog-instrumentations/src/child_process.js +144 -27
  14. package/packages/datadog-instrumentations/src/express.js +37 -4
  15. package/packages/datadog-instrumentations/src/fastify.js +12 -1
  16. package/packages/datadog-instrumentations/src/fs.js +27 -7
  17. package/packages/datadog-instrumentations/src/helpers/hooks.js +6 -0
  18. package/packages/datadog-instrumentations/src/helpers/register.js +9 -0
  19. package/packages/datadog-instrumentations/src/jest.js +2 -1
  20. package/packages/datadog-instrumentations/src/kafkajs.js +123 -63
  21. package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
  22. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -2
  23. package/packages/datadog-instrumentations/src/multer.js +37 -0
  24. package/packages/datadog-instrumentations/src/mysql2.js +220 -1
  25. package/packages/datadog-instrumentations/src/openai.js +2 -2
  26. package/packages/datadog-instrumentations/src/protobufjs.js +127 -0
  27. package/packages/datadog-instrumentations/src/url.js +84 -0
  28. package/packages/datadog-instrumentations/src/utils/src/extract-package-and-module-path.js +7 -4
  29. package/packages/datadog-instrumentations/src/winston.js +22 -0
  30. package/packages/datadog-plugin-amqplib/src/consumer.js +4 -4
  31. package/packages/datadog-plugin-avsc/src/index.js +9 -0
  32. package/packages/datadog-plugin-avsc/src/schema_iterator.js +169 -0
  33. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  34. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
  35. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -0
  36. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
  37. package/packages/datadog-plugin-azure-functions/src/index.js +77 -0
  38. package/packages/datadog-plugin-fastify/src/code_origin.js +31 -0
  39. package/packages/datadog-plugin-fastify/src/index.js +10 -12
  40. package/packages/datadog-plugin-fastify/src/tracing.js +19 -0
  41. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +8 -1
  42. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +8 -0
  43. package/packages/datadog-plugin-grpc/src/client.js +3 -0
  44. package/packages/datadog-plugin-grpc/src/server.js +3 -0
  45. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +6 -3
  46. package/packages/datadog-plugin-kafkajs/src/consumer.js +8 -4
  47. package/packages/datadog-plugin-kafkajs/src/producer.js +10 -4
  48. package/packages/datadog-plugin-mocha/src/index.js +4 -1
  49. package/packages/datadog-plugin-openai/src/index.js +9 -1015
  50. package/packages/datadog-plugin-openai/src/tracing.js +1023 -0
  51. package/packages/datadog-plugin-protobufjs/src/index.js +14 -0
  52. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +180 -0
  53. package/packages/dd-trace/src/appsec/addresses.js +8 -1
  54. package/packages/dd-trace/src/appsec/channels.js +7 -1
  55. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +13 -1
  56. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +8 -1
  57. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  58. package/packages/dd-trace/src/appsec/iast/index.js +3 -0
  59. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +1 -0
  60. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +55 -7
  61. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +15 -0
  62. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -2
  63. package/packages/dd-trace/src/appsec/index.js +61 -43
  64. package/packages/dd-trace/src/appsec/rasp/command_injection.js +49 -0
  65. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +99 -0
  66. package/packages/dd-trace/src/appsec/rasp/index.js +27 -10
  67. package/packages/dd-trace/src/appsec/rasp/lfi.js +112 -0
  68. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +24 -4
  69. package/packages/dd-trace/src/appsec/rasp/ssrf.js +4 -3
  70. package/packages/dd-trace/src/appsec/rasp/utils.js +4 -2
  71. package/packages/dd-trace/src/appsec/recommended.json +3 -7
  72. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +6 -1
  73. package/packages/dd-trace/src/appsec/remote_config/index.js +10 -0
  74. package/packages/dd-trace/src/appsec/reporter.js +17 -9
  75. package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -3
  76. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +1 -1
  77. package/packages/dd-trace/src/appsec/waf/waf_manager.js +4 -0
  78. package/packages/dd-trace/src/azure_metadata.js +120 -0
  79. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +97 -0
  80. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +90 -0
  81. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -14
  82. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +19 -1
  83. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +53 -0
  84. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +8 -1
  85. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +43 -0
  86. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +53 -0
  87. package/packages/dd-trace/src/config.js +86 -6
  88. package/packages/dd-trace/src/constants.js +3 -1
  89. package/packages/dd-trace/src/datastreams/pathway.js +1 -0
  90. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +25 -17
  91. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  92. package/packages/dd-trace/src/debugger/devtools_client/index.js +52 -5
  93. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +4 -4
  94. package/packages/dd-trace/src/debugger/devtools_client/send.js +29 -2
  95. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +187 -0
  96. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +40 -0
  97. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +252 -0
  98. package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +6 -0
  99. package/packages/dd-trace/src/debugger/devtools_client/state.js +19 -4
  100. package/packages/dd-trace/src/debugger/index.js +10 -3
  101. package/packages/dd-trace/src/exporters/common/request.js +8 -34
  102. package/packages/dd-trace/src/exporters/common/url-to-http-options-polyfill.js +31 -0
  103. package/packages/dd-trace/src/llmobs/constants/tags.js +34 -0
  104. package/packages/dd-trace/src/llmobs/constants/text.js +6 -0
  105. package/packages/dd-trace/src/llmobs/constants/writers.js +13 -0
  106. package/packages/dd-trace/src/llmobs/index.js +103 -0
  107. package/packages/dd-trace/src/llmobs/noop.js +82 -0
  108. package/packages/dd-trace/src/llmobs/plugins/base.js +65 -0
  109. package/packages/dd-trace/src/llmobs/plugins/openai.js +205 -0
  110. package/packages/dd-trace/src/llmobs/sdk.js +377 -0
  111. package/packages/dd-trace/src/llmobs/span_processor.js +195 -0
  112. package/packages/dd-trace/src/llmobs/storage.js +7 -0
  113. package/packages/dd-trace/src/llmobs/tagger.js +322 -0
  114. package/packages/dd-trace/src/llmobs/util.js +176 -0
  115. package/packages/dd-trace/src/llmobs/writers/base.js +111 -0
  116. package/packages/dd-trace/src/llmobs/writers/evaluations.js +29 -0
  117. package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +23 -0
  118. package/packages/dd-trace/src/llmobs/writers/spans/agentless.js +17 -0
  119. package/packages/dd-trace/src/llmobs/writers/spans/base.js +49 -0
  120. package/packages/dd-trace/src/noop/proxy.js +3 -0
  121. package/packages/dd-trace/src/noop/span.js +3 -0
  122. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  123. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -0
  124. package/packages/dd-trace/src/opentracing/propagation/text_map.js +73 -12
  125. package/packages/dd-trace/src/opentracing/span.js +12 -0
  126. package/packages/dd-trace/src/opentracing/tracer.js +8 -1
  127. package/packages/dd-trace/src/payload-tagging/config/aws.json +71 -3
  128. package/packages/dd-trace/src/payload-tagging/index.js +1 -1
  129. package/packages/dd-trace/src/payload-tagging/jsonpath-plus.js +2094 -0
  130. package/packages/dd-trace/src/plugin_manager.js +4 -2
  131. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -0
  132. package/packages/dd-trace/src/plugins/index.js +3 -0
  133. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  134. package/packages/dd-trace/src/plugins/outbound.js +9 -0
  135. package/packages/dd-trace/src/plugins/schema.js +35 -0
  136. package/packages/dd-trace/src/plugins/util/ci.js +23 -1
  137. package/packages/dd-trace/src/plugins/util/serverless.js +7 -0
  138. package/packages/dd-trace/src/plugins/util/stacktrace.js +94 -0
  139. package/packages/dd-trace/src/plugins/util/tags.js +7 -0
  140. package/packages/dd-trace/src/plugins/util/test.js +20 -22
  141. package/packages/dd-trace/src/plugins/util/web.js +6 -4
  142. package/packages/dd-trace/src/priority_sampler.js +16 -0
  143. package/packages/dd-trace/src/profiling/config.js +3 -1
  144. package/packages/dd-trace/src/profiling/exporters/agent.js +7 -5
  145. package/packages/dd-trace/src/profiling/profiler.js +24 -14
  146. package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
  147. package/packages/dd-trace/src/profiling/profilers/wall.js +95 -66
  148. package/packages/dd-trace/src/proxy.js +20 -1
  149. package/packages/dd-trace/src/service-naming/schemas/v0/index.js +2 -1
  150. package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +12 -0
  151. package/packages/dd-trace/src/service-naming/schemas/v1/index.js +2 -1
  152. package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +12 -0
  153. package/packages/dd-trace/src/span_processor.js +5 -0
  154. package/packages/dd-trace/src/telemetry/index.js +11 -1
  155. package/packages/datadog-core/src/storage/async_resource.js +0 -108
  156. package/packages/datadog-core/src/storage/index.js +0 -5
@@ -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
 
@@ -0,0 +1,37 @@
1
+ const shimmer = require('../../datadog-shimmer')
2
+ const { addHook } = require('./helpers/instrument')
3
+
4
+ const dc = require('dc-polyfill')
5
+ const serializeChannel = dc.channel('apm:avsc:serialize-start')
6
+ const deserializeChannel = dc.channel('apm:avsc:deserialize-end')
7
+
8
+ function wrapSerialization (Type) {
9
+ shimmer.wrap(Type.prototype, 'toBuffer', original => function () {
10
+ if (!serializeChannel.hasSubscribers) {
11
+ return original.apply(this, arguments)
12
+ }
13
+ serializeChannel.publish({ messageClass: this })
14
+ return original.apply(this, arguments)
15
+ })
16
+ }
17
+
18
+ function wrapDeserialization (Type) {
19
+ shimmer.wrap(Type.prototype, 'fromBuffer', original => function () {
20
+ if (!deserializeChannel.hasSubscribers) {
21
+ return original.apply(this, arguments)
22
+ }
23
+ const result = original.apply(this, arguments)
24
+ deserializeChannel.publish({ messageClass: result })
25
+ return result
26
+ })
27
+ }
28
+
29
+ addHook({
30
+ name: 'avsc',
31
+ versions: ['>=5.0.0']
32
+ }, avro => {
33
+ wrapDeserialization(avro.Type)
34
+ wrapSerialization(avro.Type)
35
+
36
+ return avro
37
+ })
@@ -0,0 +1,48 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ addHook
5
+ } = require('./helpers/instrument')
6
+ const shimmer = require('../../datadog-shimmer')
7
+ const dc = require('dc-polyfill')
8
+
9
+ const azureFunctionsChannel = dc.tracingChannel('datadog:azure-functions:invoke')
10
+
11
+ addHook({ name: '@azure/functions', versions: ['>=4'] }, azureFunction => {
12
+ const { app } = azureFunction
13
+
14
+ shimmer.wrap(app, 'deleteRequest', wrapHandler)
15
+ shimmer.wrap(app, 'http', wrapHandler)
16
+ shimmer.wrap(app, 'get', wrapHandler)
17
+ shimmer.wrap(app, 'patch', wrapHandler)
18
+ shimmer.wrap(app, 'post', wrapHandler)
19
+ shimmer.wrap(app, 'put', wrapHandler)
20
+
21
+ return azureFunction
22
+ })
23
+
24
+ // The http methods are overloaded so we need to check which type of argument was passed in order to wrap the handler
25
+ // The arguments are either an object with a handler property or the handler function itself
26
+ function wrapHandler (method) {
27
+ return function (name, arg) {
28
+ if (typeof arg === 'object' && arg.hasOwnProperty('handler')) {
29
+ const options = arg
30
+ shimmer.wrap(options, 'handler', handler => traceHandler(handler, name, method.name))
31
+ } else if (typeof arg === 'function') {
32
+ const handler = arg
33
+ arguments[1] = shimmer.wrapFunction(handler, handler => traceHandler(handler, name, method.name))
34
+ }
35
+ return method.apply(this, arguments)
36
+ }
37
+ }
38
+
39
+ function traceHandler (handler, functionName, methodName) {
40
+ return function (...args) {
41
+ const httpRequest = args[0]
42
+ const invocationContext = args[1]
43
+ return azureFunctionsChannel.tracePromise(
44
+ handler,
45
+ { functionName, httpRequest, invocationContext, methodName },
46
+ this, ...args)
47
+ }
48
+ }
@@ -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) {
@@ -61,14 +98,33 @@ function wrapChildProcessSyncMethod (shell = false) {
61
98
 
62
99
  const childProcessInfo = normalizeArgs(arguments, shell)
63
100
 
64
- return childProcessChannel.traceSync(
65
- childProcessMethod,
66
- {
67
- command: childProcessInfo.command,
68
- shell: childProcessInfo.shell
69
- },
70
- this,
71
- ...arguments)
101
+ const innerResource = new AsyncResource('bound-anonymous-fn')
102
+ return innerResource.runInAsyncScope(() => {
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
+ }
127
+ })
72
128
  }
73
129
  }
74
130
  }
@@ -81,18 +137,52 @@ function wrapChildProcessCustomPromisifyMethod (customPromisifyMethod, shell) {
81
137
 
82
138
  const childProcessInfo = normalizeArgs(arguments, shell)
83
139
 
84
- return childProcessChannel.tracePromise(
85
- customPromisifyMethod,
86
- {
87
- command: childProcessInfo.command,
88
- shell: childProcessInfo.shell
89
- },
90
- this,
91
- ...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)
92
182
  }
93
183
  }
94
184
 
95
- function wrapChildProcessAsyncMethod (shell = false) {
185
+ function wrapChildProcessAsyncMethod (ChildProcess, shell = false) {
96
186
  return function wrapMethod (childProcessMethod) {
97
187
  function wrappedChildProcessMethod () {
98
188
  if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
@@ -101,11 +191,39 @@ function wrapChildProcessAsyncMethod (shell = false) {
101
191
 
102
192
  const childProcessInfo = normalizeArgs(arguments, shell)
103
193
 
194
+ const cb = arguments[arguments.length - 1]
195
+ if (typeof cb === 'function') {
196
+ const callbackResource = new AsyncResource('bound-anonymous-fn')
197
+ arguments[arguments.length - 1] = callbackResource.bind(cb)
198
+ }
199
+
104
200
  const innerResource = new AsyncResource('bound-anonymous-fn')
105
201
  return innerResource.runInAsyncScope(() => {
106
- 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
+ }
107
226
 
108
- const childProcess = childProcessMethod.apply(this, arguments)
109
227
  if (childProcess) {
110
228
  let errorExecuted = false
111
229
 
@@ -120,8 +238,7 @@ function wrapChildProcessAsyncMethod (shell = false) {
120
238
  childProcessChannel.error.publish()
121
239
  }
122
240
  childProcessChannel.asyncEnd.publish({
123
- command: childProcessInfo.command,
124
- shell: childProcessInfo.shell,
241
+ ...context,
125
242
  result: code
126
243
  })
127
244
  })
@@ -3,6 +3,7 @@
3
3
  const { createWrapRouterMethod } = require('./router')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
  const { addHook, channel } = require('./helpers/instrument')
6
+ const tracingChannel = require('dc-polyfill').tracingChannel
6
7
 
7
8
  const handleChannel = channel('apm:express:request:handle')
8
9
 
@@ -35,6 +36,27 @@ function wrapResponseJson (json) {
35
36
  }
36
37
  }
37
38
 
39
+ const responseRenderChannel = tracingChannel('datadog:express:response:render')
40
+
41
+ function wrapResponseRender (render) {
42
+ return function wrappedRender (view, options, callback) {
43
+ if (!responseRenderChannel.start.hasSubscribers) {
44
+ return render.apply(this, arguments)
45
+ }
46
+
47
+ return responseRenderChannel.traceSync(
48
+ render,
49
+ {
50
+ req: this.req,
51
+ view,
52
+ options
53
+ },
54
+ this,
55
+ ...arguments
56
+ )
57
+ }
58
+ }
59
+
38
60
  addHook({ name: 'express', versions: ['>=4'] }, express => {
39
61
  shimmer.wrap(express.application, 'handle', wrapHandle)
40
62
  shimmer.wrap(express.Router, 'use', wrapRouterMethod)
@@ -42,6 +64,7 @@ addHook({ name: 'express', versions: ['>=4'] }, express => {
42
64
 
43
65
  shimmer.wrap(express.response, 'json', wrapResponseJson)
44
66
  shimmer.wrap(express.response, 'jsonp', wrapResponseJson)
67
+ shimmer.wrap(express.response, 'render', wrapResponseRender)
45
68
 
46
69
  return express
47
70
  })
@@ -79,11 +102,21 @@ addHook({
79
102
  })
80
103
 
81
104
  const processParamsStartCh = channel('datadog:express:process_params:start')
82
- const wrapProcessParamsMethod = (requestPositionInArguments) => {
83
- return (original) => {
84
- return function () {
105
+ function wrapProcessParamsMethod (requestPositionInArguments) {
106
+ return function wrapProcessParams (original) {
107
+ return function wrappedProcessParams () {
85
108
  if (processParamsStartCh.hasSubscribers) {
86
- processParamsStartCh.publish({ req: arguments[requestPositionInArguments] })
109
+ const req = arguments[requestPositionInArguments]
110
+ const abortController = new AbortController()
111
+
112
+ processParamsStartCh.publish({
113
+ req,
114
+ res: req?.res,
115
+ abortController,
116
+ params: req?.params
117
+ })
118
+
119
+ if (abortController.signal.aborted) return
87
120
  }
88
121
 
89
122
  return original.apply(this, arguments)
@@ -5,6 +5,7 @@ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
5
 
6
6
  const errorChannel = channel('apm:fastify:middleware:error')
7
7
  const handleChannel = channel('apm:fastify:request:handle')
8
+ const routeAddedChannel = channel('apm:fastify:route:added')
8
9
 
9
10
  const parsingResources = new WeakMap()
10
11
 
@@ -16,6 +17,7 @@ function wrapFastify (fastify, hasParsingEvents) {
16
17
 
17
18
  if (!app || typeof app.addHook !== 'function') return app
18
19
 
20
+ app.addHook('onRoute', onRoute)
19
21
  app.addHook('onRequest', onRequest)
20
22
  app.addHook('preHandler', preHandler)
21
23
 
@@ -86,8 +88,9 @@ function onRequest (request, reply, done) {
86
88
 
87
89
  const req = getReq(request)
88
90
  const res = getRes(reply)
91
+ const routeConfig = getRouteConfig(request)
89
92
 
90
- handleChannel.publish({ req, res })
93
+ handleChannel.publish({ req, res, routeConfig })
91
94
 
92
95
  return done()
93
96
  }
@@ -142,6 +145,10 @@ function getRes (reply) {
142
145
  return reply && (reply.raw || reply.res || reply)
143
146
  }
144
147
 
148
+ function getRouteConfig (request) {
149
+ return request?.routeOptions?.config
150
+ }
151
+
145
152
  function publishError (error, req) {
146
153
  if (error) {
147
154
  errorChannel.publish({ error, req })
@@ -150,6 +157,10 @@ function publishError (error, req) {
150
157
  return error
151
158
  }
152
159
 
160
+ function onRoute (routeOptions) {
161
+ routeAddedChannel.publish({ routeOptions, onRoute })
162
+ }
163
+
153
164
  addHook({ name: 'fastify', versions: ['>=3'] }, fastify => {
154
165
  const wrapped = shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, true))
155
166
 
@@ -266,24 +266,44 @@ function createWrapFunction (prefix = '', override = '') {
266
266
  const lastIndex = arguments.length - 1
267
267
  const cb = typeof arguments[lastIndex] === 'function' && arguments[lastIndex]
268
268
  const innerResource = new AsyncResource('bound-anonymous-fn')
269
- const message = getMessage(method, getMethodParamsRelationByPrefix(prefix)[operation], arguments, this)
269
+ const params = getMethodParamsRelationByPrefix(prefix)[operation]
270
+ const abortController = new AbortController()
271
+ const message = { ...getMessage(method, params, arguments, this), abortController }
272
+
273
+ const finish = innerResource.bind(function (error) {
274
+ if (error !== null && typeof error === 'object') { // fs.exists receives a boolean
275
+ errorChannel.publish(error)
276
+ }
277
+ finishChannel.publish()
278
+ })
270
279
 
271
280
  if (cb) {
272
281
  const outerResource = new AsyncResource('bound-anonymous-fn')
273
282
 
274
283
  arguments[lastIndex] = shimmer.wrapFunction(cb, cb => innerResource.bind(function (e) {
275
- if (e !== null && typeof e === 'object') { // fs.exists receives a boolean
276
- errorChannel.publish(e)
277
- }
278
-
279
- finishChannel.publish()
280
-
284
+ finish(e)
281
285
  return outerResource.runInAsyncScope(() => cb.apply(this, arguments))
282
286
  }))
283
287
  }
284
288
 
285
289
  return innerResource.runInAsyncScope(() => {
286
290
  startChannel.publish(message)
291
+
292
+ if (abortController.signal.aborted) {
293
+ const error = abortController.signal.reason || new Error('Aborted')
294
+
295
+ if (prefix === 'promises.') {
296
+ finish(error)
297
+ return Promise.reject(error)
298
+ } else if (name.includes('Sync') || !cb) {
299
+ finish(error)
300
+ throw error
301
+ } else if (cb) {
302
+ arguments[lastIndex](error)
303
+ return
304
+ }
305
+ }
306
+
287
307
  try {
288
308
  const result = original.apply(this, arguments)
289
309
  if (cb) return result
@@ -5,6 +5,7 @@ module.exports = {
5
5
  '@apollo/gateway': () => require('../apollo'),
6
6
  'apollo-server-core': () => require('../apollo-server-core'),
7
7
  '@aws-sdk/smithy-client': () => require('../aws-sdk'),
8
+ '@azure/functions': () => require('../azure-functions'),
8
9
  '@cucumber/cucumber': () => require('../cucumber'),
9
10
  '@playwright/test': () => require('../playwright'),
10
11
  '@elastic/elasticsearch': () => require('../elasticsearch'),
@@ -27,6 +28,7 @@ module.exports = {
27
28
  aerospike: () => require('../aerospike'),
28
29
  amqp10: () => require('../amqp10'),
29
30
  amqplib: () => require('../amqplib'),
31
+ avsc: () => require('../avsc'),
30
32
  'aws-sdk': () => require('../aws-sdk'),
31
33
  bluebird: () => require('../bluebird'),
32
34
  'body-parser': () => require('../body-parser'),
@@ -77,6 +79,7 @@ module.exports = {
77
79
  'mongodb-core': () => require('../mongodb-core'),
78
80
  mongoose: () => require('../mongoose'),
79
81
  mquery: () => require('../mquery'),
82
+ multer: () => require('../multer'),
80
83
  mysql: () => require('../mysql'),
81
84
  mysql2: () => require('../mysql2'),
82
85
  net: () => require('../net'),
@@ -88,6 +91,7 @@ module.exports = {
88
91
  'node:http2': () => require('../http2'),
89
92
  'node:https': () => require('../http'),
90
93
  'node:net': () => require('../net'),
94
+ 'node:url': () => require('../url'),
91
95
  nyc: () => require('../nyc'),
92
96
  oracledb: () => require('../oracledb'),
93
97
  openai: () => require('../openai'),
@@ -100,6 +104,7 @@ module.exports = {
100
104
  playwright: () => require('../playwright'),
101
105
  'promise-js': () => require('../promise-js'),
102
106
  promise: () => require('../promise'),
107
+ protobufjs: () => require('../protobufjs'),
103
108
  q: () => require('../q'),
104
109
  qs: () => require('../qs'),
105
110
  redis: () => require('../redis'),
@@ -111,6 +116,7 @@ module.exports = {
111
116
  sharedb: () => require('../sharedb'),
112
117
  tedious: () => require('../tedious'),
113
118
  undici: () => require('../undici'),
119
+ url: () => require('../url'),
114
120
  vitest: { esmFirst: true, fn: () => require('../vitest') },
115
121
  when: () => require('../when'),
116
122
  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
@@ -850,7 +850,8 @@ addHook({
850
850
  }, jestConfigSyncWrapper)
851
851
 
852
852
  const LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = [
853
- 'selenium-webdriver'
853
+ 'selenium-webdriver',
854
+ 'winston'
854
855
  ]
855
856
 
856
857
  function shouldBypassJestRequireEngine (moduleName) {