dd-trace 2.11.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +0 -1
- package/index.d.ts +3 -3
- package/package.json +4 -5
- package/packages/datadog-core/src/storage/async_hooks.js +4 -4
- package/packages/datadog-core/src/storage/async_resource.js +14 -4
- package/packages/datadog-instrumentations/src/couchbase.js +166 -61
- package/packages/datadog-instrumentations/src/graphql.js +17 -5
- package/packages/datadog-instrumentations/src/mocha.js +88 -18
- package/packages/datadog-instrumentations/src/restify.js +4 -8
- package/packages/datadog-plugin-couchbase/src/index.js +8 -10
- package/packages/datadog-plugin-graphql/src/resolve.js +2 -0
- package/packages/datadog-plugin-http/src/server.js +3 -8
- package/packages/datadog-plugin-mocha/src/index.js +80 -3
- package/packages/datadog-plugin-next/src/index.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +34 -10
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +111 -15
- package/packages/dd-trace/src/plugin_manager.js +49 -33
- package/packages/dd-trace/src/plugins/util/test.js +32 -1
- package/packages/dd-trace/src/plugins/util/web.js +22 -17
- package/packages/dd-trace/src/profiling/config.js +10 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -2
- package/packages/dd-trace/src/profiling/exporters/form-data.js +53 -0
- package/packages/dd-trace/src/profiling/index.js +2 -0
- package/packages/dd-trace/src/profiling/profiler.js +6 -1
- package/packages/dd-trace/src/profiling/profilers/cpu.js +126 -0
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -6,7 +6,6 @@ require,@datadog/sketches-js,Apache license 2.0,Copyright 2020 Datadog Inc.
|
|
|
6
6
|
require,@types/node,MIT,Copyright Authors
|
|
7
7
|
require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
|
|
8
8
|
require,diagnostics_channel,MIT,Copyright 2021 Simon D.
|
|
9
|
-
require,form-data,MIT,Copyright 2012 Felix Geisendörfer and contributors
|
|
10
9
|
require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
|
|
11
10
|
require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
|
|
12
11
|
require,koalas,MIT,Copyright 2013-2017 Brian Woodward
|
package/index.d.ts
CHANGED
|
@@ -313,10 +313,10 @@ export declare interface TracerOptions {
|
|
|
313
313
|
};
|
|
314
314
|
|
|
315
315
|
/**
|
|
316
|
-
* Experimental features can be enabled
|
|
316
|
+
* Experimental features can be enabled individually using key / value pairs.
|
|
317
317
|
* @default {}
|
|
318
318
|
*/
|
|
319
|
-
experimental?:
|
|
319
|
+
experimental?: {
|
|
320
320
|
b3?: boolean
|
|
321
321
|
traceparent?: boolean
|
|
322
322
|
|
|
@@ -1216,7 +1216,7 @@ declare namespace plugins {
|
|
|
1216
1216
|
|
|
1217
1217
|
/**
|
|
1218
1218
|
* This plugin automatically instruments the
|
|
1219
|
-
* [mysql2](https://github.com/
|
|
1219
|
+
* [mysql2](https://github.com/sidorares/node-mysql2) module.
|
|
1220
1220
|
*/
|
|
1221
1221
|
interface mysql2 extends mysql {}
|
|
1222
1222
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -59,15 +59,14 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@datadog/native-appsec": "^1.2.1",
|
|
62
|
-
"@datadog/native-metrics": "^1.4.
|
|
63
|
-
"@datadog/pprof": "^0.
|
|
62
|
+
"@datadog/native-metrics": "^1.4.1",
|
|
63
|
+
"@datadog/pprof": "^1.0.0",
|
|
64
64
|
"@datadog/sketches-js": "^1.0.5",
|
|
65
65
|
"@types/node": ">=12",
|
|
66
66
|
"crypto-randomuuid": "^1.0.0",
|
|
67
67
|
"diagnostics_channel": "^1.1.0",
|
|
68
|
-
"form-data": "^3.0.0",
|
|
69
68
|
"ignore": "^5.2.0",
|
|
70
|
-
"import-in-the-middle": "^1.
|
|
69
|
+
"import-in-the-middle": "^1.3.0",
|
|
71
70
|
"koalas": "^1.0.2",
|
|
72
71
|
"limiter": "^1.1.4",
|
|
73
72
|
"lodash.kebabcase": "^4.1.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { executionAsyncId } = require('async_hooks')
|
|
4
4
|
const AsyncResourceStorage = require('./async_resource')
|
|
5
5
|
|
|
6
6
|
class AsyncHooksStorage extends AsyncResourceStorage {
|
|
@@ -17,10 +17,10 @@ class AsyncHooksStorage extends AsyncResourceStorage {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
_createHook () {
|
|
20
|
-
return
|
|
21
|
-
|
|
20
|
+
return {
|
|
21
|
+
...super._createHook(),
|
|
22
22
|
destroy: this._destroy.bind(this)
|
|
23
|
-
}
|
|
23
|
+
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
_init (asyncId, type, triggerAsyncId, resource) {
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { createHook, executionAsyncResource } = require('async_hooks')
|
|
4
|
+
const { channel } = require('diagnostics_channel')
|
|
5
|
+
|
|
6
|
+
const beforeCh = channel('dd-trace:storage:before')
|
|
7
|
+
const afterCh = channel('dd-trace:storage:after')
|
|
4
8
|
|
|
5
9
|
class AsyncResourceStorage {
|
|
6
10
|
constructor () {
|
|
7
11
|
this._ddResourceStore = Symbol('ddResourceStore')
|
|
8
12
|
this._enabled = false
|
|
9
|
-
this._hook = this._createHook()
|
|
13
|
+
this._hook = createHook(this._createHook())
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
disable () {
|
|
@@ -48,9 +52,15 @@ class AsyncResourceStorage {
|
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
_createHook () {
|
|
51
|
-
return
|
|
52
|
-
init: this._init.bind(this)
|
|
53
|
-
|
|
55
|
+
return {
|
|
56
|
+
init: this._init.bind(this),
|
|
57
|
+
before () {
|
|
58
|
+
beforeCh.publish()
|
|
59
|
+
},
|
|
60
|
+
after () {
|
|
61
|
+
afterCh.publish()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
_enable () {
|
|
@@ -7,70 +7,23 @@ const {
|
|
|
7
7
|
} = require('./helpers/instrument')
|
|
8
8
|
const shimmer = require('../../datadog-shimmer')
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const finishCh = channel('apm:couchbase:query:finish')
|
|
13
|
-
const errorCh = channel('apm:couchbase:query:error')
|
|
14
|
-
|
|
15
|
-
Bucket.prototype._maybeInvoke = wrapMaybeInvoke(Bucket.prototype._maybeInvoke)
|
|
16
|
-
Bucket.prototype.query = wrapQuery(Bucket.prototype.query)
|
|
17
|
-
|
|
18
|
-
shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) {
|
|
19
|
-
if (!startCh.hasSubscribers) {
|
|
20
|
-
return _n1qlReq.apply(this, arguments)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments)
|
|
24
|
-
|
|
25
|
-
const n1qlQuery = q && q.statement
|
|
26
|
-
|
|
27
|
-
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
28
|
-
return asyncResource.runInAsyncScope(() => {
|
|
29
|
-
startCh.publish({ resource: n1qlQuery, bucket: this })
|
|
30
|
-
|
|
31
|
-
emitter.once('rows', asyncResource.bind(() => {
|
|
32
|
-
finishCh.publish(undefined)
|
|
33
|
-
}))
|
|
34
|
-
|
|
35
|
-
emitter.once('error', asyncResource.bind((error) => {
|
|
36
|
-
errorCh.publish(error)
|
|
37
|
-
finishCh.publish(undefined)
|
|
38
|
-
}))
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
return _n1qlReq.apply(this, arguments)
|
|
42
|
-
} catch (err) {
|
|
43
|
-
err.stack // trigger getting the stack at the original throwing point
|
|
44
|
-
errorCh.publish(err)
|
|
45
|
-
|
|
46
|
-
throw err
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
Bucket.prototype.upsert = wrap('apm:couchbase:upsert', Bucket.prototype.upsert)
|
|
52
|
-
Bucket.prototype.insert = wrap('apm:couchbase:insert', Bucket.prototype.insert)
|
|
53
|
-
Bucket.prototype.replace = wrap('apm:couchbase:replace', Bucket.prototype.replace)
|
|
54
|
-
Bucket.prototype.append = wrap('apm:couchbase:append', Bucket.prototype.append)
|
|
55
|
-
Bucket.prototype.prepend = wrap('apm:couchbase:prepend', Bucket.prototype.prepend)
|
|
56
|
-
|
|
57
|
-
return Bucket
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.5'] }, Cluster => {
|
|
61
|
-
Cluster.prototype._maybeInvoke = wrapMaybeInvoke(Cluster.prototype._maybeInvoke)
|
|
62
|
-
Cluster.prototype.query = wrapQuery(Cluster.prototype.query)
|
|
63
|
-
|
|
64
|
-
return Cluster
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
function findCallbackIndex (args) {
|
|
68
|
-
for (let i = args.length - 1; i >= 2; i--) {
|
|
10
|
+
function findCallbackIndex (args, lowerbound = 2) {
|
|
11
|
+
for (let i = args.length - 1; i >= lowerbound; i--) {
|
|
69
12
|
if (typeof args[i] === 'function') return i
|
|
70
13
|
}
|
|
71
14
|
return -1
|
|
72
15
|
}
|
|
73
16
|
|
|
17
|
+
// handles n1ql and string queries
|
|
18
|
+
function getQueryResource (q) {
|
|
19
|
+
return q && (typeof q === 'string' ? q : q.statement)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function wrapAllNames (names, action) {
|
|
23
|
+
names.forEach(name => action(name))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// semver >=2 <3
|
|
74
27
|
function wrapMaybeInvoke (_maybeInvoke) {
|
|
75
28
|
const wrapped = function (fn, args) {
|
|
76
29
|
if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments)
|
|
@@ -106,7 +59,7 @@ function wrap (prefix, fn) {
|
|
|
106
59
|
const finishCh = channel(prefix + ':finish')
|
|
107
60
|
const errorCh = channel(prefix + ':error')
|
|
108
61
|
|
|
109
|
-
const wrapped = function (
|
|
62
|
+
const wrapped = function () {
|
|
110
63
|
if (!startCh.hasSubscribers) {
|
|
111
64
|
return fn.apply(this, arguments)
|
|
112
65
|
}
|
|
@@ -121,7 +74,7 @@ function wrap (prefix, fn) {
|
|
|
121
74
|
return asyncResource.runInAsyncScope(() => {
|
|
122
75
|
const cb = callbackResource.bind(arguments[callbackIndex])
|
|
123
76
|
|
|
124
|
-
startCh.publish({ bucket: this })
|
|
77
|
+
startCh.publish({ bucket: { name: this.name || this._name } })
|
|
125
78
|
|
|
126
79
|
arguments[callbackIndex] = asyncResource.bind(function (error, result) {
|
|
127
80
|
if (error) {
|
|
@@ -143,3 +96,155 @@ function wrap (prefix, fn) {
|
|
|
143
96
|
}
|
|
144
97
|
return shimmer.wrap(fn, wrapped)
|
|
145
98
|
}
|
|
99
|
+
|
|
100
|
+
// semver >=3
|
|
101
|
+
|
|
102
|
+
function wrapCBandPromise (fn, name, startData, thisArg, args) {
|
|
103
|
+
const startCh = channel(`apm:couchbase:${name}:start`)
|
|
104
|
+
const finishCh = channel(`apm:couchbase:${name}:finish`)
|
|
105
|
+
const errorCh = channel(`apm:couchbase:${name}:error`)
|
|
106
|
+
|
|
107
|
+
if (!startCh.hasSubscribers) return fn.apply(thisArg, args)
|
|
108
|
+
|
|
109
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
110
|
+
const callbackResource = new AsyncResource('bound-anonymous-fn')
|
|
111
|
+
|
|
112
|
+
return asyncResource.runInAsyncScope(() => {
|
|
113
|
+
startCh.publish(startData)
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const cbIndex = findCallbackIndex(args, 1)
|
|
117
|
+
if (cbIndex >= 0) {
|
|
118
|
+
// v3 offers callback or promises event handling
|
|
119
|
+
// NOTE: this does not work with v3.2.0-3.2.1 cluster.query, as there is a bug in the couchbase source code
|
|
120
|
+
const cb = callbackResource.bind(args[cbIndex])
|
|
121
|
+
args[cbIndex] = asyncResource.bind(function (error, result) {
|
|
122
|
+
if (error) {
|
|
123
|
+
errorCh.publish(error)
|
|
124
|
+
}
|
|
125
|
+
finishCh.publish({ result })
|
|
126
|
+
return cb.apply(thisArg, arguments)
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
const res = fn.apply(thisArg, args)
|
|
130
|
+
|
|
131
|
+
// semver >=3 will always return promise by default
|
|
132
|
+
res.then(
|
|
133
|
+
asyncResource.bind((result) => finishCh.publish({ result })),
|
|
134
|
+
asyncResource.bind((err) => errorCh.publish(err)))
|
|
135
|
+
return res
|
|
136
|
+
} catch (e) {
|
|
137
|
+
e.stack
|
|
138
|
+
errorCh.publish(e)
|
|
139
|
+
throw e
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function wrapWithName (name) {
|
|
145
|
+
return function (operation) {
|
|
146
|
+
return function () { // no arguments used by us
|
|
147
|
+
return wrapCBandPromise(operation, name, {
|
|
148
|
+
collection: { name: this._name || '_default' },
|
|
149
|
+
bucket: { name: this._scope._bucket._name }
|
|
150
|
+
}, this, arguments)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function wrapV3Query (query) {
|
|
156
|
+
return function (q) {
|
|
157
|
+
const resource = getQueryResource(q)
|
|
158
|
+
return wrapCBandPromise(query, 'query', { resource }, this, arguments)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// semver >=2 <3
|
|
163
|
+
addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.5'] }, Bucket => {
|
|
164
|
+
const startCh = channel('apm:couchbase:query:start')
|
|
165
|
+
const finishCh = channel('apm:couchbase:query:finish')
|
|
166
|
+
const errorCh = channel('apm:couchbase:query:error')
|
|
167
|
+
|
|
168
|
+
Bucket.prototype._maybeInvoke = wrapMaybeInvoke(Bucket.prototype._maybeInvoke)
|
|
169
|
+
Bucket.prototype.query = wrapQuery(Bucket.prototype.query)
|
|
170
|
+
|
|
171
|
+
shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) {
|
|
172
|
+
if (!startCh.hasSubscribers) {
|
|
173
|
+
return _n1qlReq.apply(this, arguments)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments)
|
|
177
|
+
|
|
178
|
+
const n1qlQuery = getQueryResource(q)
|
|
179
|
+
|
|
180
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
181
|
+
return asyncResource.runInAsyncScope(() => {
|
|
182
|
+
startCh.publish({ resource: n1qlQuery, bucket: { name: this.name || this._name } })
|
|
183
|
+
|
|
184
|
+
emitter.once('rows', asyncResource.bind(() => {
|
|
185
|
+
finishCh.publish(undefined)
|
|
186
|
+
}))
|
|
187
|
+
|
|
188
|
+
emitter.once('error', asyncResource.bind((error) => {
|
|
189
|
+
errorCh.publish(error)
|
|
190
|
+
finishCh.publish(undefined)
|
|
191
|
+
}))
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
return _n1qlReq.apply(this, arguments)
|
|
195
|
+
} catch (err) {
|
|
196
|
+
err.stack // trigger getting the stack at the original throwing point
|
|
197
|
+
errorCh.publish(err)
|
|
198
|
+
|
|
199
|
+
throw err
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
wrapAllNames(['upsert', 'insert', 'replace', 'append', 'prepend'], name => {
|
|
205
|
+
Bucket.prototype[name] = wrap(`apm:couchbase:${name}`, Bucket.prototype[name])
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
return Bucket
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.5'] }, Cluster => {
|
|
212
|
+
Cluster.prototype._maybeInvoke = wrapMaybeInvoke(Cluster.prototype._maybeInvoke)
|
|
213
|
+
Cluster.prototype.query = wrapQuery(Cluster.prototype.query)
|
|
214
|
+
|
|
215
|
+
return Cluster
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
// semver >=3 <3.2.0
|
|
219
|
+
|
|
220
|
+
addHook({ name: 'couchbase', file: 'lib/collection.js', versions: ['>=3.0.0 <3.2.0'] }, Collection => {
|
|
221
|
+
wrapAllNames(['upsert', 'insert', 'replace'], name => {
|
|
222
|
+
shimmer.wrap(Collection.prototype, name, wrapWithName(name))
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
return Collection
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['>=3.0.0 <3.2.0'] }, Cluster => {
|
|
229
|
+
shimmer.wrap(Cluster.prototype, 'query', wrapV3Query)
|
|
230
|
+
return Cluster
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
// semver >=3.2.0
|
|
234
|
+
|
|
235
|
+
addHook({ name: 'couchbase', file: 'dist/collection.js', versions: ['>=3.2.0'] }, collection => {
|
|
236
|
+
const Collection = collection.Collection
|
|
237
|
+
|
|
238
|
+
wrapAllNames(['upsert', 'insert', 'replace'], name => {
|
|
239
|
+
shimmer.wrap(Collection.prototype, name, wrapWithName(name))
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
return collection
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
addHook({ name: 'couchbase', file: 'dist/cluster.js', versions: ['3.2.0 - 3.2.1', '>=3.2.2'] }, cluster => {
|
|
246
|
+
const Cluster = cluster.Cluster
|
|
247
|
+
|
|
248
|
+
shimmer.wrap(Cluster.prototype, 'query', wrapV3Query)
|
|
249
|
+
return cluster
|
|
250
|
+
})
|
|
@@ -17,12 +17,15 @@ const patchedTypes = new WeakSet()
|
|
|
17
17
|
/** CHANNELS */
|
|
18
18
|
|
|
19
19
|
// execute channels
|
|
20
|
-
const startResolveCh = channel('apm:graphql:resolve:start')
|
|
21
20
|
const startExecuteCh = channel('apm:graphql:execute:start')
|
|
22
21
|
const finishExecuteCh = channel('apm:graphql:execute:finish')
|
|
22
|
+
const executeErrorCh = channel('apm:graphql:execute:error')
|
|
23
|
+
|
|
24
|
+
// resolve channels
|
|
25
|
+
const startResolveCh = channel('apm:graphql:resolve:start')
|
|
23
26
|
const finishResolveCh = channel('apm:graphql:resolve:finish')
|
|
24
27
|
const updateFieldCh = channel('apm:graphql:resolve:updateField')
|
|
25
|
-
const
|
|
28
|
+
const resolveErrorCh = channel('apm:graphql:resolve:error')
|
|
26
29
|
|
|
27
30
|
// parse channels
|
|
28
31
|
const parseStartCh = channel('apm:graphql:parser:start')
|
|
@@ -124,7 +127,9 @@ function wrapValidate (validate) {
|
|
|
124
127
|
let errors
|
|
125
128
|
try {
|
|
126
129
|
errors = validate.apply(this, arguments)
|
|
127
|
-
|
|
130
|
+
if (errors && errors[0]) {
|
|
131
|
+
validateErrorCh.publish(errors && errors[0])
|
|
132
|
+
}
|
|
128
133
|
return errors
|
|
129
134
|
} catch (err) {
|
|
130
135
|
err.stack
|
|
@@ -177,7 +182,12 @@ function wrapExecute (execute) {
|
|
|
177
182
|
return callInAsyncScope(exe, asyncResource, this, arguments, (err, res) => {
|
|
178
183
|
if (finishResolveCh.hasSubscribers) finishResolvers(context)
|
|
179
184
|
|
|
180
|
-
|
|
185
|
+
const error = err || (res && res.errors && res.errors[0])
|
|
186
|
+
|
|
187
|
+
if (error) {
|
|
188
|
+
executeErrorCh.publish(error)
|
|
189
|
+
}
|
|
190
|
+
|
|
181
191
|
finishExecuteCh.publish({ res, args })
|
|
182
192
|
})
|
|
183
193
|
})
|
|
@@ -331,7 +341,9 @@ function finishResolvers ({ fields }) {
|
|
|
331
341
|
const field = fields[key]
|
|
332
342
|
const asyncResource = field.asyncResource
|
|
333
343
|
asyncResource.runInAsyncScope(() => {
|
|
334
|
-
|
|
344
|
+
if (field.error) {
|
|
345
|
+
resolveErrorCh.publish(field.error)
|
|
346
|
+
}
|
|
335
347
|
finishResolveCh.publish(field.finishTime)
|
|
336
348
|
})
|
|
337
349
|
})
|
|
@@ -6,8 +6,31 @@ const errorCh = channel('ci:mocha:test:error')
|
|
|
6
6
|
const skipCh = channel('ci:mocha:test:skip')
|
|
7
7
|
const testFinishCh = channel('ci:mocha:test:finish')
|
|
8
8
|
const parameterizedTestCh = channel('ci:mocha:test:parameterize')
|
|
9
|
+
|
|
10
|
+
const testRunStartCh = channel('ci:mocha:run:start')
|
|
9
11
|
const testRunFinishCh = channel('ci:mocha:run:finish')
|
|
10
12
|
|
|
13
|
+
const testSuiteStartCh = channel('ci:mocha:test-suite:start')
|
|
14
|
+
const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
|
|
15
|
+
const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
|
|
16
|
+
|
|
17
|
+
// TODO: remove when root hooks and fixtures are implemented
|
|
18
|
+
const patched = new WeakSet()
|
|
19
|
+
|
|
20
|
+
const testToAr = new WeakMap()
|
|
21
|
+
const originalFns = new WeakMap()
|
|
22
|
+
const testSuiteToAr = new WeakMap()
|
|
23
|
+
|
|
24
|
+
function getTestStatus (test) {
|
|
25
|
+
if (test.pending) {
|
|
26
|
+
return 'skip'
|
|
27
|
+
}
|
|
28
|
+
if (test.state !== 'failed' && !test.timedOut) {
|
|
29
|
+
return 'pass'
|
|
30
|
+
}
|
|
31
|
+
return 'fail'
|
|
32
|
+
}
|
|
33
|
+
|
|
11
34
|
function isRetry (test) {
|
|
12
35
|
return test._currentRetry !== undefined && test._currentRetry !== 0
|
|
13
36
|
}
|
|
@@ -23,12 +46,6 @@ function getTestAsyncResource (test) {
|
|
|
23
46
|
return testToAr.get(originalFn)
|
|
24
47
|
}
|
|
25
48
|
|
|
26
|
-
// TODO: remove when root hooks and fixtures are implemented
|
|
27
|
-
const patched = new WeakSet()
|
|
28
|
-
|
|
29
|
-
const testToAr = new WeakMap()
|
|
30
|
-
const originalFns = new WeakMap()
|
|
31
|
-
|
|
32
49
|
function mochaHook (Runner) {
|
|
33
50
|
if (patched.has(Runner)) return Runner
|
|
34
51
|
|
|
@@ -39,6 +56,59 @@ function mochaHook (Runner) {
|
|
|
39
56
|
return run.apply(this, arguments)
|
|
40
57
|
}
|
|
41
58
|
|
|
59
|
+
const testRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
60
|
+
|
|
61
|
+
this.once('end', testRunAsyncResource.bind(function () {
|
|
62
|
+
let status = 'pass'
|
|
63
|
+
if (this.stats) {
|
|
64
|
+
status = this.stats.failures === 0 ? 'pass' : 'fail'
|
|
65
|
+
} else if (this.failures !== 0) {
|
|
66
|
+
status = 'fail'
|
|
67
|
+
}
|
|
68
|
+
testRunFinishCh.publish(status)
|
|
69
|
+
}))
|
|
70
|
+
|
|
71
|
+
this.once('start', testRunAsyncResource.bind(function () {
|
|
72
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
73
|
+
const command = `mocha ${processArgv}`
|
|
74
|
+
testRunStartCh.publish(command)
|
|
75
|
+
}))
|
|
76
|
+
|
|
77
|
+
this.on('suite', function (suite) {
|
|
78
|
+
if (suite.root) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
82
|
+
|
|
83
|
+
testSuiteToAr.set(suite, asyncResource)
|
|
84
|
+
|
|
85
|
+
asyncResource.runInAsyncScope(() => {
|
|
86
|
+
testSuiteStartCh.publish(suite)
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
this.on('suite end', function (suite) {
|
|
91
|
+
if (suite.root) {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
let status = 'pass'
|
|
95
|
+
if (suite.pending) {
|
|
96
|
+
status = 'skip'
|
|
97
|
+
} else {
|
|
98
|
+
suite.eachTest(test => {
|
|
99
|
+
if (test.state === 'failed' || test.timedOut) {
|
|
100
|
+
status = 'fail'
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const asyncResource = testSuiteToAr.get(suite)
|
|
106
|
+
asyncResource.runInAsyncScope(() => {
|
|
107
|
+
// get suite status
|
|
108
|
+
testSuiteFinishCh.publish(status)
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
42
112
|
this.on('test', (test) => {
|
|
43
113
|
if (isRetry(test)) {
|
|
44
114
|
return
|
|
@@ -52,14 +122,7 @@ function mochaHook (Runner) {
|
|
|
52
122
|
|
|
53
123
|
this.on('test end', (test) => {
|
|
54
124
|
const asyncResource = getTestAsyncResource(test)
|
|
55
|
-
|
|
56
|
-
if (test.pending) {
|
|
57
|
-
status = 'skip'
|
|
58
|
-
} else if (test.state !== 'failed' && !test.timedOut) {
|
|
59
|
-
status = 'pass'
|
|
60
|
-
} else {
|
|
61
|
-
status = 'fail'
|
|
62
|
-
}
|
|
125
|
+
const status = getTestStatus(test)
|
|
63
126
|
|
|
64
127
|
// if there are afterEach to be run, we don't finish the test yet
|
|
65
128
|
if (!test.parent._afterEach.length) {
|
|
@@ -75,9 +138,10 @@ function mochaHook (Runner) {
|
|
|
75
138
|
if (test && hook.parent._afterEach.includes(hook)) { // only if it's an afterEach
|
|
76
139
|
const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
|
|
77
140
|
if (isLastAfterEach) {
|
|
141
|
+
const status = getTestStatus(test)
|
|
78
142
|
const asyncResource = getTestAsyncResource(test)
|
|
79
143
|
asyncResource.runInAsyncScope(() => {
|
|
80
|
-
testFinishCh.publish(
|
|
144
|
+
testFinishCh.publish(status)
|
|
81
145
|
})
|
|
82
146
|
}
|
|
83
147
|
}
|
|
@@ -100,6 +164,15 @@ function mochaHook (Runner) {
|
|
|
100
164
|
} else {
|
|
101
165
|
errorCh.publish(err)
|
|
102
166
|
}
|
|
167
|
+
// we propagate the error to the suite
|
|
168
|
+
const testSuiteAsyncResource = testSuiteToAr.get(test.parent)
|
|
169
|
+
if (testSuiteAsyncResource) {
|
|
170
|
+
const testSuiteError = new Error(`Test "${test.fullTitle()}" failed with message "${err.message}"`)
|
|
171
|
+
testSuiteError.stack = err.stack
|
|
172
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
173
|
+
testSuiteErrorCh.publish(testSuiteError)
|
|
174
|
+
})
|
|
175
|
+
}
|
|
103
176
|
})
|
|
104
177
|
}
|
|
105
178
|
})
|
|
@@ -127,9 +200,6 @@ function mochaHook (Runner) {
|
|
|
127
200
|
if (!testRunFinishCh.hasSubscribers) {
|
|
128
201
|
return runTests.apply(this, arguments)
|
|
129
202
|
}
|
|
130
|
-
this.once('end', AsyncResource.bind(() => {
|
|
131
|
-
testRunFinishCh.publish()
|
|
132
|
-
}))
|
|
133
203
|
return runTests.apply(this, arguments)
|
|
134
204
|
})
|
|
135
205
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel
|
|
4
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
5
5
|
const handlers = ['use', 'pre']
|
|
6
6
|
const methods = ['del', 'get', 'head', 'opts', 'post', 'put', 'patch']
|
|
7
7
|
|
|
@@ -9,14 +9,14 @@ const handleChannel = channel('apm:restify:request:handle')
|
|
|
9
9
|
const routeChannel = channel('apm:restify:request:route')
|
|
10
10
|
|
|
11
11
|
function wrapSetupRequest (setupRequest) {
|
|
12
|
-
return function
|
|
12
|
+
return function (req, res) {
|
|
13
13
|
handleChannel.publish({ req, res })
|
|
14
14
|
return setupRequest.apply(this, arguments)
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function wrapMethod (method) {
|
|
19
|
-
return function
|
|
19
|
+
return function (path) {
|
|
20
20
|
const middleware = wrapMiddleware(Array.prototype.slice.call(arguments, 1))
|
|
21
21
|
|
|
22
22
|
return method.apply(this, [path].concat(middleware))
|
|
@@ -24,7 +24,7 @@ function wrapMethod (method) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function wrapHandler (method) {
|
|
27
|
-
return function
|
|
27
|
+
return function () {
|
|
28
28
|
return method.apply(this, wrapMiddleware(arguments))
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -37,10 +37,6 @@ function wrapFn (fn) {
|
|
|
37
37
|
if (Array.isArray(fn)) return wrapMiddleware(fn)
|
|
38
38
|
|
|
39
39
|
return function (req, res, next) {
|
|
40
|
-
if (typeof next === 'function') {
|
|
41
|
-
arguments[2] = AsyncResource.bind(next)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
40
|
if (req.route) {
|
|
45
41
|
routeChannel.publish({ req, route: req.route })
|
|
46
42
|
}
|
|
@@ -11,11 +11,11 @@ class CouchBasePlugin extends Plugin {
|
|
|
11
11
|
|
|
12
12
|
addSubs (func, start, finish = defaultFinish) {
|
|
13
13
|
this.addSub(`apm:couchbase:${func}:start`, start)
|
|
14
|
-
this.addSub(`apm:couchbase:${func}:error`,
|
|
14
|
+
this.addSub(`apm:couchbase:${func}:error`, this.addError)
|
|
15
15
|
this.addSub(`apm:couchbase:${func}:finish`, finish)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
startSpan (operation, customTags, store, bucket) {
|
|
18
|
+
startSpan (operation, customTags, store, { bucket, collection }) {
|
|
19
19
|
const tags = {
|
|
20
20
|
'db.type': 'couchbase',
|
|
21
21
|
'component': 'couchbase',
|
|
@@ -32,7 +32,8 @@ class CouchBasePlugin extends Plugin {
|
|
|
32
32
|
tags
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
span.setTag(
|
|
35
|
+
if (bucket) span.setTag(`couchbase.bucket.name`, bucket.name)
|
|
36
|
+
if (collection) span.setTag(`couchbase.collection.name`, collection.name)
|
|
36
37
|
|
|
37
38
|
analyticsSampler.sample(span, this.config.measured)
|
|
38
39
|
return span
|
|
@@ -43,7 +44,8 @@ class CouchBasePlugin extends Plugin {
|
|
|
43
44
|
|
|
44
45
|
this.addSubs('query', ({ resource, bucket }) => {
|
|
45
46
|
const store = storage.getStore()
|
|
46
|
-
const span = this.startSpan('query', { 'span.type': 'sql', 'resource.name': resource },
|
|
47
|
+
const span = this.startSpan('query', { 'span.type': 'sql', 'resource.name': resource },
|
|
48
|
+
store, { bucket })
|
|
47
49
|
this.enter(span, store)
|
|
48
50
|
})
|
|
49
51
|
|
|
@@ -54,9 +56,9 @@ class CouchBasePlugin extends Plugin {
|
|
|
54
56
|
this._addCommandSubs('prepend')
|
|
55
57
|
}
|
|
56
58
|
_addCommandSubs (name) {
|
|
57
|
-
this.addSubs(name, ({ bucket }) => {
|
|
59
|
+
this.addSubs(name, ({ bucket, collection }) => {
|
|
58
60
|
const store = storage.getStore()
|
|
59
|
-
const span = this.startSpan(name, {}, store, bucket)
|
|
61
|
+
const span = this.startSpan(name, {}, store, { bucket, collection })
|
|
60
62
|
this.enter(span, store)
|
|
61
63
|
})
|
|
62
64
|
}
|
|
@@ -66,8 +68,4 @@ function defaultFinish () {
|
|
|
66
68
|
storage.getStore().span.finish()
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
function errorHandler (error) {
|
|
70
|
-
storage.getStore().span.setTag('error', error)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
71
|
module.exports = CouchBasePlugin
|