dd-trace 6.14.0 → 6.16.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/README.md +15 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +4 -2
- package/ci/test-optimization-validation/package-check.js +4 -1
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +1 -1
- package/index.d.ts +12 -0
- package/next.d.ts +27 -0
- package/next.js +3 -0
- package/package.json +17 -13
- package/packages/datadog-esbuild/index.js +14 -1
- package/packages/datadog-esbuild/src/resolver.js +284 -0
- package/packages/datadog-esbuild/src/utils.js +163 -119
- package/packages/datadog-instrumentations/src/ai.js +39 -97
- package/packages/datadog-instrumentations/src/anthropic.js +76 -134
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +1 -1
- package/packages/datadog-instrumentations/src/azure-cosmos.js +1 -1
- package/packages/datadog-instrumentations/src/azure-durable-functions.js +23 -9
- package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
- package/packages/datadog-instrumentations/src/bullmq.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/dd-trace-api.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +39 -14
- package/packages/datadog-instrumentations/src/helpers/instrument.js +25 -8
- package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +72 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -64
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +46 -14
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-durable-functions.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +1 -5
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +6 -7
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +99 -70
- package/packages/datadog-instrumentations/src/jest.js +141 -25
- package/packages/datadog-instrumentations/src/langchain.js +1 -1
- package/packages/datadog-instrumentations/src/langgraph.js +1 -1
- package/packages/datadog-instrumentations/src/mercurius.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +41 -5
- package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/openai-agents.js +1 -1
- package/packages/datadog-instrumentations/src/openai.js +54 -76
- package/packages/datadog-instrumentations/src/playwright.js +4 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +7 -10
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +7 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +1 -1
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +96 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -24
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -36
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-request-context.js +31 -0
- package/packages/datadog-plugin-graphql/src/resolve-error.js +33 -11
- package/packages/datadog-turbopack/index.js +212 -0
- package/packages/datadog-turbopack/src/constants.js +5 -0
- package/packages/datadog-turbopack/src/loader.js +500 -0
- package/packages/dd-trace/src/aiguard/index.js +2 -1
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +53 -25
- package/packages/dd-trace/src/aiguard/integrations/evaluate.js +49 -25
- package/packages/dd-trace/src/aiguard/integrations/index.js +3 -2
- package/packages/dd-trace/src/aiguard/integrations/openai.js +59 -30
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +116 -42
- package/packages/dd-trace/src/aiguard/messages/utils.js +29 -1
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +25 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +3 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +531 -70
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/common.js +4 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +23 -5
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +1 -20
- package/packages/dd-trace/src/appsec/telemetry/user.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/waf.js +1 -20
- package/packages/dd-trace/src/ci-visibility/requests/request.js +11 -0
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +4 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
- package/packages/dd-trace/src/config/helper.js +10 -2
- package/packages/dd-trace/src/config/index.js +20 -5
- package/packages/dd-trace/src/config/supported-configurations.json +10 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -7
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/request-options.js +1 -6
- package/packages/dd-trace/src/evp_proxy/direct.js +2 -28
- package/packages/dd-trace/src/evp_proxy/discovery.js +3 -4
- package/packages/dd-trace/src/evp_proxy/path.js +12 -3
- package/packages/dd-trace/src/exporters/agentless/writer.js +3 -1
- package/packages/dd-trace/src/exporters/common/docker.js +4 -1
- package/packages/dd-trace/src/exporters/common/proxy.js +55 -0
- package/packages/dd-trace/src/exporters/common/request.js +11 -3
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +5 -4
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +106 -25
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +12 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +8 -2
- package/packages/dd-trace/src/plugin_manager.js +9 -3
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/test.js +4 -1
- package/packages/dd-trace/src/priority_sampler.js +4 -0
- package/packages/dd-trace/src/sampling_rule.js +3 -1
- package/packages/dd-trace/src/span_processor.js +18 -3
- package/packages/dd-trace/src/telemetry/send-data.js +5 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +0 -10
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { builtinModules } = require('node:module')
|
|
4
|
+
|
|
5
|
+
const satisfies = require('../../../../vendor/dist/semifies')
|
|
6
|
+
const { getValueFromEnvSources } = require('../../../dd-trace/src/config/helper')
|
|
7
|
+
const { isRelativeRequire } = require('./shared-utils')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {string|undefined} version
|
|
11
|
+
* @param {string[]|undefined} ranges
|
|
12
|
+
* @returns {boolean}
|
|
13
|
+
*/
|
|
14
|
+
function matchVersion (version, ranges) {
|
|
15
|
+
return !version || !ranges || ranges.some(range => satisfies(version, range))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} name
|
|
20
|
+
* @param {string} [file]
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
function filename (name, file) {
|
|
24
|
+
return file ? `${name}/${file}` : name
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} name
|
|
29
|
+
* @param {string|undefined} version
|
|
30
|
+
* @param {string} moduleName
|
|
31
|
+
* @param {{ file?: string, filePattern?: string, versions?: string[] }} instrumentation
|
|
32
|
+
* @returns {boolean}
|
|
33
|
+
*/
|
|
34
|
+
function matchesInstrumentation (name, version, moduleName, instrumentation) {
|
|
35
|
+
const { file, filePattern, versions } = instrumentation
|
|
36
|
+
let matchesFile = moduleName === filename(name, file)
|
|
37
|
+
if (!matchesFile && isRelativeRequire(name)) matchesFile = true
|
|
38
|
+
if (!matchesFile && filePattern) {
|
|
39
|
+
matchesFile = new RegExp(filename(name, filePattern)).test(moduleName)
|
|
40
|
+
}
|
|
41
|
+
return matchesFile && matchVersion(version, versions)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @returns {Set<string>}
|
|
46
|
+
*/
|
|
47
|
+
function getDisabledInstrumentations () {
|
|
48
|
+
const disabled = new Set(
|
|
49
|
+
getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS')?.split(',').filter(Boolean)
|
|
50
|
+
)
|
|
51
|
+
if (disabled.size === 0) return disabled
|
|
52
|
+
|
|
53
|
+
const expanded = new Set(disabled)
|
|
54
|
+
const builtins = new Set(builtinModules)
|
|
55
|
+
|
|
56
|
+
for (const name of disabled) {
|
|
57
|
+
const prefixed = name.startsWith('node:')
|
|
58
|
+
if (!prefixed && !builtins.has(name)) continue
|
|
59
|
+
|
|
60
|
+
const counterpart = prefixed ? name.slice(5) : `node:${name}`
|
|
61
|
+
expanded.add(counterpart)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return expanded
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
filename,
|
|
69
|
+
getDisabledInstrumentations,
|
|
70
|
+
matchesInstrumentation,
|
|
71
|
+
matchVersion,
|
|
72
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { builtinModules } = require('module')
|
|
4
3
|
const path = require('path')
|
|
5
4
|
const { channel } = require('dc-polyfill')
|
|
6
|
-
const satisfies = require('../../../../vendor/dist/semifies')
|
|
7
5
|
const log = require('../../../dd-trace/src/log')
|
|
8
6
|
const telemetry = require('../../../dd-trace/src/guardrails/telemetry')
|
|
9
7
|
const { IS_SERVERLESS } = require('../../../dd-trace/src/serverless')
|
|
10
8
|
const { getValueFromEnvSources } = require('../../../dd-trace/src/config/helper')
|
|
11
9
|
const checkRequireCache = require('./check-require-cache')
|
|
12
10
|
const Hook = require('./hook')
|
|
13
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
filename,
|
|
13
|
+
getDisabledInstrumentations,
|
|
14
|
+
matchesInstrumentation,
|
|
15
|
+
} = require('./instrumentation-utils')
|
|
14
16
|
const rewriter = require('./rewriter')
|
|
15
17
|
|
|
16
|
-
const DD_TRACE_DISABLED_INSTRUMENTATIONS =
|
|
17
|
-
getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS')
|
|
18
18
|
const DD_TRACE_DEBUG = getValueFromEnvSources('DD_TRACE_DEBUG')
|
|
19
19
|
|
|
20
20
|
const hooks = require('./hooks')
|
|
@@ -22,9 +22,7 @@ const instrumentations = require('./instrumentations')
|
|
|
22
22
|
const names = Object.keys(hooks)
|
|
23
23
|
const pathSepExpr = new RegExp(`\\${path.sep}`, 'g')
|
|
24
24
|
|
|
25
|
-
const disabledInstrumentations =
|
|
26
|
-
DD_TRACE_DISABLED_INSTRUMENTATIONS?.split(',')
|
|
27
|
-
)
|
|
25
|
+
const disabledInstrumentations = getDisabledInstrumentations()
|
|
28
26
|
|
|
29
27
|
const loadChannel = channel('dd-trace:instrumentation:load')
|
|
30
28
|
|
|
@@ -54,29 +52,6 @@ const instrumentedIntegrationsSuccess = new Map()
|
|
|
54
52
|
/** @type {Set<string>} */
|
|
55
53
|
const alreadyLoggedIncompatibleIntegrations = new Set()
|
|
56
54
|
|
|
57
|
-
// Always disable prefixed and unprefixed node modules if one is disabled.
|
|
58
|
-
if (disabledInstrumentations.size) {
|
|
59
|
-
const builtinsSet = new Set(builtinModules)
|
|
60
|
-
const disabledBuiltinCounterparts = []
|
|
61
|
-
for (const name of disabledInstrumentations) {
|
|
62
|
-
const hasPrefix = name.startsWith('node:')
|
|
63
|
-
if (hasPrefix || builtinsSet.has(name)) {
|
|
64
|
-
if (hasPrefix) {
|
|
65
|
-
const unprefixedName = name.slice(5)
|
|
66
|
-
if (!disabledInstrumentations.has(unprefixedName)) {
|
|
67
|
-
disabledBuiltinCounterparts.push(unprefixedName)
|
|
68
|
-
}
|
|
69
|
-
} else if (!disabledInstrumentations.has(`node:${name}`)) {
|
|
70
|
-
disabledBuiltinCounterparts.push(`node:${name}`)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
for (const name of disabledBuiltinCounterparts) {
|
|
75
|
-
disabledInstrumentations.add(name)
|
|
76
|
-
}
|
|
77
|
-
builtinsSet.clear()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
55
|
for (const name of names) {
|
|
81
56
|
if (disabledInstrumentations.has(name)) continue
|
|
82
57
|
|
|
@@ -111,21 +86,9 @@ for (const name of names) {
|
|
|
111
86
|
instrumentedNodeModules.set(name, moduleExports)
|
|
112
87
|
}
|
|
113
88
|
|
|
114
|
-
for (const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
let matchesFile = moduleName === fullFilename
|
|
118
|
-
|
|
119
|
-
if (!matchesFile && isRelativeRequire(name)) matchesFile = true
|
|
120
|
-
|
|
121
|
-
const fullFilePattern = filePattern && filename(name, filePattern)
|
|
122
|
-
if (fullFilePattern) {
|
|
123
|
-
// Some libraries include a hash in their filenames when installed,
|
|
124
|
-
// so our instrumentation has to include a '.*' to match them for more than a single version.
|
|
125
|
-
matchesFile ||= new RegExp(fullFilePattern).test(moduleName)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (matchesFile && matchVersion(moduleVersion, versions)) {
|
|
89
|
+
for (const instrumentation of instrumentations[name]) {
|
|
90
|
+
if (matchesInstrumentation(name, moduleVersion, moduleName, instrumentation)) {
|
|
91
|
+
const { hook, patchDefault } = instrumentation
|
|
129
92
|
// IITM invokes this callback for every module in the package. Only unwrap the namespace after its file and
|
|
130
93
|
// version match, otherwise a default export from an unrelated internal module can replace that module.
|
|
131
94
|
if (isIitm && patchDefault === !!moduleExports.default) {
|
|
@@ -188,26 +151,8 @@ function logAbortedIntegrations () {
|
|
|
188
151
|
instrumentedIntegrationsSuccess.clear()
|
|
189
152
|
}
|
|
190
153
|
|
|
191
|
-
/**
|
|
192
|
-
* @param {string|undefined} version
|
|
193
|
-
* @param {string[]|undefined} ranges
|
|
194
|
-
*/
|
|
195
|
-
function matchVersion (version, ranges) {
|
|
196
|
-
return !version || !ranges || ranges.some(range => satisfies(version, range))
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @param {string} name
|
|
201
|
-
* @param {string} [file]
|
|
202
|
-
* @returns {string}
|
|
203
|
-
*/
|
|
204
|
-
function filename (name, file) {
|
|
205
|
-
return file ? `${name}/${file}` : name
|
|
206
|
-
}
|
|
207
|
-
|
|
208
154
|
module.exports = {
|
|
209
155
|
filename,
|
|
210
156
|
pathSepExpr,
|
|
211
157
|
loadChannel,
|
|
212
|
-
matchVersion,
|
|
213
158
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { readFileSync } = require('fs')
|
|
4
|
-
const { join } = require('path')
|
|
5
|
-
const { pathToFileURL } = require('url')
|
|
3
|
+
const { readFileSync } = require('node:fs')
|
|
4
|
+
const { join } = require('node:path')
|
|
5
|
+
const { pathToFileURL } = require('node:url')
|
|
6
|
+
|
|
6
7
|
const log = require('../../../../dd-trace/src/log')
|
|
7
8
|
const instrumentations = require('./instrumentations')
|
|
8
9
|
const { getRewriteTarget } = require('./targets')
|
|
@@ -13,7 +14,12 @@ const { getRewriteTarget } = require('./targets')
|
|
|
13
14
|
* @property {(moduleName: string, version: string|undefined, filePath: string) => Transformer|undefined} getTransformer
|
|
14
15
|
*
|
|
15
16
|
* @typedef {object} Transformer
|
|
16
|
-
* @property {(source: string, moduleType: 'cjs'|'esm'
|
|
17
|
+
* @property {(source: string, moduleType: 'cjs'|'esm', sourceMap?: string|object) =>
|
|
18
|
+
* { code: string, map?: string|object }} transform
|
|
19
|
+
*
|
|
20
|
+
* @typedef {(content: string|Buffer|ArrayBuffer|Uint8Array, filename: string, format?: string,
|
|
21
|
+
* target?: { moduleName: string, filePath: string }, sourceMap?: string|object) =>
|
|
22
|
+
* { code: string|Buffer|ArrayBuffer|Uint8Array, map?: string|object }} BundlerRewriter
|
|
17
23
|
*/
|
|
18
24
|
|
|
19
25
|
/**
|
|
@@ -79,46 +85,71 @@ function rewrite (content, filename, format, target) {
|
|
|
79
85
|
return content
|
|
80
86
|
}
|
|
81
87
|
|
|
88
|
+
/**
|
|
89
|
+
* @param {string} dcModule
|
|
90
|
+
* @returns {BundlerRewriter}
|
|
91
|
+
*/
|
|
92
|
+
function createBundlerRewriter (dcModule) {
|
|
93
|
+
const matcher = createMatcher(dcModule)
|
|
94
|
+
|
|
95
|
+
return function rewriteBundled (content, filename, format, target, sourceMap) {
|
|
96
|
+
if (!content) return { code: content, map: sourceMap }
|
|
97
|
+
|
|
98
|
+
target ||= getRewriteTarget(filename)
|
|
99
|
+
if (!target) return { code: content, map: sourceMap }
|
|
100
|
+
|
|
101
|
+
filename = filename.replace('file://', '')
|
|
102
|
+
const moduleType = format === 'module' ? 'esm' : 'cjs'
|
|
103
|
+
const { moduleName, filePath } = target
|
|
104
|
+
const transformer = matcher.getTransformer(moduleName, getVersion(filename, filePath), filePath)
|
|
105
|
+
if (!transformer) return { code: content, map: sourceMap }
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
return transformer.transform(getSourceText(content), moduleType, sourceMap)
|
|
109
|
+
} catch (error) {
|
|
110
|
+
log.error(error)
|
|
111
|
+
return { code: content, map: sourceMap }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
82
116
|
/**
|
|
83
117
|
* @param {'cjs'|'esm'} moduleType
|
|
84
118
|
* @returns {InstrumentationMatcher}
|
|
85
119
|
*/
|
|
86
120
|
function getMatcher (moduleType) {
|
|
87
121
|
if (moduleType === 'esm') {
|
|
88
|
-
matcherEsm ??= createMatcher(moduleType)
|
|
122
|
+
matcherEsm ??= createMatcher(getDcPolyfillSpecifier(moduleType))
|
|
89
123
|
|
|
90
124
|
return matcherEsm
|
|
91
125
|
}
|
|
92
126
|
|
|
93
|
-
matcherCjs ??= createMatcher(moduleType)
|
|
127
|
+
matcherCjs ??= createMatcher(getDcPolyfillSpecifier(moduleType))
|
|
94
128
|
|
|
95
129
|
return matcherCjs
|
|
96
130
|
}
|
|
97
131
|
|
|
98
132
|
/**
|
|
99
|
-
* @param {
|
|
133
|
+
* @param {string|undefined} dcModule
|
|
100
134
|
* @returns {InstrumentationMatcher}
|
|
101
135
|
*/
|
|
102
|
-
function createMatcher (
|
|
136
|
+
function createMatcher (dcModule) {
|
|
103
137
|
const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
|
|
104
138
|
const {
|
|
105
139
|
awaitContextCallback,
|
|
106
|
-
awaitContextCallbackAtFunctionStart,
|
|
107
|
-
awaitContextCallbackAtTryStart,
|
|
108
140
|
configureGraphqlFastPath,
|
|
109
141
|
configureGraphqlJitCompileObject,
|
|
110
142
|
configureGraphqlJitDeferredField,
|
|
111
143
|
configureGraphqlJitExecute,
|
|
112
144
|
configureGraphqlJitRuntime,
|
|
113
145
|
configureMercuriusRequest,
|
|
146
|
+
publishDurableOrchestrationFailure,
|
|
114
147
|
waitForAsyncEnd,
|
|
115
148
|
} = require('./transforms')
|
|
116
149
|
|
|
117
|
-
const matcher = create(instrumentations,
|
|
150
|
+
const matcher = create(instrumentations, dcModule)
|
|
118
151
|
|
|
119
152
|
matcher.addTransform('awaitContextCallback', awaitContextCallback)
|
|
120
|
-
matcher.addTransform('awaitContextCallbackAtFunctionStart', awaitContextCallbackAtFunctionStart)
|
|
121
|
-
matcher.addTransform('awaitContextCallbackAtTryStart', awaitContextCallbackAtTryStart)
|
|
122
153
|
matcher.addTransform('waitForAsyncEnd', waitForAsyncEnd)
|
|
123
154
|
matcher.addTransform('configureGraphqlFastPath', configureGraphqlFastPath)
|
|
124
155
|
matcher.addTransform('configureGraphqlJitCompileObject', configureGraphqlJitCompileObject)
|
|
@@ -126,6 +157,7 @@ function createMatcher (moduleType) {
|
|
|
126
157
|
matcher.addTransform('configureGraphqlJitExecute', configureGraphqlJitExecute)
|
|
127
158
|
matcher.addTransform('configureGraphqlJitRuntime', configureGraphqlJitRuntime)
|
|
128
159
|
matcher.addTransform('configureMercuriusRequest', configureMercuriusRequest)
|
|
160
|
+
matcher.addTransform('publishDurableOrchestrationFailure', publishDurableOrchestrationFailure)
|
|
129
161
|
|
|
130
162
|
return matcher
|
|
131
163
|
}
|
|
@@ -189,4 +221,4 @@ function getVersion (filename, filePath) {
|
|
|
189
221
|
return moduleVersions[basename]
|
|
190
222
|
}
|
|
191
223
|
|
|
192
|
-
module.exports = {
|
|
224
|
+
module.exports = { createBundlerRewriter, disable, rewrite }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
{
|
|
5
|
+
module: {
|
|
6
|
+
name: 'durable-functions',
|
|
7
|
+
versionRange: '>=3 <4',
|
|
8
|
+
filePath: 'lib/src/orchestrations/TaskOrchestrationExecutor.js',
|
|
9
|
+
},
|
|
10
|
+
functionQuery: {
|
|
11
|
+
className: 'TaskOrchestrationExecutor',
|
|
12
|
+
methodName: 'execute',
|
|
13
|
+
},
|
|
14
|
+
transform: 'publishDurableOrchestrationFailure',
|
|
15
|
+
channelName: 'TaskOrchestrationExecutor_failure',
|
|
16
|
+
},
|
|
17
|
+
]
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js
CHANGED
|
@@ -99,11 +99,7 @@ module.exports = [
|
|
|
99
99
|
versionRange: '>=1.60.0',
|
|
100
100
|
filePath: 'lib/coreBundle.js',
|
|
101
101
|
},
|
|
102
|
-
astQuery: '
|
|
103
|
-
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
|
|
104
|
-
'VariableDeclarator[id.name="Page2"] > ClassExpression > ClassBody > ' +
|
|
105
|
-
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async], ' +
|
|
106
|
-
'ClassDeclaration[id.name="Page2"] > ClassBody > ' +
|
|
102
|
+
astQuery: 'ClassExpression[id.name="_Page"] > ClassBody > ' +
|
|
107
103
|
'MethodDefinition[kind="method"][key.name="goto"] > FunctionExpression[async]',
|
|
108
104
|
functionQuery: {
|
|
109
105
|
methodName: 'goto',
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js
CHANGED
|
@@ -428,9 +428,9 @@ module.exports = [
|
|
|
428
428
|
versionRange: '>=9.0.0',
|
|
429
429
|
filePath: 'build/index.js',
|
|
430
430
|
},
|
|
431
|
-
astQuery: 'VariableDeclarator[id.name="testFrameworkFnWrapper"] > FunctionExpression
|
|
431
|
+
astQuery: 'VariableDeclarator[id.name="testFrameworkFnWrapper"] > FunctionExpression',
|
|
432
432
|
channelName: 'testFrameworkFnWrapper',
|
|
433
|
-
transform: '
|
|
433
|
+
transform: 'awaitContextCallback',
|
|
434
434
|
transformOptions: {
|
|
435
435
|
callbackName: 'rumCleanupCallback',
|
|
436
436
|
},
|
|
@@ -453,12 +453,11 @@ module.exports = [
|
|
|
453
453
|
versionRange: '>=9.0.0',
|
|
454
454
|
filePath: 'build/index.js',
|
|
455
455
|
},
|
|
456
|
-
astQuery: '
|
|
457
|
-
'
|
|
458
|
-
'[test.
|
|
459
|
-
'[test.right.property.name="attempts"]',
|
|
456
|
+
astQuery: 'TryStatement:has(CatchClause IfStatement[test.operator=">"]' +
|
|
457
|
+
'[test.left.object.name="retries"][test.left.property.name="limit"]' +
|
|
458
|
+
'[test.right.object.name="retries"][test.right.property.name="attempts"]) > BlockStatement',
|
|
460
459
|
channelName: 'executeAsync',
|
|
461
|
-
transform: '
|
|
460
|
+
transform: 'awaitContextCallback',
|
|
462
461
|
transformOptions: {
|
|
463
462
|
callbackName: 'rumStartCallback',
|
|
464
463
|
},
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"bullmq/dist/esm/classes/flow-producer.js": "bullmq",
|
|
44
44
|
"bullmq/dist/esm/classes/queue.js": "bullmq",
|
|
45
45
|
"bullmq/dist/esm/classes/worker.js": "bullmq",
|
|
46
|
+
"durable-functions/lib/src/orchestrations/TaskOrchestrationExecutor.js": "durable-functions",
|
|
46
47
|
"graphql-jit/dist/cjs/execution.js": "graphql-jit",
|
|
47
48
|
"graphql-jit/dist/esm/execution.js": "graphql-jit",
|
|
48
49
|
"graphql-jit/dist/execution.js": "graphql-jit",
|
|
@@ -20,67 +20,77 @@ const identifierPattern = /^[$A-Z_a-z][$\w]*$/
|
|
|
20
20
|
|
|
21
21
|
module.exports = {
|
|
22
22
|
awaitContextCallback,
|
|
23
|
-
awaitContextCallbackAtFunctionStart,
|
|
24
|
-
awaitContextCallbackAtTryStart,
|
|
25
23
|
configureGraphqlJitCompileObject,
|
|
26
24
|
configureGraphqlJitDeferredField,
|
|
27
25
|
configureGraphqlJitExecute,
|
|
28
26
|
configureGraphqlJitRuntime,
|
|
29
27
|
configureGraphqlFastPath,
|
|
30
28
|
configureMercuriusRequest,
|
|
29
|
+
publishDurableOrchestrationFailure,
|
|
31
30
|
waitForAsyncEnd,
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
|
-
*
|
|
34
|
+
* Publishes the error captured by Durable Functions immediately before its
|
|
35
|
+
* executor converts that error into a serialized failed orchestration state.
|
|
36
36
|
*
|
|
37
|
-
* @param {
|
|
38
|
-
*
|
|
37
|
+
* @param {{
|
|
38
|
+
* channelName: string,
|
|
39
|
+
* transforms: { tracingChannelDeclaration: Function }
|
|
40
|
+
* }} state
|
|
41
|
+
* @param {import('estree').FunctionExpression} node
|
|
39
42
|
* @param {import('estree').Node} _parent
|
|
40
43
|
* @param {import('estree').Node[]} ancestry
|
|
41
44
|
* @returns {void}
|
|
42
45
|
*/
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (wrappedFunction) {
|
|
58
|
-
enclosingFunction = wrappedFunction
|
|
59
|
-
callbackAncestry.unshift(wrappedFunction)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
assert(enclosingFunction?.async && enclosingFunction.body?.type === 'BlockStatement',
|
|
64
|
-
'awaitContextCallbackAtFunctionStart: expected an enclosing async function with a block body')
|
|
46
|
+
function publishDurableOrchestrationFailure (state, node, _parent, ancestry) {
|
|
47
|
+
// Class queries also visit the owning ClassDeclaration so Orchestrion can
|
|
48
|
+
// synthesize missing methods. This transform targets the concrete method only.
|
|
49
|
+
if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') return
|
|
50
|
+
|
|
51
|
+
const failureBranches = query(node, 'IfStatement').filter(({ test }) =>
|
|
52
|
+
test.type === 'BinaryExpression' &&
|
|
53
|
+
test.operator === '!==' &&
|
|
54
|
+
test.left?.type === 'MemberExpression' &&
|
|
55
|
+
test.left.object?.type === 'ThisExpression' &&
|
|
56
|
+
test.left.property?.name === 'exception' &&
|
|
57
|
+
test.right?.type === 'Identifier' &&
|
|
58
|
+
test.right.name === 'undefined'
|
|
59
|
+
)
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
'awaitContextCallbackAtFunctionStart'
|
|
61
|
+
assert.strictEqual(
|
|
62
|
+
failureBranches.length,
|
|
63
|
+
1,
|
|
64
|
+
'publishDurableOrchestrationFailure: executor failure branch not found'
|
|
71
65
|
)
|
|
72
|
-
|
|
66
|
+
assert.strictEqual(
|
|
67
|
+
failureBranches[0].consequent.type,
|
|
68
|
+
'BlockStatement',
|
|
69
|
+
'publishDurableOrchestrationFailure: expected a block failure branch'
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
const program = ancestry.at(-1)
|
|
73
|
+
state.transforms.tracingChannelDeclaration(state, program)
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
const channelVariable = `tr_ch_apm$${state.channelName.replaceAll(/[^\w]/g, '_')}`
|
|
76
|
+
const publishStatements = parse(`
|
|
77
|
+
if (${channelVariable}.end.hasSubscribers) {
|
|
78
|
+
${channelVariable}.end.publish({
|
|
79
|
+
arguments: [context, history],
|
|
80
|
+
error: this.exception
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
`).body
|
|
84
|
+
|
|
85
|
+
failureBranches[0].consequent.body.unshift(...publishStatements)
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
/**
|
|
80
|
-
* Awaits an optional context callback
|
|
89
|
+
* Awaits an optional context callback at the start of a matched function or block, or before continuing through a
|
|
90
|
+
* matched conditional branch.
|
|
81
91
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
92
|
+
* A matched conditional branch is checked again after the callback settles so its original body does not run
|
|
93
|
+
* against state that changed while awaiting.
|
|
84
94
|
*
|
|
85
95
|
* @param {{
|
|
86
96
|
* transformOptions?: {
|
|
@@ -89,14 +99,62 @@ function awaitContextCallbackAtFunctionStart (state, node, _parent, ancestry) {
|
|
|
89
99
|
* callbackThis?: boolean
|
|
90
100
|
* }
|
|
91
101
|
* }} state
|
|
92
|
-
* @param {
|
|
102
|
+
* @param {
|
|
103
|
+
* import('estree').ArrowFunctionExpression|
|
|
104
|
+
* import('estree').BlockStatement|
|
|
105
|
+
* import('estree').FunctionDeclaration|
|
|
106
|
+
* import('estree').FunctionExpression|
|
|
107
|
+
* import('estree').IfStatement
|
|
108
|
+
* } node
|
|
93
109
|
* @param {import('estree').Node} _parent
|
|
94
110
|
* @param {import('estree').Node[]} ancestry
|
|
95
111
|
* @returns {void}
|
|
96
112
|
*/
|
|
97
113
|
function awaitContextCallback (state, node, _parent, ancestry) {
|
|
114
|
+
let insertionTarget
|
|
115
|
+
let callbackAncestry = ancestry
|
|
116
|
+
|
|
117
|
+
if (node.type === 'BlockStatement') {
|
|
118
|
+
insertionTarget = node
|
|
119
|
+
} else if (functionTypes.has(node.type)) {
|
|
120
|
+
let callbackFunction = node
|
|
121
|
+
callbackAncestry = [node, ...ancestry]
|
|
122
|
+
|
|
123
|
+
if (!node.async) {
|
|
124
|
+
// Built-in function transforms run before later custom transforms. Keep knowledge of their generated wrapper
|
|
125
|
+
// here so instrumentation queries can continue to target the original function.
|
|
126
|
+
const [wrappedFunction] = query(node,
|
|
127
|
+
'VariableDeclarator[id.name="__apm$traced"] > ArrowFunctionExpression > BlockStatement > ' +
|
|
128
|
+
'VariableDeclaration > VariableDeclarator[id.name="__apm$wrapped"] > ' +
|
|
129
|
+
':matches(ArrowFunctionExpression, FunctionDeclaration, FunctionExpression)[async=true]')
|
|
130
|
+
if (wrappedFunction) {
|
|
131
|
+
callbackFunction = wrappedFunction
|
|
132
|
+
callbackAncestry.unshift(wrappedFunction)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
assert(callbackFunction.async && callbackFunction.body?.type === 'BlockStatement',
|
|
137
|
+
'awaitContextCallback: expected an async function with a block body')
|
|
138
|
+
insertionTarget = callbackFunction.body
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (insertionTarget) {
|
|
142
|
+
const generatedCallback = createAwaitedContextCallback(
|
|
143
|
+
state,
|
|
144
|
+
insertionTarget,
|
|
145
|
+
callbackAncestry,
|
|
146
|
+
'awaitContextCallback'
|
|
147
|
+
)
|
|
148
|
+
if (!generatedCallback) return
|
|
149
|
+
|
|
150
|
+
let insertionIndex = 0
|
|
151
|
+
while (typeof insertionTarget.body[insertionIndex]?.directive === 'string') insertionIndex++
|
|
152
|
+
insertionTarget.body.splice(insertionIndex, 0, ...generatedCallback.callbackStatements)
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
98
156
|
assert(node.type === 'IfStatement' && node.consequent?.type === 'BlockStatement',
|
|
99
|
-
'awaitContextCallback: expected an if statement with a block body')
|
|
157
|
+
'awaitContextCallback: expected a function, a block, or an if statement with a block body')
|
|
100
158
|
|
|
101
159
|
const originalStatements = node.consequent.body
|
|
102
160
|
const generatedCallback = createAwaitedContextCallback(
|
|
@@ -121,35 +179,6 @@ function awaitContextCallback (state, node, _parent, ancestry) {
|
|
|
121
179
|
node.consequent.body = [...callbackStatements, callbackBranch]
|
|
122
180
|
}
|
|
123
181
|
|
|
124
|
-
/**
|
|
125
|
-
* Awaits an optional context callback before entering the matched node's enclosing try block.
|
|
126
|
-
*
|
|
127
|
-
* @param {Parameters<typeof awaitContextCallback>[0]} state
|
|
128
|
-
* @param {import('estree').Node} node
|
|
129
|
-
* @param {import('estree').Node} _parent
|
|
130
|
-
* @param {import('estree').Node[]} ancestry
|
|
131
|
-
* @returns {void}
|
|
132
|
-
*/
|
|
133
|
-
function awaitContextCallbackAtTryStart (state, node, _parent, ancestry) {
|
|
134
|
-
let tryStatement = node.type === 'TryStatement' ? node : undefined
|
|
135
|
-
for (const ancestor of ancestry) {
|
|
136
|
-
if (tryStatement || functionTypes.has(ancestor.type)) break
|
|
137
|
-
if (ancestor.type === 'TryStatement') tryStatement = ancestor
|
|
138
|
-
}
|
|
139
|
-
assert(tryStatement?.block?.type === 'BlockStatement',
|
|
140
|
-
'awaitContextCallbackAtTryStart: expected an enclosing try statement with a block body')
|
|
141
|
-
|
|
142
|
-
const generatedCallback = createAwaitedContextCallback(
|
|
143
|
-
state,
|
|
144
|
-
tryStatement.block,
|
|
145
|
-
ancestry,
|
|
146
|
-
'awaitContextCallbackAtTryStart'
|
|
147
|
-
)
|
|
148
|
-
if (!generatedCallback) return
|
|
149
|
-
|
|
150
|
-
tryStatement.block.body.unshift(...generatedCallback.callbackStatements)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
182
|
/**
|
|
154
183
|
* @param {Parameters<typeof awaitContextCallback>[0]} state
|
|
155
184
|
* @param {import('estree').BlockStatement} insertionTarget
|