dd-trace 2.42.0 → 2.43.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/MIGRATING.md +0 -14
- package/package.json +18 -18
- package/packages/datadog-esbuild/index.js +109 -31
- package/packages/datadog-instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +6 -2
- package/packages/datadog-instrumentations/src/fetch.js +24 -21
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +54 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +1 -4
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +7 -2
- package/packages/datadog-instrumentations/src/http/client.js +41 -32
- package/packages/datadog-instrumentations/src/http2/client.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +63 -1
- package/packages/datadog-plugin-fetch/src/index.js +8 -13
- package/packages/datadog-plugin-http/src/client.js +25 -20
- package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +11 -7
- package/packages/dd-trace/src/appsec/passport.js +1 -1
- package/packages/dd-trace/src/config.js +7 -5
- package/packages/dd-trace/src/plugin_manager.js +6 -1
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/proxy.js +2 -2
- package/packages/dd-trace/src/serverless.js +51 -7
- package/packages/diagnostics_channel/src/index.js +1 -1
- package/packages/dd-trace/src/dcitm.js +0 -53
package/MIGRATING.md
CHANGED
|
@@ -29,20 +29,6 @@ switching to `jest-circus` to anyone still using `jest-jasmine2`.
|
|
|
29
29
|
|
|
30
30
|
We now support only Next.js 10.2 and up.
|
|
31
31
|
|
|
32
|
-
### W3C headers are now prioritized over Datadog headers
|
|
33
|
-
|
|
34
|
-
As we move towards open standards, we have decided to prioritize W3C Trace
|
|
35
|
-
Context headers over our own vendor-specific headers for context propagation
|
|
36
|
-
across services. For most applications this shouldn't change anything and
|
|
37
|
-
distributed tracing should continue to work seamlessly.
|
|
38
|
-
|
|
39
|
-
In some rare cases it's possible that some of the services involved in a trace
|
|
40
|
-
are not instrumented by Datadog at all which can cause spans within the trace to
|
|
41
|
-
become disconnected. While the data would still be available in the UI, the
|
|
42
|
-
relationship between spans would no longer be visible. This can be addressed by
|
|
43
|
-
restoring the previous behaviour using
|
|
44
|
-
`DD_TRACE_PROPAGATION_STYLE='datadog,tracecontext'`.
|
|
45
|
-
|
|
46
32
|
## 2.0 to 3.0
|
|
47
33
|
|
|
48
34
|
### Node 12 is no longer supported
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.43.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -77,10 +77,10 @@
|
|
|
77
77
|
"@opentelemetry/core": "<1.4.0",
|
|
78
78
|
"crypto-randomuuid": "^1.0.0",
|
|
79
79
|
"diagnostics_channel": "^1.1.0",
|
|
80
|
-
"ignore": "^5.2.
|
|
81
|
-
"import-in-the-middle": "^1.
|
|
80
|
+
"ignore": "^5.2.4",
|
|
81
|
+
"import-in-the-middle": "^1.4.1",
|
|
82
82
|
"int64-buffer": "^0.1.9",
|
|
83
|
-
"ipaddr.js": "^2.0
|
|
83
|
+
"ipaddr.js": "^2.1.0",
|
|
84
84
|
"istanbul-lib-coverage": "3.2.0",
|
|
85
85
|
"koalas": "^1.0.2",
|
|
86
86
|
"limiter": "^1.1.4",
|
|
@@ -92,23 +92,23 @@
|
|
|
92
92
|
"methods": "^1.1.2",
|
|
93
93
|
"module-details-from-path": "^1.0.3",
|
|
94
94
|
"msgpack-lite": "^0.1.26",
|
|
95
|
-
"node-abort-controller": "^3.
|
|
95
|
+
"node-abort-controller": "^3.1.1",
|
|
96
96
|
"opentracing": ">=0.12.1",
|
|
97
97
|
"path-to-regexp": "^0.1.2",
|
|
98
98
|
"protobufjs": "^7.2.4",
|
|
99
|
-
"retry": "^0.
|
|
100
|
-
"semver": "^7.
|
|
99
|
+
"retry": "^0.13.1",
|
|
100
|
+
"semver": "^7.5.4"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
103
|
"autocannon": "^4.5.2",
|
|
104
104
|
"axios": "^0.21.2",
|
|
105
105
|
"benchmark": "^2.1.4",
|
|
106
|
-
"body-parser": "^1.
|
|
107
|
-
"chai": "^4.
|
|
108
|
-
"chalk": "^3.0
|
|
109
|
-
"checksum": "^0.
|
|
110
|
-
"cli-table3": "^0.
|
|
111
|
-
"dotenv": "
|
|
106
|
+
"body-parser": "^1.20.2",
|
|
107
|
+
"chai": "^4.3.7",
|
|
108
|
+
"chalk": "^5.3.0",
|
|
109
|
+
"checksum": "^1.0.0",
|
|
110
|
+
"cli-table3": "^0.6.3",
|
|
111
|
+
"dotenv": "16.3.1",
|
|
112
112
|
"esbuild": "0.16.12",
|
|
113
113
|
"eslint": "^8.23.0",
|
|
114
114
|
"eslint-config-standard": "^11.0.0-beta.0",
|
|
@@ -117,13 +117,13 @@
|
|
|
117
117
|
"eslint-plugin-node": "^5.2.1",
|
|
118
118
|
"eslint-plugin-promise": "^3.6.0",
|
|
119
119
|
"eslint-plugin-standard": "^3.0.1",
|
|
120
|
-
"express": "^4.
|
|
120
|
+
"express": "^4.18.2",
|
|
121
121
|
"get-port": "^3.2.0",
|
|
122
122
|
"glob": "^7.1.6",
|
|
123
123
|
"graphql": "0.13.2",
|
|
124
124
|
"jszip": "^3.5.0",
|
|
125
125
|
"knex": "^2.4.2",
|
|
126
|
-
"mkdirp": "^0.
|
|
126
|
+
"mkdirp": "^3.0.1",
|
|
127
127
|
"mocha": "8",
|
|
128
128
|
"multer": "^1.4.5-lts.1",
|
|
129
129
|
"nock": "^11.3.3",
|
|
@@ -131,9 +131,9 @@
|
|
|
131
131
|
"pprof-format": "^2.0.7",
|
|
132
132
|
"proxyquire": "^1.8.0",
|
|
133
133
|
"rimraf": "^3.0.0",
|
|
134
|
-
"sinon": "^
|
|
134
|
+
"sinon": "^15.2.0",
|
|
135
135
|
"sinon-chai": "^3.7.0",
|
|
136
|
-
"tap": "^16.3.
|
|
137
|
-
"tape": "^
|
|
136
|
+
"tap": "^16.3.7",
|
|
137
|
+
"tape": "^5.6.5"
|
|
138
138
|
}
|
|
139
139
|
}
|
|
@@ -2,73 +2,105 @@
|
|
|
2
2
|
|
|
3
3
|
/* eslint-disable no-console */
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const instrumented = Object.keys(require('../datadog-instrumentations/src/helpers/hooks.js'))
|
|
8
|
-
const rawBuiltins = require('module').builtinModules
|
|
5
|
+
const instrumentations = require('../datadog-instrumentations/src/helpers/instrumentations.js')
|
|
6
|
+
const hooks = require('../datadog-instrumentations/src/helpers/hooks.js')
|
|
9
7
|
|
|
10
8
|
warnIfUnsupported()
|
|
11
9
|
|
|
10
|
+
for (const hook of Object.values(hooks)) {
|
|
11
|
+
hook()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const modulesOfInterest = new Set()
|
|
15
|
+
|
|
16
|
+
for (const instrumentation of Object.values(instrumentations)) {
|
|
17
|
+
for (const entry of instrumentation) {
|
|
18
|
+
if (!entry.file) {
|
|
19
|
+
modulesOfInterest.add(entry.name) // e.g. "redis"
|
|
20
|
+
} else {
|
|
21
|
+
modulesOfInterest.add(`${entry.name}/${entry.file}`) // e.g. "redis/my/file.js"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const NAMESPACE = 'datadog'
|
|
27
|
+
const NM = 'node_modules/'
|
|
28
|
+
const INSTRUMENTED = Object.keys(instrumentations)
|
|
29
|
+
const RAW_BUILTINS = require('module').builtinModules
|
|
30
|
+
const CHANNEL = 'dd-trace:bundler:load'
|
|
31
|
+
|
|
12
32
|
const builtins = new Set()
|
|
13
33
|
|
|
14
|
-
for (const builtin of
|
|
34
|
+
for (const builtin of RAW_BUILTINS) {
|
|
15
35
|
builtins.add(builtin)
|
|
16
36
|
builtins.add(`node:${builtin}`)
|
|
17
37
|
}
|
|
18
38
|
|
|
19
|
-
const packagesOfInterest = new Set()
|
|
20
|
-
|
|
21
39
|
const DEBUG = !!process.env.DD_TRACE_DEBUG
|
|
22
40
|
|
|
23
|
-
// We don't want to handle any built-in packages
|
|
41
|
+
// We don't want to handle any built-in packages
|
|
24
42
|
// Those packages will still be handled via RITM
|
|
25
43
|
// Attempting to instrument them would fail as they have no package.json file
|
|
26
|
-
for (const pkg of
|
|
44
|
+
for (const pkg of INSTRUMENTED) {
|
|
27
45
|
if (builtins.has(pkg)) continue
|
|
28
46
|
if (pkg.startsWith('node:')) continue
|
|
29
|
-
|
|
47
|
+
modulesOfInterest.add(pkg)
|
|
30
48
|
}
|
|
31
49
|
|
|
32
|
-
const DC_CHANNEL = 'dd-trace:bundledModuleLoadStart'
|
|
33
|
-
|
|
34
50
|
module.exports.name = 'datadog-esbuild'
|
|
35
51
|
|
|
36
52
|
module.exports.setup = function (build) {
|
|
37
53
|
build.onResolve({ filter: /.*/ }, args => {
|
|
54
|
+
let fullPathToModule
|
|
55
|
+
try {
|
|
56
|
+
fullPathToModule = dotFriendlyResolve(args.path, args.resolveDir)
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.warn(`Unable to find "${args.path}". Is the package dead code?`)
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
const extracted = extractPackageAndModulePath(fullPathToModule)
|
|
38
62
|
const packageName = args.path
|
|
39
63
|
|
|
40
|
-
|
|
64
|
+
const internal = builtins.has(args.path)
|
|
65
|
+
|
|
66
|
+
if (args.namespace === 'file' && (
|
|
67
|
+
modulesOfInterest.has(packageName) || modulesOfInterest.has(`${extracted.pkg}/${extracted.path}`))
|
|
68
|
+
) {
|
|
41
69
|
// The file namespace is used when requiring files from disk in userland
|
|
42
70
|
|
|
43
71
|
let pathToPackageJson
|
|
44
72
|
try {
|
|
45
|
-
pathToPackageJson = require.resolve(`${
|
|
73
|
+
pathToPackageJson = require.resolve(`${extracted.pkg}/package.json`, { paths: [ args.resolveDir ] })
|
|
46
74
|
} catch (err) {
|
|
47
75
|
if (err.code === 'MODULE_NOT_FOUND') {
|
|
48
|
-
|
|
76
|
+
if (!internal) {
|
|
77
|
+
console.warn(`Unable to find "${extracted.pkg}/package.json". Is the package dead code?`)
|
|
78
|
+
}
|
|
49
79
|
return
|
|
50
80
|
} else {
|
|
51
81
|
throw err
|
|
52
82
|
}
|
|
53
83
|
}
|
|
54
84
|
|
|
55
|
-
const
|
|
85
|
+
const packageJson = require(pathToPackageJson)
|
|
56
86
|
|
|
57
|
-
if (DEBUG) {
|
|
58
|
-
console.log(`resolve ${packageName}@${pkg.version}`)
|
|
59
|
-
}
|
|
87
|
+
if (DEBUG) console.log(`RESOLVE ${packageName}@${packageJson.version}`)
|
|
60
88
|
|
|
61
89
|
// https://esbuild.github.io/plugins/#on-resolve-arguments
|
|
62
90
|
return {
|
|
63
|
-
path:
|
|
91
|
+
path: fullPathToModule,
|
|
64
92
|
namespace: NAMESPACE,
|
|
65
93
|
pluginData: {
|
|
66
|
-
version:
|
|
94
|
+
version: packageJson.version,
|
|
95
|
+
pkg: extracted.pkg,
|
|
96
|
+
path: extracted.path,
|
|
97
|
+
full: fullPathToModule,
|
|
98
|
+
raw: packageName,
|
|
99
|
+
internal
|
|
67
100
|
}
|
|
68
101
|
}
|
|
69
|
-
} else if (args.namespace ===
|
|
102
|
+
} else if (args.namespace === NAMESPACE) {
|
|
70
103
|
// The datadog namespace is used when requiring files that are injected during the onLoad stage
|
|
71
|
-
// see note in onLoad
|
|
72
104
|
|
|
73
105
|
if (builtins.has(packageName)) return
|
|
74
106
|
|
|
@@ -80,23 +112,28 @@ module.exports.setup = function (build) {
|
|
|
80
112
|
})
|
|
81
113
|
|
|
82
114
|
build.onLoad({ filter: /.*/, namespace: NAMESPACE }, args => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
115
|
+
const data = args.pluginData
|
|
116
|
+
|
|
117
|
+
if (DEBUG) console.log(`LOAD ${data.pkg}@${data.version}, pkg "${data.path}"`)
|
|
118
|
+
|
|
119
|
+
const path = data.raw !== data.pkg
|
|
120
|
+
? `${data.pkg}/${data.path}`
|
|
121
|
+
: data.pkg
|
|
86
122
|
|
|
87
|
-
// JSON.stringify adds double quotes. For perf gain could simply add in quotes when we know it's safe.
|
|
88
123
|
const contents = `
|
|
89
124
|
const dc = require('diagnostics_channel');
|
|
90
|
-
const ch = dc.channel(${
|
|
91
|
-
const mod = require(${
|
|
125
|
+
const ch = dc.channel('${CHANNEL}');
|
|
126
|
+
const mod = require('${args.path}');
|
|
92
127
|
const payload = {
|
|
93
128
|
module: mod,
|
|
94
|
-
|
|
95
|
-
|
|
129
|
+
version: '${data.version}',
|
|
130
|
+
package: '${data.pkg}',
|
|
131
|
+
path: '${path}'
|
|
96
132
|
};
|
|
97
133
|
ch.publish(payload);
|
|
98
134
|
module.exports = payload.module;
|
|
99
135
|
`
|
|
136
|
+
|
|
100
137
|
// https://esbuild.github.io/plugins/#on-load-results
|
|
101
138
|
return {
|
|
102
139
|
contents,
|
|
@@ -121,3 +158,44 @@ function warnIfUnsupported () {
|
|
|
121
158
|
console.error('more recent version is used at runtime, third party packages won\'t be instrumented.')
|
|
122
159
|
}
|
|
123
160
|
}
|
|
161
|
+
|
|
162
|
+
// @see https://github.com/nodejs/node/issues/47000
|
|
163
|
+
function dotFriendlyResolve (path, directory) {
|
|
164
|
+
if (path === '.') {
|
|
165
|
+
path = './'
|
|
166
|
+
} else if (path === '..') {
|
|
167
|
+
path = '../'
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return require.resolve(path, { paths: [ directory ] })
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* For a given full path to a module,
|
|
175
|
+
* return the package name it belongs to and the local path to the module
|
|
176
|
+
* input: '/foo/node_modules/@co/stuff/foo/bar/baz.js'
|
|
177
|
+
* output: { pkg: '@co/stuff', path: 'foo/bar/baz.js' }
|
|
178
|
+
*/
|
|
179
|
+
function extractPackageAndModulePath (fullPath) {
|
|
180
|
+
const nm = fullPath.lastIndexOf(NM)
|
|
181
|
+
if (nm < 0) {
|
|
182
|
+
return { pkg: null, path: null }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const subPath = fullPath.substring(nm + NM.length)
|
|
186
|
+
const firstSlash = subPath.indexOf('/')
|
|
187
|
+
|
|
188
|
+
if (subPath[0] === '@') {
|
|
189
|
+
const secondSlash = subPath.substring(firstSlash + 1).indexOf('/')
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
pkg: subPath.substring(0, firstSlash + 1 + secondSlash),
|
|
193
|
+
path: subPath.substring(firstSlash + 1 + secondSlash + 1)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
pkg: subPath.substring(0, firstSlash),
|
|
199
|
+
path: subPath.substring(firstSlash + 1)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -177,7 +177,6 @@ addHook({ name: '@aws-sdk/smithy-client', versions: ['>=3'] }, smithy => {
|
|
|
177
177
|
})
|
|
178
178
|
|
|
179
179
|
addHook({ name: 'aws-sdk', versions: ['>=2.3.0'] }, AWS => {
|
|
180
|
-
shimmer.wrap(AWS.Request.prototype, 'promise', wrapRequest)
|
|
181
180
|
shimmer.wrap(AWS.config, 'setPromisesDependency', setPromisesDependency => {
|
|
182
181
|
return function wrappedSetPromisesDependency (dep) {
|
|
183
182
|
const result = setPromisesDependency.apply(this, arguments)
|
|
@@ -188,9 +187,14 @@ addHook({ name: 'aws-sdk', versions: ['>=2.3.0'] }, AWS => {
|
|
|
188
187
|
return AWS
|
|
189
188
|
})
|
|
190
189
|
|
|
190
|
+
addHook({ name: 'aws-sdk', file: 'lib/core.js', versions: ['>=2.3.0'] }, AWS => {
|
|
191
|
+
shimmer.wrap(AWS.Request.prototype, 'promise', wrapRequest)
|
|
192
|
+
return AWS
|
|
193
|
+
})
|
|
194
|
+
|
|
191
195
|
// <2.1.35 has breaking changes for instrumentation
|
|
192
196
|
// https://github.com/aws/aws-sdk-js/pull/629
|
|
193
|
-
addHook({ name: 'aws-sdk', versions: ['>=2.1.35'] }, AWS => {
|
|
197
|
+
addHook({ name: 'aws-sdk', file: 'lib/core.js', versions: ['>=2.1.35'] }, AWS => {
|
|
194
198
|
shimmer.wrap(AWS.Request.prototype, 'send', wrapRequest)
|
|
195
199
|
return AWS
|
|
196
200
|
})
|
|
@@ -17,29 +17,32 @@ function wrapFetch (fetch, Request) {
|
|
|
17
17
|
const headers = req.headers
|
|
18
18
|
const message = { req, headers }
|
|
19
19
|
|
|
20
|
-
startChannel.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return res
|
|
32
|
-
},
|
|
33
|
-
err => {
|
|
34
|
-
if (err.name !== 'AbortError') {
|
|
35
|
-
errorChannel.publish(err)
|
|
36
|
-
}
|
|
20
|
+
return startChannel.runStores(message, () => {
|
|
21
|
+
// Request object is read-only so we need new objects to change headers.
|
|
22
|
+
arguments[0] = message.req
|
|
23
|
+
arguments[1] = { headers: message.headers }
|
|
24
|
+
|
|
25
|
+
return fetch.apply(this, arguments)
|
|
26
|
+
.then(
|
|
27
|
+
res => {
|
|
28
|
+
message.res = res
|
|
29
|
+
|
|
30
|
+
finishChannel.publish(message)
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
return res
|
|
33
|
+
},
|
|
34
|
+
err => {
|
|
35
|
+
if (err.name !== 'AbortError') {
|
|
36
|
+
message.error = err
|
|
37
|
+
errorChannel.publish(message)
|
|
38
|
+
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
finishChannel.publish(message)
|
|
41
|
+
|
|
42
|
+
throw err
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
})
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line n/no-restricted-require
|
|
4
|
+
const dc = require('diagnostics_channel')
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
filename,
|
|
8
|
+
loadChannel,
|
|
9
|
+
matchVersion
|
|
10
|
+
} = require('./register.js')
|
|
11
|
+
const hooks = require('./hooks')
|
|
12
|
+
const instrumentations = require('./instrumentations')
|
|
13
|
+
const log = require('../../../dd-trace/src/log')
|
|
14
|
+
|
|
15
|
+
const CHANNEL = 'dd-trace:bundler:load'
|
|
16
|
+
|
|
17
|
+
if (!dc.subscribe) {
|
|
18
|
+
dc.subscribe = (channel, cb) => {
|
|
19
|
+
dc.channel(channel).subscribe(cb)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (!dc.unsubscribe) {
|
|
23
|
+
dc.unsubscribe = (channel, cb) => {
|
|
24
|
+
if (dc.channel(channel).hasSubscribers) {
|
|
25
|
+
dc.channel(channel).unsubscribe(cb)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
dc.subscribe(CHANNEL, (payload) => {
|
|
31
|
+
try {
|
|
32
|
+
hooks[payload.package]()
|
|
33
|
+
} catch (err) {
|
|
34
|
+
log.error(`esbuild-wrapped ${payload.package} missing in list of hooks`)
|
|
35
|
+
throw err
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!instrumentations[payload.package]) {
|
|
39
|
+
log.error(`esbuild-wrapped ${payload.package} missing in list of instrumentations`)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const { name, file, versions, hook } of instrumentations[payload.package]) {
|
|
44
|
+
if (payload.path !== filename(name, file)) continue
|
|
45
|
+
if (!matchVersion(payload.version, versions)) continue
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
loadChannel.publish({ name, version: payload.version, file })
|
|
49
|
+
payload.module = hook(payload.module, payload.version)
|
|
50
|
+
} catch (e) {
|
|
51
|
+
log.error(e)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const iitm = require('../../../dd-trace/src/iitm')
|
|
5
5
|
const ritm = require('../../../dd-trace/src/ritm')
|
|
6
|
-
const dcitm = require('../../../dd-trace/src/dcitm')
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
* This is called for every module that dd-trace supports instrumentation for
|
|
8
|
+
* This is called for every package/internal-module that dd-trace supports instrumentation for
|
|
10
9
|
* In practice, `modules` is always an array with a single entry.
|
|
11
10
|
*
|
|
12
11
|
* @param {string[]} modules list of modules to hook into
|
|
@@ -41,13 +40,11 @@ function Hook (modules, onrequire) {
|
|
|
41
40
|
return safeHook(moduleExports, moduleName, moduleBaseDir)
|
|
42
41
|
}
|
|
43
42
|
})
|
|
44
|
-
this._dcitmHook = dcitm(modules, {}, safeHook)
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
Hook.prototype.unhook = function () {
|
|
48
46
|
this._ritmHook.unhook()
|
|
49
47
|
this._iitmHook.unhook()
|
|
50
|
-
this._dcitmHook.unhook()
|
|
51
48
|
this._patched = Object.create(null)
|
|
52
49
|
}
|
|
53
50
|
|
|
@@ -11,6 +11,8 @@ module.exports = {
|
|
|
11
11
|
'@hapi/hapi': () => require('../hapi'),
|
|
12
12
|
'@jest/core': () => require('../jest'),
|
|
13
13
|
'@jest/reporters': () => require('../jest'),
|
|
14
|
+
'@jest/test-sequencer': () => require('../jest'),
|
|
15
|
+
'@jest/transform': () => require('../jest'),
|
|
14
16
|
'@koa/router': () => require('../koa'),
|
|
15
17
|
'@node-redis/client': () => require('../redis'),
|
|
16
18
|
'@opensearch-project/opensearch': () => require('../opensearch'),
|
|
@@ -38,6 +40,7 @@ module.exports = {
|
|
|
38
40
|
'find-my-way': () => require('../find-my-way'),
|
|
39
41
|
'fs': () => require('../fs'),
|
|
40
42
|
'node:fs': () => require('../fs'),
|
|
43
|
+
'generic-pool': () => require('../generic-pool'),
|
|
41
44
|
'graphql': () => require('../graphql'),
|
|
42
45
|
'grpc': () => require('../grpc'),
|
|
43
46
|
'hapi': () => require('../hapi'),
|
|
@@ -51,6 +54,7 @@ module.exports = {
|
|
|
51
54
|
'jest-environment-jsdom': () => require('../jest'),
|
|
52
55
|
'jest-jasmine2': () => require('../jest'),
|
|
53
56
|
'jest-worker': () => require('../jest'),
|
|
57
|
+
'knex': () => require('../knex'),
|
|
54
58
|
'koa': () => require('../koa'),
|
|
55
59
|
'koa-router': () => require('../koa'),
|
|
56
60
|
'kafkajs': () => require('../kafkajs'),
|
|
@@ -20,7 +20,9 @@ const disabledInstrumentations = new Set(
|
|
|
20
20
|
const loadChannel = channel('dd-trace:instrumentation:load')
|
|
21
21
|
|
|
22
22
|
// Globals
|
|
23
|
-
|
|
23
|
+
if (!disabledInstrumentations.has('fetch')) {
|
|
24
|
+
require('../fetch')
|
|
25
|
+
}
|
|
24
26
|
|
|
25
27
|
// TODO: make this more efficient
|
|
26
28
|
|
|
@@ -30,6 +32,7 @@ for (const packageName of names) {
|
|
|
30
32
|
Hook([packageName], (moduleExports, moduleName, moduleBaseDir, moduleVersion) => {
|
|
31
33
|
moduleName = moduleName.replace(pathSepExpr, '/')
|
|
32
34
|
|
|
35
|
+
// This executes the integration file thus adding its entries to `instrumentations`
|
|
33
36
|
hooks[packageName]()
|
|
34
37
|
|
|
35
38
|
if (!instrumentations[packageName]) {
|
|
@@ -74,5 +77,7 @@ function filename (name, file) {
|
|
|
74
77
|
|
|
75
78
|
module.exports = {
|
|
76
79
|
filename,
|
|
77
|
-
pathSepExpr
|
|
80
|
+
pathSepExpr,
|
|
81
|
+
loadChannel,
|
|
82
|
+
matchVersion
|
|
78
83
|
}
|
|
@@ -3,18 +3,16 @@
|
|
|
3
3
|
/* eslint-disable no-fallthrough */
|
|
4
4
|
|
|
5
5
|
const url = require('url')
|
|
6
|
-
const {
|
|
7
|
-
channel,
|
|
8
|
-
addHook,
|
|
9
|
-
AsyncResource
|
|
10
|
-
} = require('../helpers/instrument')
|
|
6
|
+
const { channel, addHook } = require('../helpers/instrument')
|
|
11
7
|
const shimmer = require('../../../datadog-shimmer')
|
|
12
8
|
|
|
13
9
|
const log = require('../../../dd-trace/src/log')
|
|
14
10
|
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
11
|
+
const startChannel = channel('apm:http:client:request:start')
|
|
12
|
+
const finishChannel = channel('apm:http:client:request:finish')
|
|
13
|
+
const endChannel = channel('apm:http:client:request:end')
|
|
14
|
+
const asyncStartChannel = channel('apm:http:client:request:asyncStart')
|
|
15
|
+
const errorChannel = channel('apm:http:client:request:error')
|
|
18
16
|
|
|
19
17
|
addHook({ name: 'https' }, hookFn)
|
|
20
18
|
|
|
@@ -32,7 +30,7 @@ function patch (http, methodName) {
|
|
|
32
30
|
|
|
33
31
|
function instrumentRequest (request) {
|
|
34
32
|
return function () {
|
|
35
|
-
if (!
|
|
33
|
+
if (!startChannel.hasSubscribers) {
|
|
36
34
|
return request.apply(this, arguments)
|
|
37
35
|
}
|
|
38
36
|
|
|
@@ -45,57 +43,68 @@ function patch (http, methodName) {
|
|
|
45
43
|
return request.apply(this, arguments)
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
const
|
|
49
|
-
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
50
|
-
|
|
51
|
-
return asyncResource.runInAsyncScope(() => {
|
|
52
|
-
startClientCh.publish({ args, http })
|
|
46
|
+
const ctx = { args, http }
|
|
53
47
|
|
|
48
|
+
return startChannel.runStores(ctx, () => {
|
|
54
49
|
let finished = false
|
|
55
50
|
let callback = args.callback
|
|
56
51
|
|
|
57
52
|
if (callback) {
|
|
58
|
-
callback =
|
|
53
|
+
callback = function () {
|
|
54
|
+
return asyncStartChannel.runStores(ctx, () => {
|
|
55
|
+
return args.callback.apply(this, arguments)
|
|
56
|
+
})
|
|
57
|
+
}
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
const options = args.options
|
|
62
|
-
const
|
|
63
|
-
const emit = req.emit
|
|
64
|
-
|
|
65
|
-
const finish = (req, res) => {
|
|
61
|
+
const finish = () => {
|
|
66
62
|
if (!finished) {
|
|
67
63
|
finished = true
|
|
68
|
-
|
|
64
|
+
finishChannel.publish(ctx)
|
|
69
65
|
}
|
|
70
66
|
}
|
|
71
67
|
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
try {
|
|
69
|
+
const req = request.call(this, options, callback)
|
|
70
|
+
const emit = req.emit
|
|
71
|
+
|
|
72
|
+
ctx.req = req
|
|
73
|
+
|
|
74
|
+
req.emit = function (eventName, arg) {
|
|
74
75
|
switch (eventName) {
|
|
75
76
|
case 'response': {
|
|
76
77
|
const res = arg
|
|
77
|
-
|
|
78
|
-
res.on('end',
|
|
79
|
-
res.on('error',
|
|
78
|
+
ctx.res = res
|
|
79
|
+
res.on('end', finish)
|
|
80
|
+
res.on('error', finish)
|
|
80
81
|
break
|
|
81
82
|
}
|
|
82
83
|
case 'connect':
|
|
83
84
|
case 'upgrade':
|
|
84
|
-
|
|
85
|
+
ctx.res = arg
|
|
86
|
+
finish()
|
|
85
87
|
break
|
|
86
88
|
case 'error':
|
|
87
89
|
case 'timeout':
|
|
88
|
-
|
|
90
|
+
ctx.error = arg
|
|
91
|
+
errorChannel.publish(ctx)
|
|
89
92
|
case 'abort': // deprecated and replaced by `close` in node 17
|
|
90
93
|
case 'close':
|
|
91
|
-
finish(
|
|
94
|
+
finish()
|
|
92
95
|
}
|
|
93
|
-
})
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
return emit.apply(this, arguments)
|
|
98
|
+
}
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
return req
|
|
101
|
+
} catch (e) {
|
|
102
|
+
ctx.error = e
|
|
103
|
+
errorChannel.publish(ctx)
|
|
104
|
+
throw e
|
|
105
|
+
} finally {
|
|
106
|
+
endChannel.publish(ctx)
|
|
107
|
+
}
|
|
99
108
|
})
|
|
100
109
|
}
|
|
101
110
|
}
|
|
@@ -188,6 +188,31 @@ addHook({
|
|
|
188
188
|
versions: ['>=24.8.0']
|
|
189
189
|
}, getTestEnvironment)
|
|
190
190
|
|
|
191
|
+
addHook({
|
|
192
|
+
name: '@jest/test-sequencer',
|
|
193
|
+
versions: ['>=24.8.0']
|
|
194
|
+
}, sequencerPackage => {
|
|
195
|
+
shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
|
|
196
|
+
const shardedTests = shard.apply(this, arguments)
|
|
197
|
+
|
|
198
|
+
if (!shardedTests.length) {
|
|
199
|
+
return shardedTests
|
|
200
|
+
}
|
|
201
|
+
// TODO: could we get the rootDir from each test?
|
|
202
|
+
const [test] = shardedTests
|
|
203
|
+
const rootDir = test && test.context && test.context.config && test.context.config.rootDir
|
|
204
|
+
|
|
205
|
+
const filteredTests = getJestSuitesToRun(skippableSuites, shardedTests, rootDir || process.cwd())
|
|
206
|
+
|
|
207
|
+
isSuitesSkipped = filteredTests.length !== shardedTests.length
|
|
208
|
+
|
|
209
|
+
skippableSuites = []
|
|
210
|
+
|
|
211
|
+
return filteredTests
|
|
212
|
+
})
|
|
213
|
+
return sequencerPackage
|
|
214
|
+
})
|
|
215
|
+
|
|
191
216
|
function cliWrapper (cli, jestVersion) {
|
|
192
217
|
const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
|
|
193
218
|
let onDone
|
|
@@ -410,6 +435,32 @@ function jestConfigSyncWrapper (jestConfig) {
|
|
|
410
435
|
return jestConfig
|
|
411
436
|
}
|
|
412
437
|
|
|
438
|
+
addHook({
|
|
439
|
+
name: '@jest/transform',
|
|
440
|
+
versions: ['>=24.8.0'],
|
|
441
|
+
file: 'build/ScriptTransformer.js'
|
|
442
|
+
}, transformPackage => {
|
|
443
|
+
const originalCreateScriptTransformer = transformPackage.createScriptTransformer
|
|
444
|
+
|
|
445
|
+
transformPackage.createScriptTransformer = async function (config) {
|
|
446
|
+
const { testEnvironmentOptions, ...restOfConfig } = config
|
|
447
|
+
const {
|
|
448
|
+
_ddTestModuleId,
|
|
449
|
+
_ddTestSessionId,
|
|
450
|
+
_ddTestCommand,
|
|
451
|
+
...restOfTestEnvironmentOptions
|
|
452
|
+
} = testEnvironmentOptions
|
|
453
|
+
|
|
454
|
+
restOfConfig.testEnvironmentOptions = restOfTestEnvironmentOptions
|
|
455
|
+
|
|
456
|
+
arguments[0] = restOfConfig
|
|
457
|
+
|
|
458
|
+
return originalCreateScriptTransformer.apply(this, arguments)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return transformPackage
|
|
462
|
+
})
|
|
463
|
+
|
|
413
464
|
/**
|
|
414
465
|
* Hook to remove the test paths (test suite) that are part of `skippableSuites`
|
|
415
466
|
*/
|
|
@@ -425,7 +476,18 @@ addHook({
|
|
|
425
476
|
return getTestPaths.apply(this, arguments)
|
|
426
477
|
}
|
|
427
478
|
|
|
428
|
-
const [{ rootDir }] = arguments
|
|
479
|
+
const [{ rootDir, shard }] = arguments
|
|
480
|
+
|
|
481
|
+
if (shard && shard.shardIndex) {
|
|
482
|
+
// If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
|
|
483
|
+
// The reason for this is the following:
|
|
484
|
+
// The tests for different shards are likely being run in different CI jobs so
|
|
485
|
+
// the requests to the skippable endpoint might be done at different times and their responses might be different.
|
|
486
|
+
// If the skippable endpoint is returning different suites and we filter the list of tests here,
|
|
487
|
+
// the base list of tests that is used for sharding might be different,
|
|
488
|
+
// causing the shards to potentially run the same suite.
|
|
489
|
+
return getTestPaths.apply(this, arguments)
|
|
490
|
+
}
|
|
429
491
|
|
|
430
492
|
const testPaths = await getTestPaths.apply(this, arguments)
|
|
431
493
|
const { tests } = testPaths
|
|
@@ -1,35 +1,30 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const HttpClientPlugin = require('../../datadog-plugin-http/src/client')
|
|
4
|
-
const { HTTP_HEADERS } = require('../../../ext/formats')
|
|
5
4
|
|
|
6
5
|
class FetchPlugin extends HttpClientPlugin {
|
|
7
6
|
static get id () { return 'fetch' }
|
|
7
|
+
static get prefix () { return `apm:fetch:request` }
|
|
8
8
|
|
|
9
9
|
addTraceSub (eventName, handler) {
|
|
10
10
|
this.addSub(`apm:${this.constructor.id}:${this.operation}:${eventName}`, handler)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
bindStart (message) {
|
|
14
14
|
const req = message.req
|
|
15
15
|
const options = new URL(req.url)
|
|
16
16
|
const headers = options.headers = Object.fromEntries(req.headers.entries())
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
options.method = req.method
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
message.args = { options }
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
}
|
|
22
|
+
const store = super.bindStart(message)
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.tracer.inject(span, HTTP_HEADERS, carrier)
|
|
24
|
+
message.headers = headers
|
|
25
|
+
message.req = new globalThis.Request(req, { headers })
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
headers.append(name, carrier[name])
|
|
32
|
-
}
|
|
27
|
+
return store
|
|
33
28
|
}
|
|
34
29
|
}
|
|
35
30
|
|
|
@@ -16,15 +16,11 @@ const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS
|
|
|
16
16
|
const HTTP_RESPONSE_HEADERS = tags.HTTP_RESPONSE_HEADERS
|
|
17
17
|
|
|
18
18
|
class HttpClientPlugin extends ClientPlugin {
|
|
19
|
-
static get id () {
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
addTraceSub (eventName, handler) {
|
|
24
|
-
this.addSub(`apm:${this.constructor.id}:client:${this.operation}:${eventName}`, handler)
|
|
25
|
-
}
|
|
19
|
+
static get id () { return 'http' }
|
|
20
|
+
static get prefix () { return `apm:http:client:request` }
|
|
26
21
|
|
|
27
|
-
|
|
22
|
+
bindStart (message) {
|
|
23
|
+
const { args, http = {} } = message
|
|
28
24
|
const store = storage.getStore()
|
|
29
25
|
const options = args.options
|
|
30
26
|
const agent = options.agent || options._defaultAgent || http.globalAgent || {}
|
|
@@ -55,7 +51,7 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
55
51
|
metrics: {
|
|
56
52
|
[CLIENT_PORT_KEY]: parseInt(options.port)
|
|
57
53
|
}
|
|
58
|
-
})
|
|
54
|
+
}, false)
|
|
59
55
|
|
|
60
56
|
// TODO: Figure out a better way to do this for any span.
|
|
61
57
|
if (!allowed) {
|
|
@@ -67,11 +63,19 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
analyticsSampler.sample(span, this.config.measured)
|
|
70
|
-
|
|
66
|
+
|
|
67
|
+
message.span = span
|
|
68
|
+
message.parentStore = store
|
|
69
|
+
message.currentStore = { ...store, span }
|
|
70
|
+
|
|
71
|
+
return message.currentStore
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
bindAsyncStart ({ parentStore }) {
|
|
75
|
+
return parentStore
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
finish ({ req, res, span }) {
|
|
75
79
|
if (res) {
|
|
76
80
|
const status = res.status || res.statusCode
|
|
77
81
|
|
|
@@ -87,17 +91,18 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
87
91
|
addRequestHeaders(req, span, this.config)
|
|
88
92
|
|
|
89
93
|
this.config.hooks.request(span, req, res)
|
|
90
|
-
super.finish()
|
|
91
|
-
}
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
this.tagPeerService(span)
|
|
96
|
+
|
|
97
|
+
span.finish()
|
|
98
|
+
}
|
|
95
99
|
|
|
96
|
-
|
|
100
|
+
error ({ span, error }) {
|
|
101
|
+
if (error) {
|
|
97
102
|
span.addTags({
|
|
98
|
-
[ERROR_TYPE]:
|
|
99
|
-
[ERROR_MESSAGE]:
|
|
100
|
-
[ERROR_STACK]:
|
|
103
|
+
[ERROR_TYPE]: error.name,
|
|
104
|
+
[ERROR_MESSAGE]: error.message || error.code,
|
|
105
|
+
[ERROR_STACK]: error.stack
|
|
101
106
|
})
|
|
102
107
|
} else {
|
|
103
108
|
span.setTag('error', 1)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
|
|
5
|
+
const { getNodeModulesPaths } = require('../path-line')
|
|
5
6
|
const Analyzer = require('./vulnerability-analyzer')
|
|
6
7
|
const { WEAK_HASH } = require('../vulnerabilities')
|
|
7
8
|
|
|
@@ -11,13 +12,16 @@ const INSECURE_HASH_ALGORITHMS = new Set([
|
|
|
11
12
|
'RSA-SHA1', 'RSA-SHA1-2', 'sha1', 'md5-sha1', 'sha1WithRSAEncryption', 'ssl3-sha1'
|
|
12
13
|
].map(algorithm => algorithm.toLowerCase()))
|
|
13
14
|
|
|
14
|
-
const EXCLUDED_LOCATIONS =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const EXCLUDED_LOCATIONS = getNodeModulesPaths(
|
|
16
|
+
'etag/index.js',
|
|
17
|
+
'@mikro-orm/core/utils/Utils.js',
|
|
18
|
+
'mongodb/lib/core/connection/connection.js',
|
|
19
|
+
'mysql2/lib/auth_41.js',
|
|
20
|
+
'pusher/lib/utils.js',
|
|
21
|
+
'redlock/dist/cjs',
|
|
22
|
+
'sqreen/lib/package-reader/index.js',
|
|
23
|
+
'ws/lib/websocket-server.js'
|
|
24
|
+
)
|
|
21
25
|
|
|
22
26
|
const EXCLUDED_PATHS_FROM_STACK = [
|
|
23
27
|
path.join('node_modules', 'object-hash', path.sep)
|
|
@@ -11,6 +11,7 @@ const tagger = require('./tagger')
|
|
|
11
11
|
const { isTrue, isFalse } = require('./util')
|
|
12
12
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
|
|
13
13
|
const { getGitMetadataFromGitProperties } = require('./git_properties')
|
|
14
|
+
const { getIsGCPFunction, getIsAzureFunctionConsumptionPlan } = require('./serverless')
|
|
14
15
|
|
|
15
16
|
const fromEntries = Object.fromEntries || (entries =>
|
|
16
17
|
entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
|
|
@@ -186,6 +187,7 @@ class Config {
|
|
|
186
187
|
process.env.AWS_LAMBDA_FUNCTION_NAME ||
|
|
187
188
|
process.env.FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
|
|
188
189
|
process.env.K_SERVICE || // Google Cloud Function Name set by newer runtimes
|
|
190
|
+
process.env.WEBSITE_SITE_NAME || // set by Azure Functions
|
|
189
191
|
pkg.name ||
|
|
190
192
|
'node'
|
|
191
193
|
const DD_SERVICE_MAPPING = coalesce(
|
|
@@ -224,11 +226,10 @@ class Config {
|
|
|
224
226
|
|
|
225
227
|
const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
|
|
226
228
|
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const isGCPFunction = isDeprecatedGCPFunction || isNewerGCPFunction
|
|
229
|
+
const isGCPFunction = getIsGCPFunction()
|
|
230
|
+
const isAzureFunctionConsumptionPlan = getIsAzureFunctionConsumptionPlan()
|
|
230
231
|
|
|
231
|
-
const inServerlessEnvironment = inAWSLambda || isGCPFunction
|
|
232
|
+
const inServerlessEnvironment = inAWSLambda || isGCPFunction || isAzureFunctionConsumptionPlan
|
|
232
233
|
|
|
233
234
|
const DD_TRACE_TELEMETRY_ENABLED = coalesce(
|
|
234
235
|
process.env.DD_TRACE_TELEMETRY_ENABLED,
|
|
@@ -359,7 +360,7 @@ class Config {
|
|
|
359
360
|
const DD_TRACE_STATS_COMPUTATION_ENABLED = coalesce(
|
|
360
361
|
options.stats,
|
|
361
362
|
process.env.DD_TRACE_STATS_COMPUTATION_ENABLED,
|
|
362
|
-
isGCPFunction
|
|
363
|
+
isGCPFunction || isAzureFunctionConsumptionPlan
|
|
363
364
|
)
|
|
364
365
|
|
|
365
366
|
const DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED = coalesce(
|
|
@@ -675,6 +676,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
675
676
|
this.traceId128BitLoggingEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
|
|
676
677
|
|
|
677
678
|
this.isGCPFunction = isGCPFunction
|
|
679
|
+
this.isAzureFunctionConsumptionPlan = isAzureFunctionConsumptionPlan
|
|
678
680
|
|
|
679
681
|
tagger.add(this.tags, {
|
|
680
682
|
service: this.service,
|
|
@@ -135,7 +135,8 @@ module.exports = class PluginManager {
|
|
|
135
135
|
site,
|
|
136
136
|
url,
|
|
137
137
|
dbmPropagationMode,
|
|
138
|
-
dsmEnabled
|
|
138
|
+
dsmEnabled,
|
|
139
|
+
clientIpEnabled
|
|
139
140
|
} = this._tracerConfig
|
|
140
141
|
|
|
141
142
|
const sharedConfig = {}
|
|
@@ -155,6 +156,10 @@ module.exports = class PluginManager {
|
|
|
155
156
|
sharedConfig.service = serviceMapping[name]
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
if (clientIpEnabled !== undefined) {
|
|
160
|
+
sharedConfig.clientIpEnabled = clientIpEnabled
|
|
161
|
+
}
|
|
162
|
+
|
|
158
163
|
sharedConfig.site = site
|
|
159
164
|
sharedConfig.url = url
|
|
160
165
|
|
|
@@ -10,6 +10,8 @@ module.exports = {
|
|
|
10
10
|
get '@grpc/grpc-js' () { return require('../../../datadog-plugin-grpc/src') },
|
|
11
11
|
get '@hapi/hapi' () { return require('../../../datadog-plugin-hapi/src') },
|
|
12
12
|
get '@jest/core' () { return require('../../../datadog-plugin-jest/src') },
|
|
13
|
+
get '@jest/test-sequencer' () { return require('../../../datadog-plugin-jest/src') },
|
|
14
|
+
get '@jest/transform' () { return require('../../../datadog-plugin-jest/src') },
|
|
13
15
|
get '@koa/router' () { return require('../../../datadog-plugin-koa/src') },
|
|
14
16
|
get '@node-redis/client' () { return require('../../../datadog-plugin-redis/src') },
|
|
15
17
|
get '@opensearch-project/opensearch' () { return require('../../../datadog-plugin-opensearch/src') },
|
|
@@ -30,8 +30,8 @@ class Tracer extends NoopProxy {
|
|
|
30
30
|
remoteConfig.enable(config)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
if (config.isGCPFunction) {
|
|
34
|
-
require('./serverless').maybeStartServerlessMiniAgent()
|
|
33
|
+
if (config.isGCPFunction || config.isAzureFunctionConsumptionPlan) {
|
|
34
|
+
require('./serverless').maybeStartServerlessMiniAgent(config)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
if (config.profiling.enabled) {
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (process.
|
|
7
|
-
|
|
3
|
+
const log = require('./log')
|
|
4
|
+
|
|
5
|
+
function maybeStartServerlessMiniAgent (config) {
|
|
6
|
+
if (process.platform !== 'win32' && process.platform !== 'linux') {
|
|
7
|
+
log.error(`Serverless Mini Agent is only supported on Windows and Linux.`)
|
|
8
|
+
return
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
const rustBinaryPath = getRustBinaryPath(config)
|
|
12
|
+
|
|
10
13
|
const fs = require('fs')
|
|
11
14
|
|
|
15
|
+
log.debug(`Trying to spawn the Serverless Mini Agent at path: ${rustBinaryPath}`)
|
|
16
|
+
|
|
12
17
|
// trying to spawn with an invalid path will return a non-descriptive error, so we want to catch
|
|
13
18
|
// invalid paths and log our own error.
|
|
14
19
|
if (!fs.existsSync(rustBinaryPath)) {
|
|
@@ -22,4 +27,43 @@ function maybeStartServerlessMiniAgent () {
|
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
function getRustBinaryPath (config) {
|
|
31
|
+
if (process.env.DD_MINI_AGENT_PATH !== undefined) {
|
|
32
|
+
return process.env.DD_MINI_AGENT_PATH
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const rustBinaryPathRoot = config.isGCPFunction ? '/workspace' : '/home/site/wwwroot'
|
|
36
|
+
const rustBinaryPathOsFolder = process.platform === 'win32'
|
|
37
|
+
? 'datadog-serverless-agent-windows-amd64' : 'datadog-serverless-agent-linux-amd64'
|
|
38
|
+
|
|
39
|
+
const rustBinaryExtension = process.platform === 'win32' ? '.exe' : ''
|
|
40
|
+
|
|
41
|
+
const rustBinaryPath =
|
|
42
|
+
`${rustBinaryPathRoot}/node_modules/@datadog/sma/${rustBinaryPathOsFolder}/\
|
|
43
|
+
datadog-serverless-trace-mini-agent${rustBinaryExtension}`
|
|
44
|
+
|
|
45
|
+
return rustBinaryPath
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getIsGCPFunction () {
|
|
49
|
+
const isDeprecatedGCPFunction = process.env.FUNCTION_NAME !== undefined && process.env.GCP_PROJECT !== undefined
|
|
50
|
+
const isNewerGCPFunction = process.env.K_SERVICE !== undefined && process.env.FUNCTION_TARGET !== undefined
|
|
51
|
+
|
|
52
|
+
return isDeprecatedGCPFunction || isNewerGCPFunction
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getIsAzureFunctionConsumptionPlan () {
|
|
56
|
+
const isAzureFunction =
|
|
57
|
+
process.env.FUNCTIONS_EXTENSION_VERSION !== undefined && process.env.FUNCTIONS_WORKER_RUNTIME !== undefined
|
|
58
|
+
const azureWebsiteSKU = process.env.WEBSITE_SKU
|
|
59
|
+
const isConsumptionPlan = azureWebsiteSKU === undefined || azureWebsiteSKU === 'Dynamic'
|
|
60
|
+
|
|
61
|
+
return isAzureFunction && isConsumptionPlan
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
maybeStartServerlessMiniAgent,
|
|
66
|
+
getIsGCPFunction,
|
|
67
|
+
getIsAzureFunctionConsumptionPlan,
|
|
68
|
+
getRustBinaryPath
|
|
69
|
+
}
|
|
@@ -64,7 +64,7 @@ if (!Channel.prototype.runStores) {
|
|
|
64
64
|
this._stores.set(store, transform)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
Channel.prototype.unbindStore = ActiveChannelPrototype.
|
|
67
|
+
Channel.prototype.unbindStore = ActiveChannelPrototype.unbindStore = function (store) {
|
|
68
68
|
if (!this._stores) return
|
|
69
69
|
this._stores.delete(store)
|
|
70
70
|
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
// TODO: Figure out why we can't use the internal version.
|
|
4
|
-
// eslint-disable-next-line n/no-restricted-require
|
|
5
|
-
const dc = require('diagnostics_channel')
|
|
6
|
-
|
|
7
|
-
const CHANNEL_PREFIX = 'dd-trace:bundledModuleLoadStart'
|
|
8
|
-
|
|
9
|
-
if (!dc.subscribe) {
|
|
10
|
-
dc.subscribe = (channel, cb) => {
|
|
11
|
-
dc.channel(channel).subscribe(cb)
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
if (!dc.unsubscribe) {
|
|
15
|
-
dc.unsubscribe = (channel, cb) => {
|
|
16
|
-
if (dc.channel(channel).hasSubscribers) {
|
|
17
|
-
dc.channel(channel).unsubscribe(cb)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
module.exports = DcitmHook
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* This allows for listening to diagnostic channel events when a module is loaded.
|
|
26
|
-
* Currently it's intended use is for situations like when code runs through a bundler.
|
|
27
|
-
*
|
|
28
|
-
* Unlike RITM and IITM, which have files available on a filesystem at runtime, DCITM
|
|
29
|
-
* requires access to a package's version ahead of time as the package.json file likely
|
|
30
|
-
* won't be available.
|
|
31
|
-
*
|
|
32
|
-
* This function runs many times at startup, once for every module that dd-trace may trace.
|
|
33
|
-
* As it runs on a per-module basis we're creating per-module channels.
|
|
34
|
-
*/
|
|
35
|
-
function DcitmHook (moduleNames, options, onrequire) {
|
|
36
|
-
if (!(this instanceof DcitmHook)) return new DcitmHook(moduleNames, options, onrequire)
|
|
37
|
-
|
|
38
|
-
function onModuleLoad (payload) {
|
|
39
|
-
payload.module = onrequire(payload.module, payload.path, undefined, payload.version)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
for (const moduleName of moduleNames) {
|
|
43
|
-
// dc.channel(`${CHANNEL_PREFIX}:${moduleName}`).subscribe(onModuleLoad)
|
|
44
|
-
dc.subscribe(`${CHANNEL_PREFIX}:${moduleName}`, onModuleLoad)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
this.unhook = function dcitmUnload () {
|
|
48
|
-
for (const moduleName of moduleNames) {
|
|
49
|
-
// dc.channel(`${CHANNEL_PREFIX}:${moduleName}`).unsubscribe(onModuleLoad)
|
|
50
|
-
dc.unsubscribe(`${CHANNEL_PREFIX}:${moduleName}`, onModuleLoad)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|