dd-trace 5.87.0 → 5.89.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 +60 -32
- package/ext/exporters.d.ts +1 -0
- package/ext/exporters.js +1 -0
- package/ext/tags.js +2 -0
- package/index.d.ts +234 -4
- package/package.json +18 -11
- package/packages/datadog-instrumentations/src/ai.js +54 -90
- package/packages/datadog-instrumentations/src/helpers/hook.js +17 -11
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +27 -110
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +103 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.js +108 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/compiler.js +74 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/index.js +43 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/matcher.js +49 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/transformer.js +121 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/{transforms.js → orchestrion/transforms.js} +143 -17
- package/packages/datadog-instrumentations/src/jest.js +176 -54
- package/packages/datadog-instrumentations/src/kafkajs.js +20 -17
- package/packages/datadog-instrumentations/src/playwright.js +1 -1
- package/packages/datadog-plugin-amqplib/src/consumer.js +14 -10
- package/packages/datadog-plugin-amqplib/src/producer.js +23 -19
- package/packages/datadog-plugin-bullmq/src/consumer.js +33 -11
- package/packages/datadog-plugin-bullmq/src/producer.js +60 -31
- package/packages/datadog-plugin-cucumber/src/index.js +9 -6
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +62 -5
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +297 -0
- package/packages/datadog-plugin-cypress/src/support.js +52 -9
- package/packages/datadog-plugin-jest/src/index.js +12 -2
- package/packages/datadog-plugin-jest/src/util.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +22 -12
- package/packages/datadog-plugin-kafkajs/src/producer.js +33 -22
- package/packages/datadog-plugin-mocha/src/index.js +9 -6
- package/packages/datadog-plugin-playwright/src/index.js +10 -6
- package/packages/datadog-plugin-vitest/src/index.js +13 -8
- package/packages/dd-trace/src/aiguard/sdk.js +5 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +4 -5
- package/packages/dd-trace/src/appsec/iast/path-line.js +36 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +3 -2
- package/packages/dd-trace/src/azure_metadata.js +0 -2
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +3 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
- package/packages/dd-trace/src/ci-visibility/requests/request.js +236 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +148 -197
- package/packages/dd-trace/src/config/helper.js +43 -1
- package/packages/dd-trace/src/config/index.js +38 -14
- package/packages/dd-trace/src/config/supported-configurations.json +4125 -512
- package/packages/dd-trace/src/constants.js +0 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -3
- package/packages/dd-trace/src/datastreams/checkpointer.js +13 -0
- package/packages/dd-trace/src/datastreams/index.js +3 -0
- package/packages/dd-trace/src/datastreams/manager.js +9 -0
- package/packages/dd-trace/src/datastreams/pathway.js +22 -3
- package/packages/dd-trace/src/datastreams/processor.js +140 -4
- package/packages/dd-trace/src/encode/agentless-json.js +155 -0
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/agent/writer.js +21 -8
- package/packages/dd-trace/src/exporters/agentless/index.js +89 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +184 -0
- package/packages/dd-trace/src/exporters/common/request.js +4 -4
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -3
- package/packages/dd-trace/src/opentelemetry/context_manager.js +19 -46
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +3 -4
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -4
- package/packages/dd-trace/src/pkg.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +57 -5
- package/packages/dd-trace/src/plugins/database.js +15 -2
- package/packages/dd-trace/src/plugins/util/test.js +48 -0
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -0
- package/packages/dd-trace/src/propagation-hash/index.js +145 -0
- package/packages/dd-trace/src/proxy.js +6 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
- package/packages/dd-trace/src/startup-log.js +53 -19
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/@datadog/source-map/index.js +1 -1
- package/vendor/dist/@isaacs/ttlcache/index.js +1 -1
- package/vendor/dist/@opentelemetry/core/index.js +1 -1
- package/vendor/dist/@opentelemetry/resources/index.js +1 -1
- package/vendor/dist/astring/index.js +1 -1
- package/vendor/dist/crypto-randomuuid/index.js +1 -1
- package/vendor/dist/escape-string-regexp/index.js +1 -1
- package/vendor/dist/esquery/index.js +1 -1
- package/vendor/dist/ignore/index.js +1 -1
- package/vendor/dist/istanbul-lib-coverage/index.js +1 -1
- package/vendor/dist/jest-docblock/index.js +1 -1
- package/vendor/dist/jsonpath-plus/index.js +1 -1
- package/vendor/dist/limiter/index.js +1 -1
- package/vendor/dist/lodash.sortby/index.js +1 -1
- package/vendor/dist/lru-cache/index.js +1 -1
- package/vendor/dist/meriyah/index.js +1 -1
- package/vendor/dist/module-details-from-path/index.js +1 -1
- package/vendor/dist/mutexify/promise/index.js +1 -1
- package/vendor/dist/opentracing/index.js +1 -1
- package/vendor/dist/path-to-regexp/index.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/retry/index.js +1 -1
- package/vendor/dist/rfdc/index.js +1 -1
- package/vendor/dist/semifies/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/vendor/dist/source-map/lib/util/index.js +1 -1
- package/vendor/dist/tlhunter-sorted-set/index.js +1 -1
- package/vendor/dist/ttl-set/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +0 -33
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +0 -106
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -741
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +0 -11
- package/packages/dd-trace/src/scope/noop/scope.js +0 -21
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
{
|
|
5
|
+
module: {
|
|
6
|
+
name: 'bullmq',
|
|
7
|
+
versionRange: '>=5.66.0',
|
|
8
|
+
filePath: 'dist/cjs/classes/queue.js',
|
|
9
|
+
},
|
|
10
|
+
functionQuery: {
|
|
11
|
+
methodName: 'add',
|
|
12
|
+
className: 'Queue',
|
|
13
|
+
kind: 'Async',
|
|
14
|
+
},
|
|
15
|
+
channelName: 'Queue_add',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
module: {
|
|
19
|
+
name: 'bullmq',
|
|
20
|
+
versionRange: '>=5.66.0',
|
|
21
|
+
filePath: 'dist/cjs/classes/queue.js',
|
|
22
|
+
},
|
|
23
|
+
functionQuery: {
|
|
24
|
+
methodName: 'addBulk',
|
|
25
|
+
className: 'Queue',
|
|
26
|
+
kind: 'Async',
|
|
27
|
+
},
|
|
28
|
+
channelName: 'Queue_addBulk',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
module: {
|
|
32
|
+
name: 'bullmq',
|
|
33
|
+
versionRange: '>=5.66.0',
|
|
34
|
+
filePath: 'dist/cjs/classes/worker.js',
|
|
35
|
+
},
|
|
36
|
+
functionQuery: {
|
|
37
|
+
methodName: 'callProcessJob',
|
|
38
|
+
className: 'Worker',
|
|
39
|
+
kind: 'Async',
|
|
40
|
+
},
|
|
41
|
+
channelName: 'Worker_callProcessJob',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
module: {
|
|
45
|
+
name: 'bullmq',
|
|
46
|
+
versionRange: '>=5.66.0',
|
|
47
|
+
filePath: 'dist/cjs/classes/flow-producer.js',
|
|
48
|
+
},
|
|
49
|
+
functionQuery: {
|
|
50
|
+
methodName: 'add',
|
|
51
|
+
className: 'FlowProducer',
|
|
52
|
+
kind: 'Async',
|
|
53
|
+
},
|
|
54
|
+
channelName: 'FlowProducer_add',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
module: {
|
|
58
|
+
name: 'bullmq',
|
|
59
|
+
versionRange: '>=5.66.0',
|
|
60
|
+
filePath: 'dist/esm/classes/queue.js',
|
|
61
|
+
},
|
|
62
|
+
functionQuery: {
|
|
63
|
+
methodName: 'add',
|
|
64
|
+
className: 'Queue',
|
|
65
|
+
kind: 'Async',
|
|
66
|
+
},
|
|
67
|
+
channelName: 'Queue_add',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
module: {
|
|
71
|
+
name: 'bullmq',
|
|
72
|
+
versionRange: '>=5.66.0',
|
|
73
|
+
filePath: 'dist/esm/classes/queue.js',
|
|
74
|
+
},
|
|
75
|
+
functionQuery: {
|
|
76
|
+
methodName: 'addBulk',
|
|
77
|
+
className: 'Queue',
|
|
78
|
+
kind: 'Async',
|
|
79
|
+
},
|
|
80
|
+
channelName: 'Queue_addBulk',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
module: {
|
|
84
|
+
name: 'bullmq',
|
|
85
|
+
versionRange: '>=5.66.0',
|
|
86
|
+
filePath: 'dist/esm/classes/worker.js',
|
|
87
|
+
},
|
|
88
|
+
functionQuery: {
|
|
89
|
+
methodName: 'callProcessJob',
|
|
90
|
+
className: 'Worker',
|
|
91
|
+
kind: 'Async',
|
|
92
|
+
},
|
|
93
|
+
channelName: 'Worker_callProcessJob',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
module: {
|
|
97
|
+
name: 'bullmq',
|
|
98
|
+
versionRange: '>=5.66.0',
|
|
99
|
+
filePath: 'dist/esm/classes/flow-producer.js',
|
|
100
|
+
},
|
|
101
|
+
functionQuery: {
|
|
102
|
+
methodName: 'add',
|
|
103
|
+
className: 'FlowProducer',
|
|
104
|
+
kind: 'Async',
|
|
105
|
+
},
|
|
106
|
+
channelName: 'FlowProducer_add',
|
|
107
|
+
},
|
|
108
|
+
]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = require('../../../../../dd-trace/src/log')
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line camelcase, no-undef
|
|
6
|
+
const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
|
7
|
+
|
|
8
|
+
const compiler = {
|
|
9
|
+
parse: (sourceText, options) => {
|
|
10
|
+
try {
|
|
11
|
+
// TODO: Figure out ESBuild `createRequire` issue and remove this hack.
|
|
12
|
+
const oxc = runtimeRequire(['oxc', 'parser'].join('-'))
|
|
13
|
+
|
|
14
|
+
compiler.parse = (sourceText, options) => {
|
|
15
|
+
const { program, errors } = oxc.parseSync('index.js', sourceText, {
|
|
16
|
+
...options,
|
|
17
|
+
preserveParens: false,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
if (errors?.length > 0) throw errors[0]
|
|
21
|
+
|
|
22
|
+
return program
|
|
23
|
+
}
|
|
24
|
+
} catch (e) {
|
|
25
|
+
log.error(e)
|
|
26
|
+
|
|
27
|
+
// Fallback for when OXC is not available.
|
|
28
|
+
const meriyah = require('../../../../../../vendor/dist/meriyah')
|
|
29
|
+
|
|
30
|
+
compiler.parse = (sourceText, { range, sourceType } = {}) => {
|
|
31
|
+
return meriyah.parse(sourceText.toString(), {
|
|
32
|
+
loc: range,
|
|
33
|
+
ranges: range,
|
|
34
|
+
module: sourceType === 'module',
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return compiler.parse(sourceText, options)
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
generate: (...args) => {
|
|
43
|
+
const astring = require('../../../../../../vendor/dist/astring')
|
|
44
|
+
|
|
45
|
+
compiler.generate = astring.generate
|
|
46
|
+
|
|
47
|
+
return compiler.generate(...args)
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
traverse: (ast, query, visitor) => {
|
|
51
|
+
const esquery = require('../../../../../../vendor/dist/esquery').default
|
|
52
|
+
|
|
53
|
+
compiler.traverse = (ast, query, visitor) => {
|
|
54
|
+
return esquery.traverse(ast, esquery.parse(query), visitor)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return compiler.traverse(ast, query, visitor)
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
query: (ast, query) => {
|
|
61
|
+
const esquery = require('../../../../../../vendor/dist/esquery').default
|
|
62
|
+
|
|
63
|
+
compiler.query = esquery.query
|
|
64
|
+
|
|
65
|
+
return compiler.query(ast, query)
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
parse: (...args) => compiler.parse(...args),
|
|
71
|
+
generate: (...args) => compiler.generate(...args),
|
|
72
|
+
traverse: (...args) => compiler.traverse(...args),
|
|
73
|
+
query: (...args) => compiler.query(...args),
|
|
74
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
This folder is basically a JavaScript version of Orchestrion-JS. The goal is
|
|
5
|
+
not to replace Orchestrion-JS, but rather to make it easier and faster to write
|
|
6
|
+
new integrations in the short-term, especially as many changes to the rewriter
|
|
7
|
+
will be needed as all the patterns we need have not been identified yet. This
|
|
8
|
+
will avoid the back and forth of having to make Rust changes to an external
|
|
9
|
+
library for every integration change or addition that requires something new.
|
|
10
|
+
|
|
11
|
+
In the meantime, we'll work concurrently on a change to Orchestrion-JS that
|
|
12
|
+
adds an "arbitrary transform" or "plugin" system that can be used from
|
|
13
|
+
JavaScript, in order to enable quick iteration while still using Orchestrion-JS.
|
|
14
|
+
Once that's done we'll use that, so that we can remove this JS approach and
|
|
15
|
+
return to using Orchestrion-JS.
|
|
16
|
+
|
|
17
|
+
The long term goal is to backport any additional features we add to the JS
|
|
18
|
+
rewriter (or using the plugin system in Orchestrion-JS once we're using that)
|
|
19
|
+
to Orchestrion-JS once we're confident that the implementation is fairly
|
|
20
|
+
complete and has all features we need.
|
|
21
|
+
|
|
22
|
+
Here is a list of the additions and changes in this rewriter compared to
|
|
23
|
+
Orchestrion-JS that will need to be backported:
|
|
24
|
+
|
|
25
|
+
(NOTE: Please keep this list up-to-date whenever new features are added)
|
|
26
|
+
|
|
27
|
+
- Supports an `astQuery` field to filter AST nodes with an esquery query. This
|
|
28
|
+
is mostly meant to be used when experimenting or if what needs to be queried
|
|
29
|
+
is not a function. We'll see over time if something like this is needed to be
|
|
30
|
+
backported or if it can be replaced by simpler queries.
|
|
31
|
+
- Supports replacing methods of child class instances in the base constructor.
|
|
32
|
+
- Supports tracing iterator (sync/async) returning functions (sync/async).
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/* eslint-disable camelcase */
|
|
36
|
+
|
|
37
|
+
const { InstrumentationMatcher } = require('./matcher')
|
|
38
|
+
|
|
39
|
+
function create (configs, dc_module) {
|
|
40
|
+
return new InstrumentationMatcher(configs, dc_module)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { create }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* eslint-disable camelcase */
|
|
4
|
+
|
|
5
|
+
const semifies = require('../../../../../../vendor/dist/semifies')
|
|
6
|
+
const { Transformer } = require('./transformer')
|
|
7
|
+
|
|
8
|
+
// TODO: addTransform
|
|
9
|
+
|
|
10
|
+
class InstrumentationMatcher {
|
|
11
|
+
#configs = []
|
|
12
|
+
#dc_module = null
|
|
13
|
+
#transformers = {}
|
|
14
|
+
|
|
15
|
+
constructor (configs, dc_module) {
|
|
16
|
+
this.#configs = configs
|
|
17
|
+
this.#dc_module = dc_module || 'diagnostics_channel'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
free () {
|
|
21
|
+
this.#transformers = {}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getTransformer (module_name, version, file_path) {
|
|
25
|
+
const id = `${module_name}/${file_path}@${version}`
|
|
26
|
+
|
|
27
|
+
if (this.#transformers[id]) return this.#transformers[id]
|
|
28
|
+
|
|
29
|
+
const configs = this.#configs.filter(({ module: { name, filePath, versionRange } }) =>
|
|
30
|
+
name === module_name &&
|
|
31
|
+
filePath === file_path &&
|
|
32
|
+
semifies(version, versionRange)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if (configs.length === 0) return
|
|
36
|
+
|
|
37
|
+
this.#transformers[id] = new Transformer(
|
|
38
|
+
module_name,
|
|
39
|
+
version,
|
|
40
|
+
file_path,
|
|
41
|
+
configs,
|
|
42
|
+
this.#dc_module
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return this.#transformers[id]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { InstrumentationMatcher }
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* eslint-disable camelcase */
|
|
4
|
+
|
|
5
|
+
const { generate, parse, traverse } = require('./compiler')
|
|
6
|
+
const transforms = require('./transforms')
|
|
7
|
+
|
|
8
|
+
let SourceMapConsumer
|
|
9
|
+
let SourceMapGenerator
|
|
10
|
+
|
|
11
|
+
class Transformer {
|
|
12
|
+
#module_name = null
|
|
13
|
+
#file_path = null
|
|
14
|
+
#configs = []
|
|
15
|
+
#dc_module = null
|
|
16
|
+
|
|
17
|
+
// TODO: module_name false for user module
|
|
18
|
+
constructor (module_name, _version, file_path, configs, dc_module) {
|
|
19
|
+
this.#module_name = module_name
|
|
20
|
+
this.#file_path = file_path
|
|
21
|
+
this.#configs = configs
|
|
22
|
+
this.#dc_module = dc_module
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
free () {
|
|
26
|
+
// Freeing is not needed for a JavaScript implementation.
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
transform (code, module_type, sourcemap) {
|
|
30
|
+
if (!code) return { code }
|
|
31
|
+
|
|
32
|
+
const sourceType = module_type === 'esm' ? 'module' : 'script'
|
|
33
|
+
|
|
34
|
+
let ast
|
|
35
|
+
|
|
36
|
+
for (const config of this.#configs) {
|
|
37
|
+
const { astQuery, functionQuery = {} } = config
|
|
38
|
+
|
|
39
|
+
ast ??= parse(code.toString(), { range: true, sourceType })
|
|
40
|
+
|
|
41
|
+
const query = astQuery || this.#fromFunctionQuery(functionQuery)
|
|
42
|
+
const state = { ...config, dcModule: this.#dc_module, sourceType, functionQuery }
|
|
43
|
+
|
|
44
|
+
state.operator = this.#getOperator(state)
|
|
45
|
+
|
|
46
|
+
traverse(ast, query, (...args) => this.#visit(state, ...args))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (ast) {
|
|
50
|
+
SourceMapConsumer ??= require('../../../../../../vendor/dist/@datadog/source-map').SourceMapConsumer
|
|
51
|
+
SourceMapGenerator ??= require('../../../../../../vendor/dist/@datadog/source-map').SourceMapGenerator
|
|
52
|
+
|
|
53
|
+
const file = `${this.#module_name}/${this.#file_path}`
|
|
54
|
+
const sourceMapInput = sourcemap ? new SourceMapConsumer(sourcemap) : { file }
|
|
55
|
+
const sourceMap = new SourceMapGenerator(sourceMapInput)
|
|
56
|
+
const code = generate(ast, { sourceMap })
|
|
57
|
+
const map = sourceMap.toString()
|
|
58
|
+
|
|
59
|
+
return { code, map }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { code }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#visit (state, ...args) {
|
|
66
|
+
const transform = transforms[state.operator]
|
|
67
|
+
const { index } = state.functionQuery
|
|
68
|
+
|
|
69
|
+
if (index !== undefined) {
|
|
70
|
+
state.functionIndex = ++state.functionIndex || 0
|
|
71
|
+
|
|
72
|
+
if (index !== state.functionIndex) return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
transform(state, ...args)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
#getOperator ({ functionQuery: { kind } }) {
|
|
79
|
+
switch (kind) {
|
|
80
|
+
case 'Async': return 'tracePromise'
|
|
81
|
+
case 'AsyncIterator': return 'traceAsyncIterator'
|
|
82
|
+
case 'Callback': return 'traceCallback'
|
|
83
|
+
case 'Iterator': return 'traceIterator'
|
|
84
|
+
case 'Sync': return 'traceSync'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#fromFunctionQuery (functionQuery) {
|
|
89
|
+
const { functionName, expressionName, className } = functionQuery
|
|
90
|
+
const method = functionQuery.methodName || functionQuery.privateMethodName
|
|
91
|
+
const type = functionQuery.privateMethodName ? 'PrivateIdentifier' : 'Identifier'
|
|
92
|
+
const queries = []
|
|
93
|
+
|
|
94
|
+
if (className) {
|
|
95
|
+
queries.push(
|
|
96
|
+
`[id.name="${className}"]`,
|
|
97
|
+
`[id.name="${className}"] > ClassExpression`,
|
|
98
|
+
`[id.name="${className}"] > ClassBody > [key.name="${method}"][key.type=${type}] > [async]`,
|
|
99
|
+
`[id.name="${className}"] > ClassExpression > ClassBody > [key.name="${method}"][key.type=${type}] > [async]`
|
|
100
|
+
)
|
|
101
|
+
} else if (method) {
|
|
102
|
+
queries.push(
|
|
103
|
+
`ClassBody > [key.name="${method}"][key.type=${type}] > [async]`,
|
|
104
|
+
`Property[key.name="${method}"][key.type=${type}] > [async]`
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (functionName) {
|
|
109
|
+
queries.push(`FunctionDeclaration[id.name="${functionName}"][async]`)
|
|
110
|
+
} else if (expressionName) {
|
|
111
|
+
queries.push(
|
|
112
|
+
`FunctionExpression[id.name="${expressionName}"][async]`,
|
|
113
|
+
`ArrowFunctionExpression[id.name="${expressionName}"][async]`
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return queries.join(', ')
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = { Transformer }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { parse, query } = require('./compiler')
|
|
3
|
+
const { parse, query, traverse } = require('./compiler')
|
|
4
4
|
|
|
5
5
|
const tracingChannelPredicate = (node) => (
|
|
6
6
|
node.specifiers?.[0]?.local?.name === 'tr_ch_apm_tracingChannel' ||
|
|
@@ -8,15 +8,15 @@ const tracingChannelPredicate = (node) => (
|
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
const transforms = module.exports = {
|
|
11
|
-
tracingChannelImport ({
|
|
11
|
+
tracingChannelImport ({ dcModule, sourceType }, node) {
|
|
12
12
|
if (node.body.some(tracingChannelPredicate)) return
|
|
13
13
|
|
|
14
14
|
const index = node.body.findIndex(child => child.directive === 'use strict')
|
|
15
|
-
const code =
|
|
16
|
-
?
|
|
17
|
-
:
|
|
15
|
+
const code = sourceType === 'module'
|
|
16
|
+
? `import { tracingChannel as tr_ch_apm_tracingChannel } from "${dcModule}"`
|
|
17
|
+
: `const {tracingChannel: tr_ch_apm_tracingChannel} = require("${dcModule}")`
|
|
18
18
|
|
|
19
|
-
node.body.splice(index + 1, 0, parse(code, {
|
|
19
|
+
node.body.splice(index + 1, 0, parse(code, { sourceType }).body[0])
|
|
20
20
|
},
|
|
21
21
|
|
|
22
22
|
tracingChannelDeclaration (state, node) {
|
|
@@ -35,7 +35,9 @@ const transforms = module.exports = {
|
|
|
35
35
|
node.body.splice(index + 1, 0, parse(code).body[0])
|
|
36
36
|
},
|
|
37
37
|
|
|
38
|
+
traceAsyncIterator: traceAny,
|
|
38
39
|
traceCallback: traceAny,
|
|
40
|
+
traceIterator: traceAny,
|
|
39
41
|
tracePromise: traceAny,
|
|
40
42
|
traceSync: traceAny,
|
|
41
43
|
}
|
|
@@ -51,18 +53,25 @@ function traceAny (state, node, _parent, ancestry) {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
function traceFunction (state, node, program) {
|
|
54
|
-
const { operator } = state
|
|
55
|
-
|
|
56
56
|
transforms.tracingChannelDeclaration(state, program)
|
|
57
57
|
|
|
58
58
|
node.body = wrap(state, {
|
|
59
|
-
type: '
|
|
59
|
+
type: 'FunctionExpression',
|
|
60
60
|
params: node.params,
|
|
61
61
|
body: node.body,
|
|
62
|
-
async:
|
|
62
|
+
async: node.async,
|
|
63
63
|
expression: false,
|
|
64
|
-
generator:
|
|
65
|
-
})
|
|
64
|
+
generator: node.generator,
|
|
65
|
+
}, program)
|
|
66
|
+
|
|
67
|
+
// The original function no longer contains any calls to `await` or `yield` as
|
|
68
|
+
// the function body is copied to the internal wrapped function, so we set
|
|
69
|
+
// these to false to avoid altering the return value of the wrapper. The old
|
|
70
|
+
// values are instead copied to the new AST node above.
|
|
71
|
+
node.generator = false
|
|
72
|
+
node.async = false
|
|
73
|
+
|
|
74
|
+
wrapSuper(state, node)
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
function traceInstanceMethod (state, node, program) {
|
|
@@ -100,15 +109,19 @@ function traceInstanceMethod (state, node, program) {
|
|
|
100
109
|
const fn = ctorBody[1].expression.right
|
|
101
110
|
|
|
102
111
|
fn.async = operator === 'tracePromise'
|
|
103
|
-
fn.body = wrap(state, { type: 'Identifier', name: `__apm$${methodName}` })
|
|
112
|
+
fn.body = wrap(state, { type: 'Identifier', name: `__apm$${methodName}` }, program)
|
|
113
|
+
|
|
114
|
+
wrapSuper(state, fn)
|
|
104
115
|
|
|
105
116
|
ctor.value.body.body.push(...ctorBody)
|
|
106
117
|
}
|
|
107
118
|
|
|
108
|
-
function wrap (state, node) {
|
|
119
|
+
function wrap (state, node, program) {
|
|
109
120
|
const { channelName, operator } = state
|
|
110
121
|
|
|
122
|
+
if (operator === 'traceAsyncIterator') return wrapIterator(state, node, program)
|
|
111
123
|
if (operator === 'traceCallback') return wrapCallback(state, node)
|
|
124
|
+
if (operator === 'traceIterator') return wrapIterator(state, node, program)
|
|
112
125
|
|
|
113
126
|
const async = operator === 'tracePromise' ? 'async' : ''
|
|
114
127
|
const channelVariable = 'tr_ch_apm$' + channelName.replaceAll(':', '_')
|
|
@@ -133,12 +146,61 @@ function wrap (state, node) {
|
|
|
133
146
|
return wrapper
|
|
134
147
|
}
|
|
135
148
|
|
|
149
|
+
function wrapSuper (_state, node) {
|
|
150
|
+
const members = new Set()
|
|
151
|
+
|
|
152
|
+
traverse(
|
|
153
|
+
node.body,
|
|
154
|
+
'[object.type=Super]',
|
|
155
|
+
(node, parent) => {
|
|
156
|
+
const { name } = node.property
|
|
157
|
+
|
|
158
|
+
let child
|
|
159
|
+
|
|
160
|
+
if (parent.callee) {
|
|
161
|
+
// This is needed because for generator functions we have to move the
|
|
162
|
+
// original function to a nested wrapped function, but we can't use an
|
|
163
|
+
// arrow function because arrow function cannot be generator functions,
|
|
164
|
+
// and `super` cannot be called from a nested function, so we have to
|
|
165
|
+
// rewrite any `super` call to not use the keyword.
|
|
166
|
+
const { expression } = parse(`__apm$super['${name}'].call(this)`).body[0]
|
|
167
|
+
|
|
168
|
+
parent.callee = child = expression.callee
|
|
169
|
+
parent.arguments.unshift(...expression.arguments)
|
|
170
|
+
} else {
|
|
171
|
+
parent.expression = child = parse(`__apm$super['${name}']`).body[0]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
child.computed = parent.callee.computed
|
|
175
|
+
child.optional = parent.callee.optional
|
|
176
|
+
|
|
177
|
+
members.add(name)
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
for (const name of members) {
|
|
182
|
+
const member = parse(`
|
|
183
|
+
class Wrapper {
|
|
184
|
+
wrapper () {
|
|
185
|
+
__apm$super['${name}'] = super['${name}']
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
`).body[0].body.body[0].value.body.body[0]
|
|
189
|
+
|
|
190
|
+
node.body.body.unshift(member)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (members.size > 0) {
|
|
194
|
+
node.body.body.unshift(parse('const __apm$super = {}').body[0])
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
136
198
|
function wrapCallback (state, node) {
|
|
137
|
-
const { channelName, functionQuery: {
|
|
199
|
+
const { channelName, functionQuery: { callbackIndex = -1 } } = state
|
|
138
200
|
const channelVariable = 'tr_ch_apm$' + channelName.replaceAll(':', '_')
|
|
139
201
|
const wrapper = parse(`
|
|
140
202
|
function wrapper () {
|
|
141
|
-
const __apm$cb = Array.prototype.at.call(arguments, ${
|
|
203
|
+
const __apm$cb = Array.prototype.at.call(arguments, ${callbackIndex});
|
|
142
204
|
const __apm$ctx = {
|
|
143
205
|
arguments,
|
|
144
206
|
self: this,
|
|
@@ -173,7 +235,7 @@ function wrapCallback (state, node) {
|
|
|
173
235
|
if (typeof __apm$cb !== 'function') {
|
|
174
236
|
return __apm$traced();
|
|
175
237
|
}
|
|
176
|
-
Array.prototype.splice.call(arguments, ${
|
|
238
|
+
Array.prototype.splice.call(arguments, ${callbackIndex}, 1, __apm$wrappedCb);
|
|
177
239
|
|
|
178
240
|
return ${channelVariable}.start.runStores(__apm$ctx, () => {
|
|
179
241
|
try {
|
|
@@ -194,3 +256,67 @@ function wrapCallback (state, node) {
|
|
|
194
256
|
|
|
195
257
|
return wrapper
|
|
196
258
|
}
|
|
259
|
+
|
|
260
|
+
function wrapIterator (state, node, program) {
|
|
261
|
+
const { channelName, operator } = state
|
|
262
|
+
const baseChannel = channelName.replaceAll(':', '_')
|
|
263
|
+
const channelVariable = 'tr_ch_apm$' + baseChannel
|
|
264
|
+
const nextChannel = baseChannel + '_next'
|
|
265
|
+
const traceMethod = operator === 'traceAsyncIterator' ? 'tracePromise' : 'traceSync'
|
|
266
|
+
const traceNext = `tr_ch_apm$${nextChannel}.${traceMethod}`
|
|
267
|
+
|
|
268
|
+
transforms.tracingChannelDeclaration({ ...state, channelName: nextChannel }, program)
|
|
269
|
+
|
|
270
|
+
const wrapper = parse(`
|
|
271
|
+
function wrapper () {
|
|
272
|
+
const __apm$traced = () => {
|
|
273
|
+
const __apm$wrapped = () => {};
|
|
274
|
+
return __apm$wrapped.apply(this, arguments);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
if (!${channelVariable}.start.hasSubscribers) return __apm$traced();
|
|
278
|
+
|
|
279
|
+
{
|
|
280
|
+
const wrap = iter => {
|
|
281
|
+
const { next: iterNext, return: iterReturn, throw: iterThrow } = iter;
|
|
282
|
+
|
|
283
|
+
iter.next = (...args) => ${traceNext}(iterNext, ctx, iter, ...args);
|
|
284
|
+
iter.return = (...args) => ${traceNext}(iterReturn, ctx, iter, ...args);
|
|
285
|
+
iter.throw = (...args) => ${traceNext}(iterThrow, ctx, iter, ...args);
|
|
286
|
+
|
|
287
|
+
return iter;
|
|
288
|
+
};
|
|
289
|
+
const ctx = {
|
|
290
|
+
arguments,
|
|
291
|
+
self: this,
|
|
292
|
+
moduleVersion: "1.0.0"
|
|
293
|
+
};
|
|
294
|
+
const iter = ${channelVariable}.traceSync(__apm$traced, ctx);
|
|
295
|
+
|
|
296
|
+
if (typeof iter.then !== 'function') return wrap(iter);
|
|
297
|
+
|
|
298
|
+
return iter.then(result => {
|
|
299
|
+
ctx.result = result;
|
|
300
|
+
|
|
301
|
+
${channelVariable}.asyncStart.publish(ctx);
|
|
302
|
+
${channelVariable}.asyncEnd.publish(ctx);
|
|
303
|
+
|
|
304
|
+
return wrap(result);
|
|
305
|
+
}, err => {
|
|
306
|
+
ctx.error = err;
|
|
307
|
+
|
|
308
|
+
${channelVariable}.error.publish(ctx);
|
|
309
|
+
${channelVariable}.asyncStart.publish(ctx);
|
|
310
|
+
${channelVariable}.asyncEnd.publish(ctx);
|
|
311
|
+
|
|
312
|
+
return Promise.reject(err);
|
|
313
|
+
});
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
`).body[0].body // Extract only block statement of function body.
|
|
317
|
+
|
|
318
|
+
// Replace the right-hand side assignment of `const __apm$wrapped = () => {}`.
|
|
319
|
+
query(wrapper, '[id.name=__apm$wrapped]')[0].init = node
|
|
320
|
+
|
|
321
|
+
return wrapper
|
|
322
|
+
}
|