dd-trace 5.95.0 → 5.97.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/index.d.ts +43 -0
- package/package.json +10 -8
- package/packages/datadog-esbuild/index.js +20 -9
- package/packages/datadog-instrumentations/src/ai.js +112 -0
- package/packages/datadog-instrumentations/src/child_process.js +7 -17
- package/packages/datadog-instrumentations/src/crypto.js +1 -2
- package/packages/datadog-instrumentations/src/cucumber.js +4 -1
- package/packages/datadog-instrumentations/src/cypress-config.js +324 -0
- package/packages/datadog-instrumentations/src/cypress.js +86 -4
- package/packages/datadog-instrumentations/src/dns.js +1 -2
- package/packages/datadog-instrumentations/src/express.js +4 -4
- package/packages/datadog-instrumentations/src/fs.js +27 -29
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +182 -0
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
- package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
- package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +25 -0
- package/packages/datadog-instrumentations/src/http/client.js +2 -3
- package/packages/datadog-instrumentations/src/http/server.js +2 -5
- package/packages/datadog-instrumentations/src/http2/client.js +1 -3
- package/packages/datadog-instrumentations/src/http2/server.js +1 -3
- package/packages/datadog-instrumentations/src/jest.js +13 -4
- package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +14 -1
- package/packages/datadog-instrumentations/src/net.js +2 -8
- package/packages/datadog-instrumentations/src/pino.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +4 -1
- package/packages/datadog-instrumentations/src/prisma.js +1 -2
- package/packages/datadog-instrumentations/src/selenium.js +4 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/url.js +1 -3
- package/packages/datadog-instrumentations/src/vitest.js +5 -1
- package/packages/datadog-instrumentations/src/vm.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +4 -3
- package/packages/datadog-plugin-cucumber/src/index.js +7 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +57 -5
- package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +4 -2
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
- package/packages/datadog-plugin-mocha/src/index.js +5 -2
- package/packages/datadog-plugin-next/src/index.js +2 -14
- package/packages/datadog-plugin-openai/src/services.js +1 -0
- package/packages/datadog-webpack/index.js +3 -3
- package/packages/dd-trace/index.js +12 -10
- package/packages/dd-trace/src/agent/url.js +2 -2
- package/packages/dd-trace/src/aiguard/index.js +64 -0
- package/packages/dd-trace/src/aiguard/sdk.js +4 -0
- package/packages/dd-trace/src/appsec/blocking.js +3 -0
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config.js +1 -0
- package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
- package/packages/dd-trace/src/ci-visibility/lage.js +39 -0
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/config/defaults.js +316 -146
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -1
- package/packages/dd-trace/src/config/helper.js +59 -10
- package/packages/dd-trace/src/config/index.js +570 -1503
- package/packages/dd-trace/src/config/parsers.js +256 -0
- package/packages/dd-trace/src/config/remote_config.js +59 -2
- package/packages/dd-trace/src/config/supported-configurations.json +367 -433
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
- package/packages/dd-trace/src/crashtracking/index.js +1 -7
- package/packages/dd-trace/src/debugger/index.js +1 -1
- package/packages/dd-trace/src/dogstatsd.js +12 -9
- package/packages/dd-trace/src/encode/0.4.js +1 -1
- package/packages/dd-trace/src/exporter.js +5 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
- package/packages/dd-trace/src/exporters/common/request.js +9 -0
- package/packages/dd-trace/src/exporters/common/writer.js +12 -2
- package/packages/dd-trace/src/heap_snapshots.js +3 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
- package/packages/dd-trace/src/llmobs/constants/text.js +3 -0
- package/packages/dd-trace/src/llmobs/index.js +13 -5
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
- package/packages/dd-trace/src/llmobs/sdk.js +12 -8
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +9 -6
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
- package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
- package/packages/dd-trace/src/log/index.js +26 -55
- package/packages/dd-trace/src/log/writer.js +7 -19
- package/packages/dd-trace/src/noop/proxy.js +8 -0
- package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
- package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
- package/packages/dd-trace/src/plugin_manager.js +8 -6
- package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
- package/packages/dd-trace/src/plugins/plugin.js +7 -4
- package/packages/dd-trace/src/plugins/util/test.js +5 -0
- package/packages/dd-trace/src/process-tags/index.js +3 -0
- package/packages/dd-trace/src/profiler.js +27 -2
- package/packages/dd-trace/src/profiling/config.js +73 -241
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
- package/packages/dd-trace/src/profiling/profiler.js +56 -44
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
- package/packages/dd-trace/src/propagation-hash/index.js +2 -1
- package/packages/dd-trace/src/proxy.js +36 -3
- package/packages/dd-trace/src/remote_config/index.js +3 -0
- package/packages/dd-trace/src/require-package-json.js +8 -4
- package/packages/dd-trace/src/ritm.js +58 -26
- package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +3 -0
- package/packages/dd-trace/src/sampler.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -0
- package/packages/dd-trace/src/startup-log.js +9 -0
- package/packages/dd-trace/src/telemetry/index.js +2 -3
- package/packages/dd-trace/src/telemetry/send-data.js +5 -19
- package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
- package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
- package/packages/dd-trace/src/util.js +0 -9
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts a LanguageModelV2FilePart with an image mediaType to an AI guard style image_url content part.
|
|
5
|
+
*
|
|
6
|
+
* @param {{type: 'file', data: URL|string|Uint8Array, mediaType: string}} part
|
|
7
|
+
* @returns {{type: 'image_url', image_url: {url: string}}|undefined}
|
|
8
|
+
*/
|
|
9
|
+
function convertFilePartToImageUrl (part) {
|
|
10
|
+
const { data, mediaType } = part
|
|
11
|
+
|
|
12
|
+
if (data instanceof URL) {
|
|
13
|
+
return { type: 'image_url', image_url: { url: data.toString() } }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (typeof data === 'string') {
|
|
17
|
+
if (data.startsWith('http') || data.startsWith('data:')) {
|
|
18
|
+
return { type: 'image_url', image_url: { url: data } }
|
|
19
|
+
}
|
|
20
|
+
return { type: 'image_url', image_url: { url: `data:${mediaType};base64,${data}` } }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (data instanceof Uint8Array) {
|
|
24
|
+
return { type: 'image_url', image_url: { url: `data:${mediaType};base64,${Buffer.from(data).toString('base64')}` } }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Converts a LanguageModelV2Prompt to the AI guard style message format.
|
|
30
|
+
*
|
|
31
|
+
* Vercel AI v2 prompt entries use content arrays with typed parts (e.g. { type: 'text', text },
|
|
32
|
+
* { type: 'file', data, mediaType }). This function converts them to AI guard style messages.
|
|
33
|
+
* When file parts with image media types are present, the content is an array of text and
|
|
34
|
+
* image_url parts; otherwise it is a plain string.
|
|
35
|
+
*
|
|
36
|
+
* @param {Array<{role: string, content: string|Array<{type: string}>}>} prompt
|
|
37
|
+
* @returns {Array<{role: string, content?: string|Array<{type: string}>, tool_calls?: Array, tool_call_id?: string}>}
|
|
38
|
+
*/
|
|
39
|
+
function convertVercelPromptToMessages (prompt) {
|
|
40
|
+
if (!Array.isArray(prompt)) return []
|
|
41
|
+
|
|
42
|
+
const messages = []
|
|
43
|
+
for (const msg of prompt) {
|
|
44
|
+
switch (msg.role) {
|
|
45
|
+
case 'system':
|
|
46
|
+
messages.push({ role: 'system', content: typeof msg.content === 'string' ? msg.content : '' })
|
|
47
|
+
break
|
|
48
|
+
|
|
49
|
+
case 'user': {
|
|
50
|
+
if (!Array.isArray(msg.content)) break
|
|
51
|
+
|
|
52
|
+
const contentParts = []
|
|
53
|
+
for (const part of msg.content) {
|
|
54
|
+
if (part.type === 'text') {
|
|
55
|
+
contentParts.push({ type: 'text', text: part.text })
|
|
56
|
+
} else if (part.type === 'file' && part.mediaType?.startsWith('image/')) {
|
|
57
|
+
const converted = convertFilePartToImageUrl(part)
|
|
58
|
+
if (converted) contentParts.push(converted)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (contentParts.length === 0) break
|
|
63
|
+
|
|
64
|
+
const hasImages = contentParts.some(p => p.type === 'image_url')
|
|
65
|
+
if (hasImages) {
|
|
66
|
+
messages.push({ role: 'user', content: contentParts })
|
|
67
|
+
} else {
|
|
68
|
+
messages.push({ role: 'user', content: contentParts.map(p => p.text).join('\n') })
|
|
69
|
+
}
|
|
70
|
+
break
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
case 'assistant': {
|
|
74
|
+
const textParts = []
|
|
75
|
+
const toolCalls = []
|
|
76
|
+
if (!Array.isArray(msg.content)) break
|
|
77
|
+
|
|
78
|
+
for (const part of msg.content) {
|
|
79
|
+
if (part.type === 'text') {
|
|
80
|
+
textParts.push(part.text)
|
|
81
|
+
} else if (part.type === 'tool-call') {
|
|
82
|
+
const args = part.args ?? part.input
|
|
83
|
+
toolCalls.push({
|
|
84
|
+
id: part.toolCallId,
|
|
85
|
+
function: {
|
|
86
|
+
name: part.toolName,
|
|
87
|
+
arguments: typeof args === 'string' ? args : JSON.stringify(args),
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (toolCalls.length > 0) {
|
|
94
|
+
messages.push({ role: 'assistant', tool_calls: toolCalls })
|
|
95
|
+
} else if (textParts.length > 0) {
|
|
96
|
+
messages.push({ role: 'assistant', content: textParts.join('\n') })
|
|
97
|
+
}
|
|
98
|
+
break
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
case 'tool': {
|
|
102
|
+
if (!Array.isArray(msg.content)) break
|
|
103
|
+
|
|
104
|
+
for (const part of msg.content) {
|
|
105
|
+
if (part.type === 'tool-result') {
|
|
106
|
+
const result = part.result ?? part.output
|
|
107
|
+
messages.push({
|
|
108
|
+
role: 'tool',
|
|
109
|
+
tool_call_id: part.toolCallId,
|
|
110
|
+
content: typeof result === 'string' ? result : JSON.stringify(result),
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
break
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return messages
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Converts LLM output tool calls to AI guard style message format.
|
|
123
|
+
*
|
|
124
|
+
* @param {Array<object>} inputMessages - The input messages already in AI guard style format
|
|
125
|
+
* @param {Array<{toolCallId: string, toolName: string, args?: unknown, input?: unknown}>} toolCalls
|
|
126
|
+
* @returns {Array<object>}
|
|
127
|
+
*/
|
|
128
|
+
function buildToolCallOutputMessages (inputMessages, toolCalls) {
|
|
129
|
+
return [
|
|
130
|
+
...inputMessages,
|
|
131
|
+
{
|
|
132
|
+
role: 'assistant',
|
|
133
|
+
tool_calls: toolCalls.map(tc => {
|
|
134
|
+
const args = tc.args ?? tc.input
|
|
135
|
+
return {
|
|
136
|
+
id: tc.toolCallId,
|
|
137
|
+
function: {
|
|
138
|
+
name: tc.toolName,
|
|
139
|
+
arguments: typeof args === 'string' ? args : JSON.stringify(args),
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
}),
|
|
143
|
+
},
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Builds OpenAI-style output messages for the assistant's text response.
|
|
149
|
+
*
|
|
150
|
+
* @param {Array<object>} inputMessages - The input messages already in AI guard style format
|
|
151
|
+
* @param {string} text - The assistant's text response
|
|
152
|
+
* @returns {Array<object>}
|
|
153
|
+
*/
|
|
154
|
+
function buildTextOutputMessages (inputMessages, text) {
|
|
155
|
+
return [
|
|
156
|
+
...inputMessages,
|
|
157
|
+
{ role: 'assistant', content: text },
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Parses a Vercel AI content array and dispatches to the appropriate output message builder.
|
|
163
|
+
*
|
|
164
|
+
* @param {Array<object>} inputMessages - The input messages already in AI guard style format
|
|
165
|
+
* @param {Array<{type: string}>} content - Vercel AI content array from doGenerate/doStream result
|
|
166
|
+
* @returns {Array<object>}
|
|
167
|
+
*/
|
|
168
|
+
function buildOutputMessages (inputMessages, content) {
|
|
169
|
+
const toolCalls = content.filter(c => c.type === 'tool-call')
|
|
170
|
+
const text = content.filter(c => c.type === 'text').map(c => c.text).join('\n')
|
|
171
|
+
if (toolCalls.length) return buildToolCallOutputMessages(inputMessages, toolCalls)
|
|
172
|
+
if (text) return buildTextOutputMessages(inputMessages, text)
|
|
173
|
+
return inputMessages
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
convertVercelPromptToMessages,
|
|
178
|
+
convertFilePartToImageUrl,
|
|
179
|
+
buildToolCallOutputMessages,
|
|
180
|
+
buildTextOutputMessages,
|
|
181
|
+
buildOutputMessages,
|
|
182
|
+
}
|
|
@@ -45,45 +45,73 @@ if (!dc.unsubscribe) {
|
|
|
45
45
|
dc.unsubscribe = (channel, cb) => {
|
|
46
46
|
if (dc.channel(channel).hasSubscribers) {
|
|
47
47
|
dc.channel(channel).unsubscribe(cb)
|
|
48
|
+
return true
|
|
48
49
|
}
|
|
50
|
+
return false
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} name
|
|
56
|
+
*/
|
|
57
|
+
function doHook (name) {
|
|
58
|
+
const hook = hooks[name] ?? hooks[`node:${name}`]
|
|
54
59
|
if (!hook) {
|
|
55
|
-
log.error('esbuild-wrapped %s missing in list of hooks',
|
|
60
|
+
log.error('esbuild-wrapped %s missing in list of hooks', name)
|
|
56
61
|
return
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
const hookFn = hook.fn ?? hook
|
|
60
65
|
if (typeof hookFn !== 'function') {
|
|
61
|
-
log.error('esbuild-wrapped hook %s is not a function',
|
|
66
|
+
log.error('esbuild-wrapped hook %s is not a function', name)
|
|
62
67
|
return
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
try {
|
|
66
71
|
hookFn()
|
|
67
72
|
} catch {
|
|
68
|
-
log.error('esbuild-wrapped %s hook failed',
|
|
73
|
+
log.error('esbuild-wrapped %s hook failed', name)
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
/** @type {Set<string>} */
|
|
78
|
+
const instrumentedNodeModules = new Set()
|
|
74
79
|
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
/** @typedef {{ package: string, module: unknown, version: string, path: string }} Payload */
|
|
81
|
+
dc.subscribe(CHANNEL, (message) => {
|
|
82
|
+
const payload = /** @type {Payload} */ (message)
|
|
83
|
+
const name = payload.package
|
|
84
|
+
|
|
85
|
+
const isPrefixedWithNode = name.startsWith('node:')
|
|
86
|
+
|
|
87
|
+
const isNodeModule = isPrefixedWithNode || !hooks[name]
|
|
88
|
+
|
|
89
|
+
if (isNodeModule) {
|
|
90
|
+
const nodeName = isPrefixedWithNode ? name.slice(5) : name
|
|
91
|
+
// Used for node: prefixed modules to prevent double instrumentation.
|
|
92
|
+
if (instrumentedNodeModules.has(nodeName)) {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
instrumentedNodeModules.add(nodeName)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
doHook(name)
|
|
99
|
+
|
|
100
|
+
const instrumentation = instrumentations[name] ?? instrumentations[`node:${name}`]
|
|
101
|
+
|
|
102
|
+
if (!instrumentation) {
|
|
103
|
+
log.error('esbuild-wrapped %s missing in list of instrumentations', name)
|
|
77
104
|
return
|
|
78
105
|
}
|
|
79
106
|
|
|
80
|
-
for (const {
|
|
81
|
-
if (payload.path !== filename(name, file))
|
|
82
|
-
|
|
107
|
+
for (const { file, versions, hook } of instrumentation) {
|
|
108
|
+
if (payload.path !== filename(name, file) || !matchVersion(payload.version, versions)) {
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
83
111
|
|
|
84
112
|
try {
|
|
85
113
|
loadChannel.publish({ name, version: payload.version, file })
|
|
86
|
-
payload.module = hook(payload.module, payload.version)
|
|
114
|
+
payload.module = hook(payload.module, payload.version) ?? payload.module
|
|
87
115
|
} catch (e) {
|
|
88
116
|
log.error('Error executing bundler hook', e)
|
|
89
117
|
}
|
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
|
|
2
3
|
const path = require('path')
|
|
4
|
+
|
|
3
5
|
const iitm = require('../../../dd-trace/src/iitm')
|
|
4
6
|
const ritm = require('../../../dd-trace/src/ritm')
|
|
7
|
+
const log = require('../../../dd-trace/src/log')
|
|
8
|
+
const requirePackageJson = require('../../../dd-trace/src/require-package-json')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} moduleBaseDir
|
|
12
|
+
* @returns {string|undefined}
|
|
13
|
+
*/
|
|
14
|
+
function getVersion (moduleBaseDir) {
|
|
15
|
+
if (moduleBaseDir) {
|
|
16
|
+
return requirePackageJson(moduleBaseDir, /** @type {import('module').Module} */ (module)).version
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return process.version
|
|
20
|
+
}
|
|
5
21
|
|
|
6
22
|
/**
|
|
7
23
|
* This is called for every package/internal-module that dd-trace supports instrumentation for
|
|
8
24
|
* In practice, `modules` is always an array with a single entry.
|
|
9
25
|
*
|
|
26
|
+
* @overload
|
|
27
|
+
* @param {string[]} modules list of modules to hook into
|
|
28
|
+
* @param {object} hookOptions hook options
|
|
29
|
+
* @param {Function} onrequire callback to be executed upon encountering module
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* @overload
|
|
10
33
|
* @param {string[]} modules list of modules to hook into
|
|
11
34
|
* @param {object} hookOptions hook options
|
|
12
35
|
* @param {Function} onrequire callback to be executed upon encountering module
|
|
13
36
|
*/
|
|
14
37
|
function Hook (modules, hookOptions, onrequire) {
|
|
38
|
+
// TODO: Rewrite this to use class syntax. The same should be done for ritm.
|
|
15
39
|
if (!(this instanceof Hook)) return new Hook(modules, hookOptions, onrequire)
|
|
16
40
|
|
|
17
41
|
if (typeof hookOptions === 'function') {
|
|
@@ -42,6 +66,13 @@ function Hook (modules, hookOptions, onrequire) {
|
|
|
42
66
|
return result
|
|
43
67
|
}
|
|
44
68
|
|
|
69
|
+
try {
|
|
70
|
+
moduleVersion ||= getVersion(moduleBaseDir)
|
|
71
|
+
} catch (error) {
|
|
72
|
+
log.error('Error getting version for "%s": %s', moduleName, error.message, error)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
45
76
|
if (
|
|
46
77
|
isIitm &&
|
|
47
78
|
moduleExports.default &&
|
|
@@ -66,10 +97,4 @@ function Hook (modules, hookOptions, onrequire) {
|
|
|
66
97
|
})
|
|
67
98
|
}
|
|
68
99
|
|
|
69
|
-
Hook.prototype.unhook = function () {
|
|
70
|
-
this._ritmHook.unhook()
|
|
71
|
-
this._iitmHook.unhook()
|
|
72
|
-
this._patched = Object.create(null)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
100
|
module.exports = Hook
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
+
// Only list unprefixed node modules. They will automatically be instrumented as prefixed and unprefixed.
|
|
5
|
+
child_process: () => require('../child_process'),
|
|
6
|
+
crypto: () => require('../crypto'),
|
|
7
|
+
dns: () => require('../dns'),
|
|
8
|
+
fs: { serverless: false, fn: () => require('../fs') },
|
|
9
|
+
http: () => require('../http'),
|
|
10
|
+
http2: () => require('../http2'),
|
|
11
|
+
https: () => require('../http'),
|
|
12
|
+
net: () => require('../net'),
|
|
13
|
+
url: () => require('../url'),
|
|
14
|
+
vm: () => require('../vm'),
|
|
15
|
+
// Non Node.js modules
|
|
4
16
|
'@anthropic-ai/sdk': { esmFirst: true, fn: () => require('../anthropic') },
|
|
5
17
|
'@apollo/server': () => require('../apollo-server'),
|
|
6
18
|
'@apollo/gateway': () => require('../apollo'),
|
|
@@ -47,31 +59,24 @@ module.exports = {
|
|
|
47
59
|
bullmq: () => require('../bullmq'),
|
|
48
60
|
bunyan: () => require('../bunyan'),
|
|
49
61
|
'cassandra-driver': () => require('../cassandra-driver'),
|
|
50
|
-
child_process: () => require('../child_process'),
|
|
51
62
|
connect: () => require('../connect'),
|
|
52
63
|
cookie: () => require('../cookie'),
|
|
53
64
|
'cookie-parser': () => require('../cookie-parser'),
|
|
54
65
|
couchbase: () => require('../couchbase'),
|
|
55
|
-
crypto: () => require('../crypto'),
|
|
56
66
|
cypress: () => require('../cypress'),
|
|
57
67
|
'dd-trace-api': () => require('../dd-trace-api'),
|
|
58
|
-
dns: () => require('../dns'),
|
|
59
68
|
elasticsearch: () => require('../elasticsearch'),
|
|
60
69
|
express: () => require('../express'),
|
|
61
70
|
'express-mongo-sanitize': () => require('../express-mongo-sanitize'),
|
|
62
71
|
'express-session': () => require('../express-session'),
|
|
63
72
|
fastify: () => require('../fastify'),
|
|
64
73
|
'find-my-way': () => require('../find-my-way'),
|
|
65
|
-
fs: { serverless: false, fn: () => require('../fs') },
|
|
66
74
|
'generic-pool': () => require('../generic-pool'),
|
|
67
75
|
graphql: () => require('../graphql'),
|
|
68
76
|
grpc: () => require('../grpc'),
|
|
69
77
|
handlebars: () => require('../handlebars'),
|
|
70
78
|
hapi: () => require('../hapi'),
|
|
71
79
|
hono: { esmFirst: true, fn: () => require('../hono') },
|
|
72
|
-
http: () => require('../http'),
|
|
73
|
-
http2: () => require('../http2'),
|
|
74
|
-
https: () => require('../http'),
|
|
75
80
|
ioredis: () => require('../ioredis'),
|
|
76
81
|
iovalkey: () => require('../iovalkey'),
|
|
77
82
|
'jest-circus': () => require('../jest'),
|
|
@@ -103,18 +108,8 @@ module.exports = {
|
|
|
103
108
|
multer: () => require('../multer'),
|
|
104
109
|
mysql: () => require('../mysql'),
|
|
105
110
|
mysql2: () => require('../mysql2'),
|
|
106
|
-
net: () => require('../net'),
|
|
107
111
|
next: () => require('../next'),
|
|
108
112
|
'node-serialize': () => require('../node-serialize'),
|
|
109
|
-
'node:child_process': () => require('../child_process'),
|
|
110
|
-
'node:crypto': () => require('../crypto'),
|
|
111
|
-
'node:dns': () => require('../dns'),
|
|
112
|
-
'node:http': () => require('../http'),
|
|
113
|
-
'node:http2': () => require('../http2'),
|
|
114
|
-
'node:https': () => require('../http'),
|
|
115
|
-
'node:net': () => require('../net'),
|
|
116
|
-
'node:url': () => require('../url'),
|
|
117
|
-
'node:vm': () => require('../vm'),
|
|
118
113
|
nyc: () => require('../nyc'),
|
|
119
114
|
oracledb: () => require('../oracledb'),
|
|
120
115
|
openai: { esmFirst: true, fn: () => require('../openai') },
|
|
@@ -142,9 +137,7 @@ module.exports = {
|
|
|
142
137
|
tedious: () => require('../tedious'),
|
|
143
138
|
tinypool: { esmFirst: true, fn: () => require('../vitest') },
|
|
144
139
|
undici: () => require('../undici'),
|
|
145
|
-
url: () => require('../url'),
|
|
146
140
|
vitest: { esmFirst: true, fn: () => require('../vitest') },
|
|
147
|
-
vm: () => require('../vm'),
|
|
148
141
|
when: () => require('../when'),
|
|
149
142
|
winston: () => require('../winston'),
|
|
150
143
|
workerpool: () => require('../mocha'),
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { AsyncResource } = require('async_hooks')
|
|
4
|
-
const dc = require('dc-polyfill')
|
|
4
|
+
const dc = /** @type {typeof import('node:diagnostics_channel')} */ (require('dc-polyfill'))
|
|
5
5
|
const instrumentations = require('./instrumentations')
|
|
6
6
|
const rewriterInstrumentations = require('./rewriter/instrumentations')
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import('node:diagnostics_channel').Channel} Channel
|
|
10
|
+
* @typedef {import('node:diagnostics_channel').TracingChannel} TracingChannel
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @type {Record<string, Channel>}
|
|
15
|
+
*/
|
|
8
16
|
const channelMap = {}
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} name
|
|
19
|
+
* @returns {Channel}
|
|
20
|
+
*/
|
|
9
21
|
exports.channel = function (name) {
|
|
10
22
|
const maybe = channelMap[name]
|
|
11
23
|
if (maybe) return maybe
|
|
@@ -14,7 +26,14 @@ exports.channel = function (name) {
|
|
|
14
26
|
return ch
|
|
15
27
|
}
|
|
16
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @type {Record<string, TracingChannel>}
|
|
31
|
+
*/
|
|
17
32
|
const tracingChannelMap = {}
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} name
|
|
35
|
+
* @returns {TracingChannel}
|
|
36
|
+
*/
|
|
18
37
|
exports.tracingChannel = function (name) {
|
|
19
38
|
const maybe = tracingChannelMap[name]
|
|
20
39
|
if (maybe) return maybe
|
|
@@ -34,24 +53,19 @@ exports.getHooks = function getHooks (names) {
|
|
|
34
53
|
|
|
35
54
|
/**
|
|
36
55
|
* @param {object} args
|
|
37
|
-
* @param {string
|
|
38
|
-
* @param {string[]} args.versions array of semver range strings
|
|
56
|
+
* @param {string} args.name module name
|
|
57
|
+
* @param {string[]} [args.versions] array of semver range strings
|
|
39
58
|
* @param {string} [args.file='index.js'] path to file within package to instrument
|
|
40
59
|
* @param {string} [args.filePattern] pattern to match files within package to instrument
|
|
41
|
-
* @param {boolean} [args.patchDefault] whether to patch the default export
|
|
42
|
-
* @param {(moduleExports: unknown, version: string) => unknown} hook
|
|
60
|
+
* @param {boolean} [args.patchDefault=true] whether to patch the default export
|
|
61
|
+
* @param {(moduleExports: unknown, version: string, isIitm?: boolean) => unknown} [hook] Patches module exports
|
|
43
62
|
*/
|
|
44
63
|
exports.addHook = function addHook ({ name, versions, file, filePattern, patchDefault }, hook) {
|
|
45
|
-
if (
|
|
46
|
-
name = [
|
|
64
|
+
if (!instrumentations[name]) {
|
|
65
|
+
instrumentations[name] = []
|
|
47
66
|
}
|
|
48
67
|
|
|
49
|
-
|
|
50
|
-
if (!instrumentations[val]) {
|
|
51
|
-
instrumentations[val] = []
|
|
52
|
-
}
|
|
53
|
-
instrumentations[val].push({ name: val, versions, file, filePattern, hook, patchDefault })
|
|
54
|
-
}
|
|
68
|
+
instrumentations[name].push({ versions, file, filePattern, hook, patchDefault })
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
exports.AsyncResource = AsyncResource
|