dd-trace 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +57 -0
- package/package.json +2 -2
- package/packages/datadog-instrumentations/index.js +9 -0
- package/packages/datadog-instrumentations/src/amqp10.js +70 -0
- package/packages/datadog-instrumentations/src/amqplib.js +58 -0
- package/packages/datadog-instrumentations/src/cassandra-driver.js +191 -0
- package/packages/datadog-instrumentations/src/cucumber.js +118 -0
- package/packages/datadog-instrumentations/src/elasticsearch.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/instrument.js +3 -3
- package/packages/datadog-instrumentations/src/ioredis.js +8 -5
- package/packages/datadog-instrumentations/src/mocha.js +122 -0
- package/packages/datadog-instrumentations/src/mongodb-core.js +179 -0
- package/packages/datadog-instrumentations/src/pg.js +75 -0
- package/packages/datadog-instrumentations/src/redis.js +8 -8
- package/packages/datadog-instrumentations/src/rhea.js +224 -0
- package/packages/datadog-instrumentations/src/tedious.js +66 -0
- package/packages/datadog-plugin-amqp10/src/index.js +79 -122
- package/packages/datadog-plugin-amqplib/src/index.js +77 -142
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
- package/packages/datadog-plugin-cassandra-driver/src/index.js +52 -224
- package/packages/datadog-plugin-cucumber/src/index.js +85 -128
- package/packages/datadog-plugin-jest/src/jest-jasmine2.js +5 -3
- package/packages/datadog-plugin-mocha/src/index.js +96 -207
- package/packages/datadog-plugin-mongodb-core/src/index.js +119 -3
- package/packages/datadog-plugin-pg/src/index.js +32 -69
- package/packages/datadog-plugin-rhea/src/index.js +59 -225
- package/packages/datadog-plugin-tedious/src/index.js +38 -86
- package/packages/dd-trace/lib/version.js +1 -1
- package/packages/dd-trace/src/appsec/recommended.json +137 -116
- package/packages/dd-trace/src/config.js +13 -1
- package/packages/dd-trace/src/noop/tracer.js +4 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +34 -1
- package/packages/dd-trace/src/opentracing/tracer.js +1 -1
- package/packages/dd-trace/src/plugins/log_plugin.js +10 -5
- package/packages/dd-trace/src/plugins/util/git.js +1 -1
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/span_processor.js +22 -7
- package/packages/dd-trace/src/tracer.js +16 -0
- package/packages/datadog-plugin-mongodb-core/src/legacy.js +0 -59
- package/packages/datadog-plugin-mongodb-core/src/unified.js +0 -138
- package/packages/datadog-plugin-mongodb-core/src/util.js +0 -143
package/index.d.ts
CHANGED
|
@@ -108,6 +108,13 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
108
108
|
* should not be cached.
|
|
109
109
|
*/
|
|
110
110
|
getRumData(): string;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Links an authenticated user to the current trace.
|
|
114
|
+
* @param {User} user Properties of the authenticated user. Accepts custom fields.
|
|
115
|
+
* @returns {Tracer} The Tracer instance for chaining.
|
|
116
|
+
*/
|
|
117
|
+
setUser(user: User): Tracer;
|
|
111
118
|
}
|
|
112
119
|
|
|
113
120
|
export declare interface TraceOptions extends Analyzable {
|
|
@@ -266,6 +273,12 @@ export declare interface TracerOptions {
|
|
|
266
273
|
*/
|
|
267
274
|
flushInterval?: number;
|
|
268
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Number of spans before partially exporting a trace. This prevents keeping all the spans in memory for very large traces.
|
|
278
|
+
* @default 1000
|
|
279
|
+
*/
|
|
280
|
+
flushMinSpans?: number;
|
|
281
|
+
|
|
269
282
|
/**
|
|
270
283
|
* Whether to enable runtime metrics.
|
|
271
284
|
* @default false
|
|
@@ -305,6 +318,7 @@ export declare interface TracerOptions {
|
|
|
305
318
|
*/
|
|
306
319
|
experimental?: boolean | {
|
|
307
320
|
b3?: boolean
|
|
321
|
+
traceparent?: boolean
|
|
308
322
|
|
|
309
323
|
/**
|
|
310
324
|
* Whether to add an auto-generated `runtime-id` tag to metrics.
|
|
@@ -418,6 +432,49 @@ export declare interface TracerOptions {
|
|
|
418
432
|
};
|
|
419
433
|
}
|
|
420
434
|
|
|
435
|
+
/**
|
|
436
|
+
* User object that can be passed to `tracer.setUser()`.
|
|
437
|
+
*/
|
|
438
|
+
export declare interface User {
|
|
439
|
+
/**
|
|
440
|
+
* Unique identifier of the user.
|
|
441
|
+
* Mandatory.
|
|
442
|
+
*/
|
|
443
|
+
id: string,
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Email of the user.
|
|
447
|
+
*/
|
|
448
|
+
email?: string,
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* User-friendly name of the user.
|
|
452
|
+
*/
|
|
453
|
+
name?: string,
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Session ID of the user.
|
|
457
|
+
*/
|
|
458
|
+
session_id?: string,
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Role the user is making the request under.
|
|
462
|
+
*/
|
|
463
|
+
role?: string,
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Scopes or granted authorizations the user currently possesses.
|
|
467
|
+
* The value could come from the scope associated with an OAuth2
|
|
468
|
+
* Access Token or an attribute value in a SAML 2 Assertion.
|
|
469
|
+
*/
|
|
470
|
+
scope?: string,
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Custom fields to attach to the user (RBAC, Oauth, etc…).
|
|
474
|
+
*/
|
|
475
|
+
[key: string]: string | undefined
|
|
476
|
+
}
|
|
477
|
+
|
|
421
478
|
/** @hidden */
|
|
422
479
|
interface EventEmitter {
|
|
423
480
|
emit(eventName: string | symbol, ...args: any[]): any;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"node": ">=12"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@datadog/native-appsec": "^0.8.
|
|
64
|
+
"@datadog/native-appsec": "^0.8.2",
|
|
65
65
|
"@datadog/native-metrics": "^1.1.0",
|
|
66
66
|
"@datadog/pprof": "^0.3.0",
|
|
67
67
|
"@datadog/sketches-js": "^1.0.4",
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
require('./src/amqplib')
|
|
4
|
+
require('./src/amqp10')
|
|
3
5
|
require('./src/bluebird')
|
|
4
6
|
require('./src/bunyan')
|
|
7
|
+
require('./src/cassandra-driver')
|
|
5
8
|
require('./src/couchbase')
|
|
9
|
+
require('./src/cucumber')
|
|
6
10
|
require('./src/dns')
|
|
7
11
|
require('./src/elasticsearch')
|
|
8
12
|
require('./src/generic-pool')
|
|
9
13
|
require('./src/ioredis')
|
|
10
14
|
require('./src/memcached')
|
|
15
|
+
require('./src/mongodb-core')
|
|
11
16
|
require('./src/mongoose')
|
|
12
17
|
require('./src/mysql')
|
|
13
18
|
require('./src/mysql2')
|
|
19
|
+
require('./src/mocha')
|
|
14
20
|
require('./src/pino')
|
|
21
|
+
require('./src/pg')
|
|
15
22
|
require('./src/promise')
|
|
16
23
|
require('./src/promise-js')
|
|
17
24
|
require('./src/q')
|
|
18
25
|
require('./src/redis')
|
|
26
|
+
require('./src/rhea')
|
|
19
27
|
require('./src/sharedb')
|
|
28
|
+
require('./src/tedious')
|
|
20
29
|
require('./src/when')
|
|
21
30
|
require('./src/winston')
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
channel,
|
|
5
|
+
addHook,
|
|
6
|
+
AsyncResource
|
|
7
|
+
} = require('./helpers/instrument')
|
|
8
|
+
const shimmer = require('../../datadog-shimmer')
|
|
9
|
+
|
|
10
|
+
addHook({ name: 'amqp10', file: 'lib/sender_link.js', versions: ['>=3'] }, SenderLink => {
|
|
11
|
+
const startCh = channel('apm:amqp10:send:start')
|
|
12
|
+
const asyncEndCh = channel('apm:amqp10:send:async-end')
|
|
13
|
+
const endCh = channel('apm:amqp10:send:end')
|
|
14
|
+
const errorCh = channel('apm:amqp10:send:error')
|
|
15
|
+
shimmer.wrap(SenderLink.prototype, 'send', send => function (msg, options) {
|
|
16
|
+
if (!startCh.hasSubscribers) {
|
|
17
|
+
return send.apply(this, arguments)
|
|
18
|
+
}
|
|
19
|
+
startCh.publish({ link: this })
|
|
20
|
+
try {
|
|
21
|
+
const promise = send.apply(this, arguments)
|
|
22
|
+
|
|
23
|
+
if (!promise) {
|
|
24
|
+
finish(asyncEndCh, errorCh)
|
|
25
|
+
return promise
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
29
|
+
|
|
30
|
+
promise.then(asyncResource.bind(() => finish(asyncEndCh, errorCh)),
|
|
31
|
+
asyncResource.bind(e => finish(asyncEndCh, errorCh, e)))
|
|
32
|
+
|
|
33
|
+
return promise
|
|
34
|
+
} catch (err) {
|
|
35
|
+
finish(asyncEndCh, errorCh, err)
|
|
36
|
+
throw err
|
|
37
|
+
} finally {
|
|
38
|
+
endCh.publish(undefined)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
return SenderLink
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
addHook({ name: 'amqp10', file: 'lib/receiver_link.js', versions: ['>=3'] }, ReceiverLink => {
|
|
45
|
+
const startCh = channel('apm:amqp10:receive:start')
|
|
46
|
+
const endCh = channel('apm:amqp10:receive:end')
|
|
47
|
+
const errorCh = channel('apm:amqp10:receive:error')
|
|
48
|
+
shimmer.wrap(ReceiverLink.prototype, '_messageReceived', messageReceived => function (transferFrame) {
|
|
49
|
+
if (!transferFrame || transferFrame.aborted || transferFrame.more) {
|
|
50
|
+
return messageReceived.apply(this, arguments)
|
|
51
|
+
}
|
|
52
|
+
startCh.publish({ link: this })
|
|
53
|
+
try {
|
|
54
|
+
return messageReceived.apply(this, arguments)
|
|
55
|
+
} catch (err) {
|
|
56
|
+
errorCh.publish(err)
|
|
57
|
+
throw err
|
|
58
|
+
} finally {
|
|
59
|
+
endCh.publish(undefined)
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
return ReceiverLink
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
function finish (asyncEndCh, errorCh, error) {
|
|
66
|
+
if (error) {
|
|
67
|
+
errorCh.publish(error)
|
|
68
|
+
}
|
|
69
|
+
asyncEndCh.publish(undefined)
|
|
70
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
channel,
|
|
5
|
+
addHook
|
|
6
|
+
} = require('./helpers/instrument')
|
|
7
|
+
const kebabCase = require('lodash.kebabcase')
|
|
8
|
+
const shimmer = require('../../datadog-shimmer')
|
|
9
|
+
|
|
10
|
+
const startCh = channel('apm:amqplib:command:start')
|
|
11
|
+
const endCh = channel('apm:amqplib:command:end')
|
|
12
|
+
const errorCh = channel('apm:amqplib:command:error')
|
|
13
|
+
|
|
14
|
+
let methods = {}
|
|
15
|
+
|
|
16
|
+
addHook({ name: 'amqplib', file: 'lib/defs.js', versions: ['>=0.5'] }, defs => {
|
|
17
|
+
methods = Object.keys(defs)
|
|
18
|
+
.filter(key => Number.isInteger(defs[key]))
|
|
19
|
+
.filter(key => isCamelCase(key))
|
|
20
|
+
.reduce((acc, key) => Object.assign(acc, { [defs[key]]: kebabCase(key).replace('-', '.') }), {})
|
|
21
|
+
return defs
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
addHook({ name: 'amqplib', file: 'lib/channel.js', versions: ['>=0.5'] }, channel => {
|
|
25
|
+
shimmer.wrap(channel.Channel.prototype, 'sendImmediately', sendImmediately => function (method, fields) {
|
|
26
|
+
return instrument(sendImmediately, this, arguments, methods[method], fields)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
shimmer.wrap(channel.Channel.prototype, 'sendMessage', sendMessage => function (fields) {
|
|
30
|
+
return instrument(sendMessage, this, arguments, 'basic.publish', fields)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
shimmer.wrap(channel.BaseChannel.prototype, 'dispatchMessage', dispatchMessage => function (fields, message) {
|
|
34
|
+
return instrument(dispatchMessage, this, arguments, 'basic.deliver', fields, message)
|
|
35
|
+
})
|
|
36
|
+
return channel
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
function instrument (send, channel, args, method, fields, message) {
|
|
40
|
+
if (!startCh.hasSubscribers) {
|
|
41
|
+
return send.apply(this, arguments)
|
|
42
|
+
}
|
|
43
|
+
startCh.publish({ channel, method, fields, message })
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
return send.apply(channel, args)
|
|
47
|
+
} catch (err) {
|
|
48
|
+
errorCh.publish(err)
|
|
49
|
+
|
|
50
|
+
throw err
|
|
51
|
+
} finally {
|
|
52
|
+
endCh.publish(undefined)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isCamelCase (str) {
|
|
57
|
+
return /([A-Z][a-z0-9]+)+/.test(str)
|
|
58
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
channel,
|
|
5
|
+
addHook,
|
|
6
|
+
AsyncResource
|
|
7
|
+
} = require('./helpers/instrument')
|
|
8
|
+
const shimmer = require('../../datadog-shimmer')
|
|
9
|
+
|
|
10
|
+
const startCh = channel('apm:cassandra:query:start')
|
|
11
|
+
const asyncEndCh = channel('apm:cassandra:query:async-end')
|
|
12
|
+
const endCh = channel('apm:cassandra:query:end')
|
|
13
|
+
const errorCh = channel('apm:cassandra:query:error')
|
|
14
|
+
const addConnectionCh = channel(`apm:cassandra:query:addConnection`)
|
|
15
|
+
|
|
16
|
+
addHook({ name: 'cassandra-driver', versions: ['>=3.0.0'] }, cassandra => {
|
|
17
|
+
shimmer.wrap(cassandra.Client.prototype, 'batch', batch => function (queries, options, callback) {
|
|
18
|
+
if (!startCh.hasSubscribers) {
|
|
19
|
+
return batch.apply(this, arguments)
|
|
20
|
+
}
|
|
21
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
22
|
+
startCh.publish({ keyspace: this.keyspace, query: queries })
|
|
23
|
+
|
|
24
|
+
const lastIndex = arguments.length - 1
|
|
25
|
+
let cb = arguments[lastIndex]
|
|
26
|
+
|
|
27
|
+
if (typeof cb === 'function') {
|
|
28
|
+
cb = asyncResource.bind(cb)
|
|
29
|
+
arguments[lastIndex] = wrapCallback(asyncEndCh, errorCh, cb)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const res = batch.apply(this, arguments)
|
|
34
|
+
if (typeof res === 'function' || !res) {
|
|
35
|
+
return wrapCallback(asyncEndCh, errorCh, res)
|
|
36
|
+
} else {
|
|
37
|
+
const promiseAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
38
|
+
return res.then(
|
|
39
|
+
promiseAsyncResource.bind(() => finish(asyncEndCh, errorCh)),
|
|
40
|
+
promiseAsyncResource.bind(err => finish(asyncEndCh, errorCh, err))
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {
|
|
44
|
+
finish(asyncEndCh, errorCh, e)
|
|
45
|
+
throw e
|
|
46
|
+
} finally {
|
|
47
|
+
endCh.publish(undefined)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
return cassandra
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
addHook({ name: 'cassandra-driver', versions: ['>=4.4'] }, cassandra => {
|
|
54
|
+
shimmer.wrap(cassandra.Client.prototype, '_execute', _execute => function (query, params, execOptions, callback) {
|
|
55
|
+
if (!startCh.hasSubscribers) {
|
|
56
|
+
return _execute.apply(this, arguments)
|
|
57
|
+
}
|
|
58
|
+
startCh.publish({ keyspace: this.keyspace, query })
|
|
59
|
+
const promise = _execute.apply(this, arguments)
|
|
60
|
+
|
|
61
|
+
const promiseAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
62
|
+
|
|
63
|
+
promise.then(
|
|
64
|
+
promiseAsyncResource.bind(() => finish(asyncEndCh, errorCh)),
|
|
65
|
+
promiseAsyncResource.bind(err => finish(asyncEndCh, errorCh, err))
|
|
66
|
+
)
|
|
67
|
+
endCh.publish(undefined)
|
|
68
|
+
return promise
|
|
69
|
+
})
|
|
70
|
+
return cassandra
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
addHook({ name: 'cassandra-driver', versions: ['3 - 4.3'] }, cassandra => {
|
|
74
|
+
shimmer.wrap(cassandra.Client.prototype, '_innerExecute', _innerExecute =>
|
|
75
|
+
function (query, params, execOptions, callback) {
|
|
76
|
+
if (!startCh.hasSubscribers) {
|
|
77
|
+
return _innerExecute.apply(this, arguments)
|
|
78
|
+
}
|
|
79
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
80
|
+
const isValid = (args) => {
|
|
81
|
+
return args.length === 4 || typeof args[3] === 'function'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!isValid(arguments)) {
|
|
85
|
+
return _innerExecute.apply(this, arguments)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
startCh.publish({ keyspace: this.keyspace, query })
|
|
89
|
+
|
|
90
|
+
const lastIndex = arguments.length - 1
|
|
91
|
+
let cb = arguments[lastIndex]
|
|
92
|
+
|
|
93
|
+
if (typeof cb === 'function') {
|
|
94
|
+
cb = asyncResource.bind(cb)
|
|
95
|
+
arguments[lastIndex] = wrapCallback(asyncEndCh, errorCh, cb)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
return _innerExecute.apply(this, arguments)
|
|
100
|
+
} catch (e) {
|
|
101
|
+
finish(asyncEndCh, errorCh, e)
|
|
102
|
+
throw e
|
|
103
|
+
} finally {
|
|
104
|
+
endCh.publish(undefined)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
return cassandra
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
addHook({ name: 'cassandra-driver', versions: ['>=3.3'], file: 'lib/request-execution.js' }, RequestExecution => {
|
|
112
|
+
shimmer.wrap(RequestExecution.prototype, '_sendOnConnection', _sendOnConnection => function () {
|
|
113
|
+
if (!startCh.hasSubscribers) {
|
|
114
|
+
return _sendOnConnection.apply(this, arguments)
|
|
115
|
+
}
|
|
116
|
+
addConnectionCh.publish({ address: this._connection.address, port: this._connection.port })
|
|
117
|
+
return _sendOnConnection.apply(this, arguments)
|
|
118
|
+
})
|
|
119
|
+
return RequestExecution
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
addHook({ name: 'cassandra-driver', versions: ['3.3 - 4.3'], file: 'lib/request-execution.js' }, RequestExecution => {
|
|
123
|
+
shimmer.wrap(RequestExecution.prototype, 'start', start => function (getHostCallback) {
|
|
124
|
+
if (!startCh.hasSubscribers) {
|
|
125
|
+
return getHostCallback.apply(this, arguments)
|
|
126
|
+
}
|
|
127
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
128
|
+
const execution = this
|
|
129
|
+
|
|
130
|
+
if (!isRequestValid(this, arguments, 1)) {
|
|
131
|
+
return start.apply(this, arguments)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
getHostCallback = asyncResource.bind(getHostCallback)
|
|
135
|
+
|
|
136
|
+
arguments[0] = AsyncResource.bind(function () {
|
|
137
|
+
addConnectionCh.publish({ address: execution._connection.address, port: execution._connection.port })
|
|
138
|
+
return getHostCallback.apply(this, arguments)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
return start.apply(this, arguments)
|
|
142
|
+
})
|
|
143
|
+
return RequestExecution
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
addHook({ name: 'cassandra-driver', versions: ['3 - 3.2'], file: 'lib/request-handler.js' }, RequestHandler => {
|
|
147
|
+
shimmer.wrap(RequestHandler.prototype, 'send', send => function (request, options, callback) {
|
|
148
|
+
if (!startCh.hasSubscribers) {
|
|
149
|
+
return send.apply(this, arguments)
|
|
150
|
+
}
|
|
151
|
+
const handler = this
|
|
152
|
+
|
|
153
|
+
if (!isRequestValid(this, arguments, 3)) {
|
|
154
|
+
return send.apply(this, arguments)
|
|
155
|
+
}
|
|
156
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
157
|
+
|
|
158
|
+
callback = asyncResource.bind(callback)
|
|
159
|
+
|
|
160
|
+
arguments[2] = AsyncResource.bind(function () {
|
|
161
|
+
addConnectionCh.publish({ address: handler.connection.address, port: handler.connection.port })
|
|
162
|
+
return callback.apply(this, arguments)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
return send.apply(this, arguments)
|
|
166
|
+
})
|
|
167
|
+
return RequestHandler
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
function finish (asyncEndCh, errorCh, error) {
|
|
171
|
+
if (error) {
|
|
172
|
+
errorCh.publish(error)
|
|
173
|
+
}
|
|
174
|
+
asyncEndCh.publish(undefined)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function wrapCallback (asyncEndCh, errorCh, callback) {
|
|
178
|
+
return AsyncResource.bind(function (err) {
|
|
179
|
+
finish(asyncEndCh, errorCh, err)
|
|
180
|
+
if (callback) {
|
|
181
|
+
return callback.apply(this, arguments)
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function isRequestValid (exec, args, length) {
|
|
187
|
+
if (!exec) return false
|
|
188
|
+
if (args.length !== length || typeof args[length - 1] !== 'function') return false
|
|
189
|
+
|
|
190
|
+
return true
|
|
191
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
|
|
6
|
+
const runStartCh = channel('ci:cucumber:run:start')
|
|
7
|
+
const runEndCh = channel('ci:cucumber:run:end')
|
|
8
|
+
const runAsyncEndCh = channel('ci:cucumber:run:async-end')
|
|
9
|
+
const runStepStartCh = channel('ci:cucumber:run-step:start')
|
|
10
|
+
const runStepEndCh = channel('ci:cucumber:run-step:end')
|
|
11
|
+
const errorCh = channel('ci:cucumber:error')
|
|
12
|
+
|
|
13
|
+
function getStatusFromResult (result) {
|
|
14
|
+
if (result.status === 1) {
|
|
15
|
+
return { status: 'pass' }
|
|
16
|
+
}
|
|
17
|
+
if (result.status === 2) {
|
|
18
|
+
return { status: 'skip' }
|
|
19
|
+
}
|
|
20
|
+
if (result.status === 4) {
|
|
21
|
+
return { status: 'skip', skipReason: 'not implemented' }
|
|
22
|
+
}
|
|
23
|
+
return { status: 'fail', errorMessage: result.message }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getStatusFromResultLatest (result) {
|
|
27
|
+
if (result.status === 'PASSED') {
|
|
28
|
+
return { status: 'pass' }
|
|
29
|
+
}
|
|
30
|
+
if (result.status === 'SKIPPED' || result.status === 'PENDING') {
|
|
31
|
+
return { status: 'skip' }
|
|
32
|
+
}
|
|
33
|
+
if (result.status === 'UNDEFINED') {
|
|
34
|
+
return { status: 'skip', skipReason: 'not implemented' }
|
|
35
|
+
}
|
|
36
|
+
return { status: 'fail', errorMessage: result.message }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function wrapRun (pl, isLatestVersion) {
|
|
40
|
+
shimmer.wrap(pl.prototype, 'run', run => function () {
|
|
41
|
+
if (!runStartCh.hasSubscribers) {
|
|
42
|
+
return run.apply(this, arguments)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
runStartCh.publish({ pickleName: this.pickle.name, pickleUri: this.pickle.uri })
|
|
46
|
+
try {
|
|
47
|
+
const promise = run.apply(this, arguments)
|
|
48
|
+
promise.finally(() => {
|
|
49
|
+
const result = this.getWorstStepResult()
|
|
50
|
+
const { status, skipReason, errorMessage } = isLatestVersion
|
|
51
|
+
? getStatusFromResultLatest(result) : getStatusFromResult(result)
|
|
52
|
+
|
|
53
|
+
runAsyncEndCh.publish({ status, skipReason, errorMessage })
|
|
54
|
+
})
|
|
55
|
+
return promise
|
|
56
|
+
} catch (err) {
|
|
57
|
+
errorCh.publish(err)
|
|
58
|
+
throw err
|
|
59
|
+
} finally {
|
|
60
|
+
runEndCh.publish(undefined)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
shimmer.wrap(pl.prototype, 'runStep', runStep => function () {
|
|
64
|
+
if (!runStepStartCh.hasSubscribers) {
|
|
65
|
+
return runStep.apply(this, arguments)
|
|
66
|
+
}
|
|
67
|
+
const testStep = arguments[0]
|
|
68
|
+
let resource
|
|
69
|
+
|
|
70
|
+
if (isLatestVersion) {
|
|
71
|
+
resource = testStep.text
|
|
72
|
+
} else {
|
|
73
|
+
resource = testStep.isHook ? 'hook' : testStep.pickleStep.text
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
runStepStartCh.publish({ resource })
|
|
77
|
+
try {
|
|
78
|
+
const promise = runStep.apply(this, arguments)
|
|
79
|
+
|
|
80
|
+
promise.then((result) => {
|
|
81
|
+
const { status, skipReason, errorMessage } = isLatestVersion
|
|
82
|
+
? getStatusFromResultLatest(result) : getStatusFromResult(result)
|
|
83
|
+
|
|
84
|
+
runAsyncEndCh.publish({ isStep: true, status, skipReason, errorMessage })
|
|
85
|
+
})
|
|
86
|
+
return promise
|
|
87
|
+
} catch (err) {
|
|
88
|
+
errorCh.publish(err)
|
|
89
|
+
throw err
|
|
90
|
+
} finally {
|
|
91
|
+
runStepEndCh.publish(undefined)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
addHook({
|
|
97
|
+
name: '@cucumber/cucumber',
|
|
98
|
+
versions: ['7.0.0 - 7.2.1'],
|
|
99
|
+
file: 'lib/runtime/pickle_runner.js'
|
|
100
|
+
}, (PickleRunner) => {
|
|
101
|
+
const pl = PickleRunner.default
|
|
102
|
+
|
|
103
|
+
wrapRun(pl, false)
|
|
104
|
+
|
|
105
|
+
return PickleRunner
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
addHook({
|
|
109
|
+
name: '@cucumber/cucumber',
|
|
110
|
+
versions: ['>=7.3.0'],
|
|
111
|
+
file: 'lib/runtime/test_case_runner.js'
|
|
112
|
+
}, (TestCaseRunner) => {
|
|
113
|
+
const pl = TestCaseRunner.default
|
|
114
|
+
|
|
115
|
+
wrapRun(pl, true)
|
|
116
|
+
|
|
117
|
+
return TestCaseRunner
|
|
118
|
+
})
|
|
@@ -35,18 +35,20 @@ function wrapRequest (request) {
|
|
|
35
35
|
|
|
36
36
|
if (!params) return request.apply(this, arguments)
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const parentResource = new AsyncResource('bound-anonymous-fn')
|
|
39
39
|
|
|
40
40
|
startCh.publish({ params })
|
|
41
41
|
|
|
42
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
43
|
+
|
|
42
44
|
try {
|
|
43
45
|
const lastIndex = arguments.length - 1
|
|
44
46
|
cb = arguments[lastIndex]
|
|
45
47
|
|
|
46
48
|
if (typeof cb === 'function') {
|
|
47
|
-
cb =
|
|
49
|
+
cb = parentResource.bind(cb)
|
|
48
50
|
|
|
49
|
-
arguments[lastIndex] =
|
|
51
|
+
arguments[lastIndex] = asyncResource.bind(function (error) {
|
|
50
52
|
finish(params, error)
|
|
51
53
|
return cb.apply(null, arguments)
|
|
52
54
|
})
|
|
@@ -54,7 +56,10 @@ function wrapRequest (request) {
|
|
|
54
56
|
} else {
|
|
55
57
|
const promise = request.apply(this, arguments)
|
|
56
58
|
if (promise && typeof promise.then === 'function') {
|
|
57
|
-
|
|
59
|
+
const onResolve = asyncResource.bind(() => finish(params))
|
|
60
|
+
const onReject = asyncResource.bind(e => finish(params, e))
|
|
61
|
+
|
|
62
|
+
promise.then(onResolve, onReject)
|
|
58
63
|
} else {
|
|
59
64
|
finish(params)
|
|
60
65
|
}
|
|
@@ -20,11 +20,11 @@ exports.channel = function channel (name) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
exports.addHook = function addHook ({ name, versions, file }, hook) {
|
|
23
|
-
|
|
23
|
+
const fullFilename = filename(name, file)
|
|
24
24
|
const loaderHook = (moduleExports, moduleName, moduleBaseDir) => {
|
|
25
25
|
moduleName = moduleName.replace(pathSepExpr, '/')
|
|
26
26
|
const moduleVersion = getVersion(moduleBaseDir)
|
|
27
|
-
if (moduleName !==
|
|
27
|
+
if (moduleName !== fullFilename || !matchVersion(moduleVersion, versions)) {
|
|
28
28
|
return moduleExports
|
|
29
29
|
}
|
|
30
30
|
return hook(moduleExports)
|
|
@@ -65,7 +65,7 @@ function cjsPostLoad (instrumentation, hook) {
|
|
|
65
65
|
if (!id.includes(`/node_modules/${instrumentation.name}/`)) continue
|
|
66
66
|
|
|
67
67
|
if (instrumentation.file) {
|
|
68
|
-
if (!id.endsWith(`/node_modules/${filename(instrumentation)}`)) continue
|
|
68
|
+
if (!id.endsWith(`/node_modules/${filename(instrumentation.name, instrumentation.file)}`)) continue
|
|
69
69
|
|
|
70
70
|
const basedir = getBasedir(ids[i])
|
|
71
71
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
channel,
|
|
5
|
-
addHook
|
|
5
|
+
addHook,
|
|
6
|
+
AsyncResource
|
|
6
7
|
} = require('./helpers/instrument')
|
|
7
8
|
const shimmer = require('../../datadog-shimmer')
|
|
8
9
|
|
|
@@ -21,12 +22,14 @@ addHook({ name: 'ioredis', versions: ['>=2'] }, Redis => {
|
|
|
21
22
|
const connectionName = options.connectionName
|
|
22
23
|
const db = options.db
|
|
23
24
|
const connectionOptions = { host: options.host, port: options.port }
|
|
25
|
+
|
|
24
26
|
startCh.publish({ db, command: command.name, args: command.args, connectionOptions, connectionName })
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
29
|
+
const onResolve = asyncResource.bind(() => finish(asyncEndCh, errorCh))
|
|
30
|
+
const onReject = asyncResource.bind(err => finish(asyncEndCh, errorCh, err))
|
|
31
|
+
|
|
32
|
+
command.promise.then(onResolve, onReject)
|
|
30
33
|
|
|
31
34
|
try {
|
|
32
35
|
return sendCommand.apply(this, arguments)
|