dd-trace 5.24.0 → 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.
- package/LICENSE-3rdparty.csv +1 -0
- package/index.d.ts +335 -0
- package/package.json +13 -7
- package/packages/datadog-code-origin/index.js +4 -4
- package/packages/datadog-core/src/utils/src/parse-tags.js +33 -0
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-instrumentations/src/amqplib.js +65 -5
- package/packages/datadog-instrumentations/src/child_process.js +135 -27
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -0
- package/packages/datadog-instrumentations/src/kafkajs.js +123 -63
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -2
- package/packages/datadog-instrumentations/src/multer.js +37 -0
- package/packages/datadog-instrumentations/src/openai.js +2 -2
- package/packages/datadog-instrumentations/src/url.js +84 -0
- package/packages/datadog-instrumentations/src/utils/src/extract-package-and-module-path.js +7 -4
- package/packages/datadog-plugin-amqplib/src/consumer.js +4 -4
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
- package/packages/datadog-plugin-fastify/src/code_origin.js +2 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +8 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +8 -0
- package/packages/datadog-plugin-grpc/src/client.js +3 -0
- package/packages/datadog-plugin-grpc/src/server.js +3 -0
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +6 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +8 -4
- package/packages/datadog-plugin-kafkajs/src/producer.js +10 -4
- package/packages/datadog-plugin-mocha/src/index.js +4 -1
- package/packages/datadog-plugin-openai/src/index.js +9 -1015
- package/packages/datadog-plugin-openai/src/tracing.js +1023 -0
- package/packages/dd-trace/src/appsec/addresses.js +2 -0
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +55 -7
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -2
- package/packages/dd-trace/src/appsec/index.js +3 -0
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +49 -0
- package/packages/dd-trace/src/appsec/rasp/index.js +3 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +4 -3
- package/packages/dd-trace/src/appsec/rasp/utils.js +3 -2
- package/packages/dd-trace/src/appsec/recommended.json +2 -4
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +2 -0
- package/packages/dd-trace/src/appsec/reporter.js +5 -4
- package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -3
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +4 -0
- package/packages/dd-trace/src/azure_metadata.js +120 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +97 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +90 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +53 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +8 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +43 -0
- package/packages/dd-trace/src/config.js +75 -6
- package/packages/dd-trace/src/constants.js +3 -1
- package/packages/dd-trace/src/datastreams/pathway.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +9 -13
- package/packages/dd-trace/src/debugger/devtools_client/send.js +15 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +57 -23
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +12 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +31 -20
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +6 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +11 -2
- package/packages/dd-trace/src/debugger/index.js +10 -3
- package/packages/dd-trace/src/llmobs/constants/tags.js +34 -0
- package/packages/dd-trace/src/llmobs/constants/text.js +6 -0
- package/packages/dd-trace/src/llmobs/constants/writers.js +13 -0
- package/packages/dd-trace/src/llmobs/index.js +103 -0
- package/packages/dd-trace/src/llmobs/noop.js +82 -0
- package/packages/dd-trace/src/llmobs/plugins/base.js +65 -0
- package/packages/dd-trace/src/llmobs/plugins/openai.js +205 -0
- package/packages/dd-trace/src/llmobs/sdk.js +377 -0
- package/packages/dd-trace/src/llmobs/span_processor.js +195 -0
- package/packages/dd-trace/src/llmobs/storage.js +7 -0
- package/packages/dd-trace/src/llmobs/tagger.js +322 -0
- package/packages/dd-trace/src/llmobs/util.js +176 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +111 -0
- package/packages/dd-trace/src/llmobs/writers/evaluations.js +29 -0
- package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +23 -0
- package/packages/dd-trace/src/llmobs/writers/spans/agentless.js +17 -0
- package/packages/dd-trace/src/llmobs/writers/spans/base.js +49 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/noop/span.js +3 -0
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentelemetry/tracer.js +1 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +73 -12
- package/packages/dd-trace/src/opentracing/span.js +12 -0
- package/packages/dd-trace/src/opentracing/tracer.js +8 -1
- package/packages/dd-trace/src/payload-tagging/config/aws.json +71 -3
- package/packages/dd-trace/src/plugins/outbound.js +9 -0
- package/packages/dd-trace/src/priority_sampler.js +16 -0
- package/packages/dd-trace/src/profiling/config.js +3 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +7 -5
- package/packages/dd-trace/src/profiling/profilers/wall.js +2 -1
- package/packages/dd-trace/src/proxy.js +8 -1
- package/packages/dd-trace/src/span_processor.js +5 -0
- package/packages/dd-trace/src/telemetry/index.js +11 -1
|
@@ -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.
|
|
28
|
-
shimmer.wrap(childProcess, '
|
|
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
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
133
|
-
shell: childProcessInfo.shell,
|
|
241
|
+
...context,
|
|
134
242
|
result: code
|
|
135
243
|
})
|
|
136
244
|
})
|
|
@@ -79,6 +79,7 @@ module.exports = {
|
|
|
79
79
|
'mongodb-core': () => require('../mongodb-core'),
|
|
80
80
|
mongoose: () => require('../mongoose'),
|
|
81
81
|
mquery: () => require('../mquery'),
|
|
82
|
+
multer: () => require('../multer'),
|
|
82
83
|
mysql: () => require('../mysql'),
|
|
83
84
|
mysql2: () => require('../mysql2'),
|
|
84
85
|
net: () => require('../net'),
|
|
@@ -90,6 +91,7 @@ module.exports = {
|
|
|
90
91
|
'node:http2': () => require('../http2'),
|
|
91
92
|
'node:https': () => require('../http'),
|
|
92
93
|
'node:net': () => require('../net'),
|
|
94
|
+
'node:url': () => require('../url'),
|
|
93
95
|
nyc: () => require('../nyc'),
|
|
94
96
|
oracledb: () => require('../oracledb'),
|
|
95
97
|
openai: () => require('../openai'),
|
|
@@ -114,6 +116,7 @@ module.exports = {
|
|
|
114
116
|
sharedb: () => require('../sharedb'),
|
|
115
117
|
tedious: () => require('../tedious'),
|
|
116
118
|
undici: () => require('../undici'),
|
|
119
|
+
url: () => require('../url'),
|
|
117
120
|
vitest: { esmFirst: true, fn: () => require('../vitest') },
|
|
118
121
|
when: () => require('../when'),
|
|
119
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
|
|
@@ -52,45 +52,59 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
52
52
|
const send = producer.send
|
|
53
53
|
const bootstrapServers = this._brokers
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
55
|
+
const kafkaClusterIdPromise = getKafkaClusterId(this)
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
57
|
+
producer.send = function () {
|
|
58
|
+
const wrappedSend = (clusterId) => {
|
|
59
|
+
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (message !== null && typeof message === 'object') {
|
|
67
|
-
message.headers = message.headers || {}
|
|
68
|
-
}
|
|
61
|
+
return innerAsyncResource.runInAsyncScope(() => {
|
|
62
|
+
if (!producerStartCh.hasSubscribers) {
|
|
63
|
+
return send.apply(this, arguments)
|
|
69
64
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
producerFinishCh.publish(undefined)
|
|
77
|
-
producerCommitCh.publish(res)
|
|
78
|
-
}),
|
|
79
|
-
innerAsyncResource.bind(err => {
|
|
80
|
-
if (err) {
|
|
81
|
-
producerErrorCh.publish(err)
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const { topic, messages = [] } = arguments[0]
|
|
68
|
+
for (const message of messages) {
|
|
69
|
+
if (message !== null && typeof message === 'object') {
|
|
70
|
+
message.headers = message.headers || {}
|
|
82
71
|
}
|
|
83
|
-
|
|
84
|
-
})
|
|
85
|
-
)
|
|
72
|
+
}
|
|
73
|
+
producerStartCh.publish({ topic, messages, bootstrapServers, clusterId })
|
|
86
74
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
75
|
+
const result = send.apply(this, arguments)
|
|
76
|
+
|
|
77
|
+
result.then(
|
|
78
|
+
innerAsyncResource.bind(res => {
|
|
79
|
+
producerFinishCh.publish(undefined)
|
|
80
|
+
producerCommitCh.publish(res)
|
|
81
|
+
}),
|
|
82
|
+
innerAsyncResource.bind(err => {
|
|
83
|
+
if (err) {
|
|
84
|
+
producerErrorCh.publish(err)
|
|
85
|
+
}
|
|
86
|
+
producerFinishCh.publish(undefined)
|
|
87
|
+
})
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return result
|
|
91
|
+
} catch (e) {
|
|
92
|
+
producerErrorCh.publish(e)
|
|
93
|
+
producerFinishCh.publish(undefined)
|
|
94
|
+
throw e
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!isPromise(kafkaClusterIdPromise)) {
|
|
100
|
+
// promise is already resolved
|
|
101
|
+
return wrappedSend(kafkaClusterIdPromise)
|
|
102
|
+
} else {
|
|
103
|
+
// promise is not resolved
|
|
104
|
+
return kafkaClusterIdPromise.then((clusterId) => {
|
|
105
|
+
return wrappedSend(clusterId)
|
|
106
|
+
})
|
|
107
|
+
}
|
|
94
108
|
}
|
|
95
109
|
return producer
|
|
96
110
|
})
|
|
@@ -100,15 +114,17 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
100
114
|
return createConsumer.apply(this, arguments)
|
|
101
115
|
}
|
|
102
116
|
|
|
103
|
-
const
|
|
117
|
+
const kafkaClusterIdPromise = getKafkaClusterId(this)
|
|
118
|
+
|
|
119
|
+
const eachMessageExtractor = (args, clusterId) => {
|
|
104
120
|
const { topic, partition, message } = args[0]
|
|
105
|
-
return { topic, partition, message, groupId }
|
|
121
|
+
return { topic, partition, message, groupId, clusterId }
|
|
106
122
|
}
|
|
107
123
|
|
|
108
|
-
const eachBatchExtractor = (args) => {
|
|
124
|
+
const eachBatchExtractor = (args, clusterId) => {
|
|
109
125
|
const { batch } = args[0]
|
|
110
126
|
const { topic, partition, messages } = batch
|
|
111
|
-
return { topic, partition, messages, groupId }
|
|
127
|
+
return { topic, partition, messages, groupId, clusterId }
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
const consumer = createConsumer.apply(this, arguments)
|
|
@@ -116,43 +132,53 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
116
132
|
consumer.on(consumer.events.COMMIT_OFFSETS, commitsFromEvent)
|
|
117
133
|
|
|
118
134
|
const run = consumer.run
|
|
119
|
-
|
|
120
135
|
const groupId = arguments[0].groupId
|
|
136
|
+
|
|
121
137
|
consumer.run = function ({ eachMessage, eachBatch, ...runArgs }) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
138
|
+
const wrapConsume = (clusterId) => {
|
|
139
|
+
return run({
|
|
140
|
+
eachMessage: wrappedCallback(
|
|
141
|
+
eachMessage,
|
|
142
|
+
consumerStartCh,
|
|
143
|
+
consumerFinishCh,
|
|
144
|
+
consumerErrorCh,
|
|
145
|
+
eachMessageExtractor,
|
|
146
|
+
clusterId
|
|
147
|
+
),
|
|
148
|
+
eachBatch: wrappedCallback(
|
|
149
|
+
eachBatch,
|
|
150
|
+
batchConsumerStartCh,
|
|
151
|
+
batchConsumerFinishCh,
|
|
152
|
+
batchConsumerErrorCh,
|
|
153
|
+
eachBatchExtractor,
|
|
154
|
+
clusterId
|
|
155
|
+
),
|
|
156
|
+
...runArgs
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!isPromise(kafkaClusterIdPromise)) {
|
|
161
|
+
// promise is already resolved
|
|
162
|
+
return wrapConsume(kafkaClusterIdPromise)
|
|
163
|
+
} else {
|
|
164
|
+
// promise is not resolved
|
|
165
|
+
return kafkaClusterIdPromise.then((clusterId) => {
|
|
166
|
+
return wrapConsume(clusterId)
|
|
167
|
+
})
|
|
168
|
+
}
|
|
143
169
|
}
|
|
144
|
-
|
|
145
170
|
return consumer
|
|
146
171
|
})
|
|
147
172
|
return Kafka
|
|
148
173
|
})
|
|
149
174
|
|
|
150
|
-
const
|
|
175
|
+
const wrappedCallback = (fn, startCh, finishCh, errorCh, extractArgs, clusterId) => {
|
|
151
176
|
return typeof fn === 'function'
|
|
152
177
|
? function (...args) {
|
|
153
178
|
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
154
179
|
return innerAsyncResource.runInAsyncScope(() => {
|
|
155
|
-
const extractedArgs = extractArgs(args)
|
|
180
|
+
const extractedArgs = extractArgs(args, clusterId)
|
|
181
|
+
|
|
156
182
|
startCh.publish(extractedArgs)
|
|
157
183
|
try {
|
|
158
184
|
const result = fn.apply(this, args)
|
|
@@ -179,3 +205,37 @@ const wrapFunction = (fn, startCh, finishCh, errorCh, extractArgs) => {
|
|
|
179
205
|
}
|
|
180
206
|
: fn
|
|
181
207
|
}
|
|
208
|
+
|
|
209
|
+
const getKafkaClusterId = (kafka) => {
|
|
210
|
+
if (kafka._ddKafkaClusterId) {
|
|
211
|
+
return kafka._ddKafkaClusterId
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (!kafka.admin) {
|
|
215
|
+
return null
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const admin = kafka.admin()
|
|
219
|
+
|
|
220
|
+
if (!admin.describeCluster) {
|
|
221
|
+
return null
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return admin.connect()
|
|
225
|
+
.then(() => {
|
|
226
|
+
return admin.describeCluster()
|
|
227
|
+
})
|
|
228
|
+
.then((clusterInfo) => {
|
|
229
|
+
const clusterId = clusterInfo?.clusterId
|
|
230
|
+
kafka._ddKafkaClusterId = clusterId
|
|
231
|
+
admin.disconnect()
|
|
232
|
+
return clusterId
|
|
233
|
+
})
|
|
234
|
+
.catch((error) => {
|
|
235
|
+
throw error
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function isPromise (obj) {
|
|
240
|
+
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
|
|
241
|
+
}
|
|
@@ -280,12 +280,12 @@ function getOnFailHandler (isMain) {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
function getOnTestRetryHandler () {
|
|
283
|
-
return function (test) {
|
|
283
|
+
return function (test, err) {
|
|
284
284
|
const asyncResource = getTestAsyncResource(test)
|
|
285
285
|
if (asyncResource) {
|
|
286
286
|
const isFirstAttempt = test._currentRetry === 0
|
|
287
287
|
asyncResource.runInAsyncScope(() => {
|
|
288
|
-
testRetryCh.publish(isFirstAttempt)
|
|
288
|
+
testRetryCh.publish({ isFirstAttempt, err })
|
|
289
289
|
})
|
|
290
290
|
}
|
|
291
291
|
const key = getTestToArKey(test)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const shimmer = require('../../datadog-shimmer')
|
|
4
|
+
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
|
|
5
|
+
|
|
6
|
+
const multerReadCh = channel('datadog:multer:read:finish')
|
|
7
|
+
|
|
8
|
+
function publishRequestBodyAndNext (req, res, next) {
|
|
9
|
+
return shimmer.wrapFunction(next, next => function () {
|
|
10
|
+
if (multerReadCh.hasSubscribers && req) {
|
|
11
|
+
const abortController = new AbortController()
|
|
12
|
+
const body = req.body
|
|
13
|
+
|
|
14
|
+
multerReadCh.publish({ req, res, body, abortController })
|
|
15
|
+
|
|
16
|
+
if (abortController.signal.aborted) return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return next.apply(this, arguments)
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
addHook({
|
|
24
|
+
name: 'multer',
|
|
25
|
+
file: 'lib/make-middleware.js',
|
|
26
|
+
versions: ['^1.4.4-lts.1']
|
|
27
|
+
}, makeMiddleware => {
|
|
28
|
+
return shimmer.wrapFunction(makeMiddleware, makeMiddleware => function () {
|
|
29
|
+
const middleware = makeMiddleware.apply(this, arguments)
|
|
30
|
+
|
|
31
|
+
return shimmer.wrapFunction(middleware, middleware => function wrapMulterMiddleware (req, res, next) {
|
|
32
|
+
const nextResource = new AsyncResource('bound-anonymous-fn')
|
|
33
|
+
arguments[2] = nextResource.bind(publishRequestBodyAndNext(req, res, next))
|
|
34
|
+
return middleware.apply(this, arguments)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const { addHook } = require('./helpers/instrument')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const ch = tracingChannel('apm:openai:request')
|
|
6
|
+
const dc = require('dc-polyfill')
|
|
7
|
+
const ch = dc.tracingChannel('apm:openai:request')
|
|
8
8
|
|
|
9
9
|
const V4_PACKAGE_SHIMS = [
|
|
10
10
|
{
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
const names = ['url', 'node:url']
|
|
6
|
+
|
|
7
|
+
const parseFinishedChannel = channel('datadog:url:parse:finish')
|
|
8
|
+
const urlGetterChannel = channel('datadog:url:getter:finish')
|
|
9
|
+
const instrumentedGetters = ['host', 'origin', 'hostname']
|
|
10
|
+
|
|
11
|
+
addHook({ name: names }, function (url) {
|
|
12
|
+
shimmer.wrap(url, 'parse', (parse) => {
|
|
13
|
+
return function wrappedParse (input) {
|
|
14
|
+
const parsedValue = parse.apply(this, arguments)
|
|
15
|
+
if (!parseFinishedChannel.hasSubscribers) return parsedValue
|
|
16
|
+
|
|
17
|
+
parseFinishedChannel.publish({
|
|
18
|
+
input,
|
|
19
|
+
parsed: parsedValue,
|
|
20
|
+
isURL: false
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return parsedValue
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const URLPrototype = url.URL.prototype.constructor.prototype
|
|
28
|
+
instrumentedGetters.forEach(property => {
|
|
29
|
+
const originalDescriptor = Object.getOwnPropertyDescriptor(URLPrototype, property)
|
|
30
|
+
|
|
31
|
+
if (originalDescriptor?.get) {
|
|
32
|
+
const newDescriptor = shimmer.wrap(originalDescriptor, 'get', function (originalGet) {
|
|
33
|
+
return function get () {
|
|
34
|
+
const result = originalGet.apply(this, arguments)
|
|
35
|
+
if (!urlGetterChannel.hasSubscribers) return result
|
|
36
|
+
|
|
37
|
+
const context = { urlObject: this, result, property }
|
|
38
|
+
urlGetterChannel.publish(context)
|
|
39
|
+
|
|
40
|
+
return context.result
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
Object.defineProperty(URLPrototype, property, newDescriptor)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
shimmer.wrap(url, 'URL', (URL) => {
|
|
49
|
+
return class extends URL {
|
|
50
|
+
constructor (input, base) {
|
|
51
|
+
super(...arguments)
|
|
52
|
+
|
|
53
|
+
if (!parseFinishedChannel.hasSubscribers) return
|
|
54
|
+
|
|
55
|
+
parseFinishedChannel.publish({
|
|
56
|
+
input,
|
|
57
|
+
base,
|
|
58
|
+
parsed: this,
|
|
59
|
+
isURL: true
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
if (url.URL.parse) {
|
|
66
|
+
shimmer.wrap(url.URL, 'parse', (parse) => {
|
|
67
|
+
return function wrappedParse (input, base) {
|
|
68
|
+
const parsedValue = parse.apply(this, arguments)
|
|
69
|
+
if (!parseFinishedChannel.hasSubscribers) return parsedValue
|
|
70
|
+
|
|
71
|
+
parseFinishedChannel.publish({
|
|
72
|
+
input,
|
|
73
|
+
base,
|
|
74
|
+
parsed: parsedValue,
|
|
75
|
+
isURL: true
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return parsedValue
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return url
|
|
84
|
+
})
|
|
@@ -6,7 +6,7 @@ const NM = 'node_modules/'
|
|
|
6
6
|
* For a given full path to a module,
|
|
7
7
|
* return the package name it belongs to and the local path to the module
|
|
8
8
|
* input: '/foo/node_modules/@co/stuff/foo/bar/baz.js'
|
|
9
|
-
* output: { pkg: '@co/stuff', path: 'foo/bar/baz.js' }
|
|
9
|
+
* output: { pkg: '@co/stuff', path: 'foo/bar/baz.js', pkgJson: '/foo/node_modules/@co/stuff/package.json' }
|
|
10
10
|
*/
|
|
11
11
|
module.exports = function extractPackageAndModulePath (fullPath) {
|
|
12
12
|
const nm = fullPath.lastIndexOf(NM)
|
|
@@ -17,17 +17,20 @@ module.exports = function extractPackageAndModulePath (fullPath) {
|
|
|
17
17
|
const subPath = fullPath.substring(nm + NM.length)
|
|
18
18
|
const firstSlash = subPath.indexOf('/')
|
|
19
19
|
|
|
20
|
+
const firstPath = fullPath.substring(fullPath[0], nm + NM.length)
|
|
21
|
+
|
|
20
22
|
if (subPath[0] === '@') {
|
|
21
23
|
const secondSlash = subPath.substring(firstSlash + 1).indexOf('/')
|
|
22
|
-
|
|
23
24
|
return {
|
|
24
25
|
pkg: subPath.substring(0, firstSlash + 1 + secondSlash),
|
|
25
|
-
path: subPath.substring(firstSlash + 1 + secondSlash + 1)
|
|
26
|
+
path: subPath.substring(firstSlash + 1 + secondSlash + 1),
|
|
27
|
+
pkgJson: firstPath + subPath.substring(0, firstSlash + 1 + secondSlash) + '/package.json'
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
return {
|
|
30
32
|
pkg: subPath.substring(0, firstSlash),
|
|
31
|
-
path: subPath.substring(firstSlash + 1)
|
|
33
|
+
path: subPath.substring(firstSlash + 1),
|
|
34
|
+
pkgJson: firstPath + subPath.substring(0, firstSlash) + '/package.json'
|
|
32
35
|
}
|
|
33
36
|
}
|