dd-trace 3.12.1 → 3.13.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/ci/init.js +1 -0
- package/index.d.ts +50 -0
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/fs.js +357 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/jest.js +11 -1
- package/packages/datadog-instrumentations/src/mocha.js +3 -2
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/playwright.js +236 -0
- package/packages/datadog-plugin-fs/src/index.js +45 -0
- package/packages/datadog-plugin-jest/src/index.js +45 -23
- package/packages/datadog-plugin-mocha/src/index.js +34 -6
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +171 -0
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
- package/packages/dd-trace/src/appsec/index.js +1 -1
- package/packages/dd-trace/src/appsec/recommended.json +247 -112
- package/packages/dd-trace/src/appsec/sdk/index.js +23 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +11 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
- package/packages/dd-trace/src/config.js +7 -0
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
- package/packages/dd-trace/src/log/channels.js +47 -0
- package/packages/dd-trace/src/log/index.js +79 -0
- package/packages/dd-trace/src/log/writer.js +108 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +27 -10
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
- package/packages/dd-trace/src/plugins/util/web.js +11 -0
- package/packages/dd-trace/src/proxy.js +2 -0
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
package/ci/init.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -115,6 +115,8 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
115
115
|
* @returns {Tracer} The Tracer instance for chaining.
|
|
116
116
|
*/
|
|
117
117
|
setUser (user: User): Tracer;
|
|
118
|
+
|
|
119
|
+
appsec: Appsec;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
export declare interface TraceOptions extends Analyzable {
|
|
@@ -537,6 +539,17 @@ export declare interface TracerOptions {
|
|
|
537
539
|
*/
|
|
538
540
|
pollInterval?: number,
|
|
539
541
|
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Whether to enable client IP collection from relevant IP headers
|
|
545
|
+
* @default false
|
|
546
|
+
*/
|
|
547
|
+
clientIpEnabled?: boolean
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Custom header name to source the http.client_ip tag from.
|
|
551
|
+
*/
|
|
552
|
+
clientIpHeader?: string,
|
|
540
553
|
}
|
|
541
554
|
|
|
542
555
|
/**
|
|
@@ -582,6 +595,36 @@ export declare interface User {
|
|
|
582
595
|
[key: string]: string | undefined
|
|
583
596
|
}
|
|
584
597
|
|
|
598
|
+
export declare interface Appsec {
|
|
599
|
+
/**
|
|
600
|
+
* Links a successful login event to the current trace. Will link the passed user to the current trace with Appsec.setUser() internally.
|
|
601
|
+
* @param {User} user Properties of the authenticated user. Accepts custom fields.
|
|
602
|
+
* @param {[key: string]: string} metadata Custom fields to link to the login success event.
|
|
603
|
+
*
|
|
604
|
+
* @beta This method is in beta and could change in future versions.
|
|
605
|
+
*/
|
|
606
|
+
trackUserLoginSuccessEvent(user: User, metadata?: { [key: string]: string }): void
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Links a failed login event to the current trace.
|
|
610
|
+
* @param {string} userId The user id of the attemped login.
|
|
611
|
+
* @param {boolean} exists If the user id exists.
|
|
612
|
+
* @param {[key: string]: string} metadata Custom fields to link to the login failure event.
|
|
613
|
+
*
|
|
614
|
+
* @beta This method is in beta and could change in future versions.
|
|
615
|
+
*/
|
|
616
|
+
trackUserLoginFailureEvent(userId: string, exists: boolean, metadata?: { [key: string]: string }): void
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Links a custom event to the current trace.
|
|
620
|
+
* @param {string} eventName The name of the event.
|
|
621
|
+
* @param {[key: string]: string} metadata Custom fields to link to the event.
|
|
622
|
+
*
|
|
623
|
+
* @beta This method is in beta and could change in future versions.
|
|
624
|
+
*/
|
|
625
|
+
trackCustomEvent(eventName: string, metadata?: { [key: string]: string }): void
|
|
626
|
+
}
|
|
627
|
+
|
|
585
628
|
/** @hidden */
|
|
586
629
|
declare type anyObject = {
|
|
587
630
|
[key: string]: any;
|
|
@@ -669,6 +712,7 @@ interface Plugins {
|
|
|
669
712
|
"opensearch": plugins.opensearch;
|
|
670
713
|
"oracledb": plugins.oracledb;
|
|
671
714
|
"paperplane": plugins.paperplane;
|
|
715
|
+
"playwright": plugins.playwright;
|
|
672
716
|
"pg": plugins.pg;
|
|
673
717
|
"pino": plugins.pino;
|
|
674
718
|
"redis": plugins.redis;
|
|
@@ -1358,6 +1402,12 @@ declare namespace plugins {
|
|
|
1358
1402
|
*/
|
|
1359
1403
|
interface paperplane extends HttpServer {}
|
|
1360
1404
|
|
|
1405
|
+
/**
|
|
1406
|
+
* This plugin automatically instruments the
|
|
1407
|
+
* [playwright](https://github.com/microsoft/playwright) module.
|
|
1408
|
+
*/
|
|
1409
|
+
interface playwright extends Integration {}
|
|
1410
|
+
|
|
1361
1411
|
/**
|
|
1362
1412
|
* This plugin automatically instruments the
|
|
1363
1413
|
* [pg](https://node-postgres.com/) module.
|
package/package.json
CHANGED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
channel,
|
|
6
|
+
addHook,
|
|
7
|
+
AsyncResource
|
|
8
|
+
} = require('./helpers/instrument')
|
|
9
|
+
const shimmer = require('../../datadog-shimmer')
|
|
10
|
+
|
|
11
|
+
const startChannel = channel('apm:fs:operation:start')
|
|
12
|
+
const finishChannel = channel('apm:fs:operation:finish')
|
|
13
|
+
const errorChannel = channel('apm:fs:operation:error')
|
|
14
|
+
const ddFhSym = Symbol('ddFileHandle')
|
|
15
|
+
let kHandle, kDirReadPromisified, kDirClosePromisified
|
|
16
|
+
|
|
17
|
+
const paramsByMethod = {
|
|
18
|
+
access: ['path', 'mode'],
|
|
19
|
+
appendFile: ['path', 'data', 'options'],
|
|
20
|
+
chmod: ['path', 'mode'],
|
|
21
|
+
chown: ['path', 'uid', 'gid'],
|
|
22
|
+
close: ['fd'],
|
|
23
|
+
copyFile: ['src', 'dest', 'mode'],
|
|
24
|
+
cp: ['src', 'dest', 'options'],
|
|
25
|
+
exists: ['path'],
|
|
26
|
+
fchmod: ['fd', 'mode'],
|
|
27
|
+
fchown: ['fd', 'uid', 'gid'],
|
|
28
|
+
fdatasync: ['fd'],
|
|
29
|
+
fstat: ['fd', 'options'],
|
|
30
|
+
fsync: ['fd'],
|
|
31
|
+
ftruncate: ['fd', 'len'],
|
|
32
|
+
futimes: ['fd', 'atime', 'mtime'],
|
|
33
|
+
lchmod: ['path', 'mode'],
|
|
34
|
+
lchown: ['path', 'uid', 'gid'],
|
|
35
|
+
link: ['existingPath', 'newPath'],
|
|
36
|
+
lstat: ['path', 'options'],
|
|
37
|
+
lutimes: ['path', 'atime', 'mtime'],
|
|
38
|
+
mkdir: ['path', 'options'],
|
|
39
|
+
mkdtemp: ['prefix', 'options'],
|
|
40
|
+
open: ['path', 'flag', 'mode'],
|
|
41
|
+
opendir: ['path', 'options'],
|
|
42
|
+
read: ['fd'],
|
|
43
|
+
readdir: ['path', 'options'],
|
|
44
|
+
readFile: ['path', 'options'],
|
|
45
|
+
readlink: ['path', 'options'],
|
|
46
|
+
readv: ['fd'],
|
|
47
|
+
realpath: ['path', 'options'],
|
|
48
|
+
rename: ['oldPath', 'newPath'],
|
|
49
|
+
rmdir: ['path', 'options'],
|
|
50
|
+
rm: ['path', 'options'],
|
|
51
|
+
stat: ['path', 'options'],
|
|
52
|
+
symlink: ['target', 'path', 'type'],
|
|
53
|
+
truncate: ['path', 'len'],
|
|
54
|
+
unlink: ['path'],
|
|
55
|
+
utimes: ['path', 'atime', 'mtime'],
|
|
56
|
+
write: ['fd'],
|
|
57
|
+
writeFile: ['file', 'data', 'options'],
|
|
58
|
+
writev: ['fd']
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const watchMethods = {
|
|
62
|
+
unwatchFile: ['path', 'listener'],
|
|
63
|
+
watch: ['path', 'options', 'listener'],
|
|
64
|
+
watchFile: ['path', 'options', 'listener']
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const paramsByFileHandleMethods = {
|
|
68
|
+
appendFile: ['data', 'options'],
|
|
69
|
+
chmod: ['mode'],
|
|
70
|
+
chown: ['uid', 'gid'],
|
|
71
|
+
close: [],
|
|
72
|
+
createReadStream: ['options'],
|
|
73
|
+
createWriteStream: ['options'],
|
|
74
|
+
datasync: [],
|
|
75
|
+
read: ['buffer', 'offset', 'length', 'position'],
|
|
76
|
+
readableWebStream: [],
|
|
77
|
+
readFile: ['options'],
|
|
78
|
+
readLines: ['options'],
|
|
79
|
+
readv: ['buffers', 'position'],
|
|
80
|
+
stat: ['options'],
|
|
81
|
+
sync: [],
|
|
82
|
+
truncate: ['len'],
|
|
83
|
+
utimes: ['atime', 'mtime'],
|
|
84
|
+
write: ['buffer', 'offset', 'length', 'position'],
|
|
85
|
+
writeFile: ['data', 'options'],
|
|
86
|
+
writev: ['buffers', 'position']
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
addHook({ name: 'fs' }, fs => {
|
|
90
|
+
const asyncMethods = Object.keys(paramsByMethod)
|
|
91
|
+
const syncMethods = asyncMethods.map(name => `${name}Sync`)
|
|
92
|
+
|
|
93
|
+
massWrap(fs, asyncMethods, createWrapFunction())
|
|
94
|
+
massWrap(fs, syncMethods, createWrapFunction())
|
|
95
|
+
massWrap(fs.promises, asyncMethods, createWrapFunction('promises.'))
|
|
96
|
+
|
|
97
|
+
wrap(fs.realpath, 'native', createWrapFunction('', 'realpath.native'))
|
|
98
|
+
wrap(fs.realpathSync, 'native', createWrapFunction('', 'realpath.native'))
|
|
99
|
+
wrap(fs.promises.realpath, 'native', createWrapFunction('', 'realpath.native'))
|
|
100
|
+
|
|
101
|
+
wrap(fs, 'createReadStream', wrapCreateStream)
|
|
102
|
+
wrap(fs, 'createWriteStream', wrapCreateStream)
|
|
103
|
+
if (fs.Dir) {
|
|
104
|
+
wrap(fs.Dir.prototype, 'close', createWrapFunction('dir.'))
|
|
105
|
+
wrap(fs.Dir.prototype, 'closeSync', createWrapFunction('dir.'))
|
|
106
|
+
wrap(fs.Dir.prototype, 'read', createWrapFunction('dir.'))
|
|
107
|
+
wrap(fs.Dir.prototype, 'readSync', createWrapFunction('dir.'))
|
|
108
|
+
wrap(fs.Dir.prototype, Symbol.asyncIterator, createWrapDirAsyncIterator())
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
wrap(fs, 'unwatchFile', createWatchWrapFunction())
|
|
112
|
+
wrap(fs, 'watch', createWatchWrapFunction())
|
|
113
|
+
wrap(fs, 'watchFile', createWatchWrapFunction())
|
|
114
|
+
|
|
115
|
+
return fs
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
function isFirstMethodReturningFileHandle (original) {
|
|
119
|
+
return !kHandle && original.name === 'open'
|
|
120
|
+
}
|
|
121
|
+
function wrapFileHandle (fh) {
|
|
122
|
+
const fileHandlePrototype = getFileHandlePrototype(fh)
|
|
123
|
+
const desc = Reflect.getOwnPropertyDescriptor(fileHandlePrototype, kHandle)
|
|
124
|
+
if (!desc || !desc.get) {
|
|
125
|
+
Reflect.defineProperty(fileHandlePrototype, kHandle, {
|
|
126
|
+
get () {
|
|
127
|
+
return this[ddFhSym]
|
|
128
|
+
},
|
|
129
|
+
set (h) {
|
|
130
|
+
this[ddFhSym] = h
|
|
131
|
+
wrap(this, 'close', createWrapFunction('filehandle.'))
|
|
132
|
+
},
|
|
133
|
+
configurable: true
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
for (const name of Reflect.ownKeys(fileHandlePrototype)) {
|
|
137
|
+
if (typeof name !== 'string' || name === 'constructor' || name === 'fd' || name === 'getAsyncId') {
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
wrap(fileHandlePrototype, name, createWrapFunction('filehandle.'))
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getFileHandlePrototype (fh) {
|
|
145
|
+
if (!kHandle) {
|
|
146
|
+
kHandle = Reflect.ownKeys(fh).find(key => typeof key === 'symbol' && key.toString().includes('kHandle'))
|
|
147
|
+
}
|
|
148
|
+
return Object.getPrototypeOf(fh)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getSymbolName (sym) {
|
|
152
|
+
return sym.description || sym.toString()
|
|
153
|
+
}
|
|
154
|
+
function initDirAsyncIteratorProperties (iterator) {
|
|
155
|
+
const keys = Reflect.ownKeys(iterator)
|
|
156
|
+
for (const key of keys) {
|
|
157
|
+
if (kDirReadPromisified && kDirClosePromisified) break
|
|
158
|
+
if (typeof key !== 'symbol') continue
|
|
159
|
+
if (!kDirReadPromisified && getSymbolName(key).includes('kDirReadPromisified')) {
|
|
160
|
+
kDirReadPromisified = key
|
|
161
|
+
}
|
|
162
|
+
if (!kDirClosePromisified && getSymbolName(key).includes('kDirClosePromisified')) {
|
|
163
|
+
kDirClosePromisified = key
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function createWrapDirAsyncIterator () {
|
|
169
|
+
return function wrapDirAsyncIterator (asyncIterator) {
|
|
170
|
+
return function wrappedAsyncIterator () {
|
|
171
|
+
if (!kDirReadPromisified || !kDirClosePromisified) {
|
|
172
|
+
initDirAsyncIteratorProperties(this)
|
|
173
|
+
}
|
|
174
|
+
wrap(this, kDirReadPromisified, createWrapFunction('dir.', 'read'))
|
|
175
|
+
wrap(this, kDirClosePromisified, createWrapFunction('dir.', 'close'))
|
|
176
|
+
return asyncIterator.apply(this, arguments)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function wrapCreateStream (original) {
|
|
182
|
+
const classes = {
|
|
183
|
+
createReadStream: 'ReadStream',
|
|
184
|
+
createWriteStream: 'WriteStream'
|
|
185
|
+
}
|
|
186
|
+
const name = classes[original.name]
|
|
187
|
+
|
|
188
|
+
return function (path, options) {
|
|
189
|
+
if (!startChannel.hasSubscribers) return original.apply(this, arguments)
|
|
190
|
+
|
|
191
|
+
const innerResource = new AsyncResource('bound-anonymous-fn')
|
|
192
|
+
const message = getMessage(name, ['path', 'options'], arguments)
|
|
193
|
+
|
|
194
|
+
return innerResource.runInAsyncScope(() => {
|
|
195
|
+
startChannel.publish(message)
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const stream = original.apply(this, arguments)
|
|
199
|
+
const onError = innerResource.bind(error => {
|
|
200
|
+
errorChannel.publish(error)
|
|
201
|
+
onFinish()
|
|
202
|
+
})
|
|
203
|
+
const onFinish = innerResource.bind(() => {
|
|
204
|
+
finishChannel.publish()
|
|
205
|
+
stream.off('close', onFinish)
|
|
206
|
+
stream.off('end', onFinish)
|
|
207
|
+
stream.off('finish', onFinish)
|
|
208
|
+
stream.off('error', onError)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
stream.once('close', onFinish)
|
|
212
|
+
stream.once('end', onFinish)
|
|
213
|
+
stream.once('finish', onFinish)
|
|
214
|
+
stream.once('error', onError)
|
|
215
|
+
|
|
216
|
+
return stream
|
|
217
|
+
} catch (error) {
|
|
218
|
+
errorChannel.publish(error)
|
|
219
|
+
finishChannel.publish()
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function getMethodParamsRelationByPrefix (prefix) {
|
|
226
|
+
if (prefix === 'filehandle.') {
|
|
227
|
+
return paramsByFileHandleMethods
|
|
228
|
+
}
|
|
229
|
+
return paramsByMethod
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function createWatchWrapFunction (override = '') {
|
|
233
|
+
return function wrapFunction (original) {
|
|
234
|
+
const name = override || original.name
|
|
235
|
+
const method = name
|
|
236
|
+
const operation = name
|
|
237
|
+
return function () {
|
|
238
|
+
if (!startChannel.hasSubscribers) return original.apply(this, arguments)
|
|
239
|
+
const message = getMessage(method, watchMethods[operation], arguments, this)
|
|
240
|
+
const innerResource = new AsyncResource('bound-anonymous-fn')
|
|
241
|
+
return innerResource.runInAsyncScope(() => {
|
|
242
|
+
startChannel.publish(message)
|
|
243
|
+
try {
|
|
244
|
+
const result = original.apply(this, arguments)
|
|
245
|
+
finishChannel.publish()
|
|
246
|
+
return result
|
|
247
|
+
} catch (error) {
|
|
248
|
+
errorChannel.publish(error)
|
|
249
|
+
finishChannel.publish()
|
|
250
|
+
throw error
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function createWrapFunction (prefix = '', override = '') {
|
|
258
|
+
return function wrapFunction (original) {
|
|
259
|
+
const name = override || original.name
|
|
260
|
+
const method = `${prefix}${name}`
|
|
261
|
+
const operation = name.match(/^(.+?)(Sync)?(\.native)?$/)[1]
|
|
262
|
+
|
|
263
|
+
return function () {
|
|
264
|
+
if (!startChannel.hasSubscribers) return original.apply(this, arguments)
|
|
265
|
+
|
|
266
|
+
const lastIndex = arguments.length - 1
|
|
267
|
+
const cb = typeof arguments[lastIndex] === 'function' && arguments[lastIndex]
|
|
268
|
+
const innerResource = new AsyncResource('bound-anonymous-fn')
|
|
269
|
+
const message = getMessage(method, getMethodParamsRelationByPrefix(prefix)[operation], arguments, this)
|
|
270
|
+
|
|
271
|
+
if (cb) {
|
|
272
|
+
const outerResource = new AsyncResource('bound-anonymous-fn')
|
|
273
|
+
|
|
274
|
+
arguments[lastIndex] = innerResource.bind(function (e) {
|
|
275
|
+
if (typeof e === 'object') { // fs.exists receives a boolean
|
|
276
|
+
errorChannel.publish(e)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
finishChannel.publish()
|
|
280
|
+
|
|
281
|
+
return outerResource.runInAsyncScope(() => cb.apply(this, arguments))
|
|
282
|
+
})
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return innerResource.runInAsyncScope(() => {
|
|
286
|
+
startChannel.publish(message)
|
|
287
|
+
try {
|
|
288
|
+
const result = original.apply(this, arguments)
|
|
289
|
+
if (cb) return result
|
|
290
|
+
if (result && typeof result.then === 'function') {
|
|
291
|
+
// TODO method open returning promise and filehandle prototype not initialized, initialize it
|
|
292
|
+
|
|
293
|
+
return result.then(
|
|
294
|
+
value => {
|
|
295
|
+
if (isFirstMethodReturningFileHandle(original)) {
|
|
296
|
+
wrapFileHandle(value)
|
|
297
|
+
}
|
|
298
|
+
finishChannel.publish()
|
|
299
|
+
return value
|
|
300
|
+
},
|
|
301
|
+
error => {
|
|
302
|
+
errorChannel.publish(error)
|
|
303
|
+
finishChannel.publish()
|
|
304
|
+
throw error
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
finishChannel.publish()
|
|
310
|
+
|
|
311
|
+
return result
|
|
312
|
+
} catch (error) {
|
|
313
|
+
errorChannel.publish(error)
|
|
314
|
+
finishChannel.publish()
|
|
315
|
+
throw error
|
|
316
|
+
}
|
|
317
|
+
})
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function getMessage (operation, params, args, self) {
|
|
323
|
+
const metadata = {}
|
|
324
|
+
if (params) {
|
|
325
|
+
for (let i = 0; i < params.length; i++) {
|
|
326
|
+
if (!params[i] || typeof args[i] === 'function') continue
|
|
327
|
+
metadata[params[i]] = args[i]
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (self) {
|
|
332
|
+
// For `Dir` the path is available on `this.path`
|
|
333
|
+
if (self.path) {
|
|
334
|
+
metadata.path = self.path
|
|
335
|
+
}
|
|
336
|
+
// For FileHandle fs is available on `this.fd`
|
|
337
|
+
if (self.fd) {
|
|
338
|
+
metadata.fd = self.fd
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return { operation, ...metadata }
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function massWrap (target, methods, wrapper) {
|
|
346
|
+
for (const method of methods) {
|
|
347
|
+
wrap(target, method, wrapper)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function wrap (target, method, wrapper) {
|
|
352
|
+
try {
|
|
353
|
+
shimmer.wrap(target, method, wrapper)
|
|
354
|
+
} catch (e) {
|
|
355
|
+
// skip unavailable method
|
|
356
|
+
}
|
|
357
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
'@cucumber/cucumber': () => require('../cucumber'),
|
|
5
|
+
'@playwright/test': () => require('../playwright'),
|
|
5
6
|
'@elastic/elasticsearch': () => require('../elasticsearch'),
|
|
6
7
|
'@elastic/transport': () => require('../elasticsearch'),
|
|
7
8
|
'@google-cloud/pubsub': () => require('../google-cloud-pubsub'),
|
|
@@ -31,6 +32,8 @@ module.exports = {
|
|
|
31
32
|
'express': () => require('../express'),
|
|
32
33
|
'fastify': () => require('../fastify'),
|
|
33
34
|
'find-my-way': () => require('../find-my-way'),
|
|
35
|
+
'fs': () => require('../fs'),
|
|
36
|
+
'node:fs': () => require('../fs'),
|
|
34
37
|
'graphql': () => require('../graphql'),
|
|
35
38
|
'grpc': () => require('../grpc'),
|
|
36
39
|
'hapi': () => require('../hapi'),
|
|
@@ -218,9 +218,19 @@ function cliWrapper (cli) {
|
|
|
218
218
|
|
|
219
219
|
const isSuitesSkipped = !!skippableSuites.length
|
|
220
220
|
|
|
221
|
+
let testFrameworkVersion
|
|
222
|
+
try {
|
|
223
|
+
testFrameworkVersion = this.getVersion()
|
|
224
|
+
} catch (e) {
|
|
225
|
+
try {
|
|
226
|
+
testFrameworkVersion = this.default.getVersion()
|
|
227
|
+
} catch (e) {
|
|
228
|
+
// ignore errors
|
|
229
|
+
}
|
|
230
|
+
}
|
|
221
231
|
const processArgv = process.argv.slice(2).join(' ')
|
|
222
232
|
sessionAsyncResource.runInAsyncScope(() => {
|
|
223
|
-
testSessionStartCh.publish(`jest ${processArgv}
|
|
233
|
+
testSessionStartCh.publish({ command: `jest ${processArgv}`, testFrameworkVersion })
|
|
224
234
|
})
|
|
225
235
|
|
|
226
236
|
const result = await runCLI.apply(this, arguments)
|
|
@@ -39,6 +39,7 @@ const testFileToSuiteAr = new Map()
|
|
|
39
39
|
const originalCoverageMap = createCoverageMap()
|
|
40
40
|
|
|
41
41
|
let suitesToSkip = []
|
|
42
|
+
let mochaVersion
|
|
42
43
|
|
|
43
44
|
function getSuitesByTestFile (root) {
|
|
44
45
|
const suitesByTestFile = {}
|
|
@@ -128,7 +129,7 @@ function mochaHook (Runner) {
|
|
|
128
129
|
this.once('start', testRunAsyncResource.bind(function () {
|
|
129
130
|
const processArgv = process.argv.slice(2).join(' ')
|
|
130
131
|
const command = `mocha ${processArgv}`
|
|
131
|
-
testSessionStartCh.publish(command)
|
|
132
|
+
testSessionStartCh.publish({ command, frameworkVersion: mochaVersion })
|
|
132
133
|
}))
|
|
133
134
|
|
|
134
135
|
this.on('suite', function (suite) {
|
|
@@ -315,12 +316,12 @@ addHook({
|
|
|
315
316
|
file: 'lib/mocha.js'
|
|
316
317
|
}, (Mocha) => {
|
|
317
318
|
const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
318
|
-
|
|
319
319
|
/**
|
|
320
320
|
* Get ITR configuration and skippable suites
|
|
321
321
|
* If ITR is disabled, `onDone` is called immediately on the subscriber
|
|
322
322
|
*/
|
|
323
323
|
shimmer.wrap(Mocha.prototype, 'run', run => function () {
|
|
324
|
+
mochaVersion = this.version
|
|
324
325
|
if (!itrConfigurationCh.hasSubscribers) {
|
|
325
326
|
return run.apply(this, arguments)
|
|
326
327
|
}
|
|
@@ -19,13 +19,19 @@ addHook({ name: 'mysql', file: 'lib/Connection.js', versions: ['>=2'] }, Connect
|
|
|
19
19
|
|
|
20
20
|
const sql = arguments[0].sql ? arguments[0].sql : arguments[0]
|
|
21
21
|
const conf = this.config
|
|
22
|
+
const payload = { sql, conf }
|
|
22
23
|
|
|
23
24
|
const callbackResource = new AsyncResource('bound-anonymous-fn')
|
|
24
25
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
25
26
|
|
|
26
27
|
return asyncResource.runInAsyncScope(() => {
|
|
27
|
-
startCh.publish(
|
|
28
|
+
startCh.publish(payload)
|
|
28
29
|
|
|
30
|
+
if (arguments[0].sql) {
|
|
31
|
+
arguments[0].sql = payload.sql
|
|
32
|
+
} else {
|
|
33
|
+
arguments[0] = payload.sql
|
|
34
|
+
}
|
|
29
35
|
try {
|
|
30
36
|
const res = query.apply(this, arguments)
|
|
31
37
|
|
|
@@ -45,8 +45,14 @@ addHook({ name: 'mysql2', file: 'lib/connection.js', versions: ['>=1'] }, Connec
|
|
|
45
45
|
|
|
46
46
|
return asyncResource.bind(function executeWithTrace (packet, connection) {
|
|
47
47
|
const sql = cmd.statement ? cmd.statement.query : cmd.sql
|
|
48
|
+
const payload = { sql, conf: config }
|
|
49
|
+
startCh.publish(payload)
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
if (cmd.statement) {
|
|
52
|
+
cmd.statement.query = payload.sql
|
|
53
|
+
} else {
|
|
54
|
+
cmd.sql = payload.sql
|
|
55
|
+
}
|
|
50
56
|
|
|
51
57
|
if (this.onResult) {
|
|
52
58
|
const onResult = callbackResource.bind(this.onResult)
|