dd-trace 2.11.0 → 2.12.1
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/connect.js +4 -4
- package/packages/datadog-instrumentations/src/couchbase.js +166 -61
- package/packages/datadog-instrumentations/src/fastify.js +12 -25
- package/packages/datadog-instrumentations/src/graphql.js +17 -5
- package/packages/datadog-instrumentations/src/koa.js +4 -4
- package/packages/datadog-instrumentations/src/mocha.js +88 -18
- package/packages/datadog-instrumentations/src/restify.js +4 -8
- package/packages/datadog-instrumentations/src/router.js +4 -4
- 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 +39 -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 +25 -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.1",
|
|
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 () {
|
|
@@ -78,12 +78,12 @@ function wrapLayerHandle (layer) {
|
|
|
78
78
|
|
|
79
79
|
try {
|
|
80
80
|
return original.apply(this, arguments)
|
|
81
|
-
} catch (
|
|
82
|
-
errorChannel.publish(
|
|
81
|
+
} catch (error) {
|
|
82
|
+
errorChannel.publish({ req, error })
|
|
83
83
|
nextChannel.publish({ req })
|
|
84
84
|
exitChannel.publish({ req })
|
|
85
85
|
|
|
86
|
-
throw
|
|
86
|
+
throw error
|
|
87
87
|
}
|
|
88
88
|
})
|
|
89
89
|
})
|
|
@@ -92,7 +92,7 @@ function wrapLayerHandle (layer) {
|
|
|
92
92
|
function wrapNext (req, next) {
|
|
93
93
|
return function (error) {
|
|
94
94
|
if (error) {
|
|
95
|
-
errorChannel.publish(error)
|
|
95
|
+
errorChannel.publish({ req, error })
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
nextChannel.publish({ req })
|
|
@@ -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
|
+
})
|
|
@@ -6,7 +6,6 @@ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
|
6
6
|
const errorChannel = channel('apm:fastify:middleware:error')
|
|
7
7
|
const handleChannel = channel('apm:fastify:request:handle')
|
|
8
8
|
|
|
9
|
-
const requestResources = new WeakMap()
|
|
10
9
|
const parsingResources = new WeakMap()
|
|
11
10
|
|
|
12
11
|
function wrapFastify (fastify, hasParsingEvents) {
|
|
@@ -42,16 +41,13 @@ function wrapAddHook (addHook) {
|
|
|
42
41
|
|
|
43
42
|
arguments[arguments.length - 1] = shimmer.wrap(fn, function (request, reply, done) {
|
|
44
43
|
const req = getReq(request)
|
|
45
|
-
const requestResource = requestResources.get(req)
|
|
46
|
-
|
|
47
|
-
if (!requestResource) return fn.apply(this, arguments)
|
|
48
44
|
|
|
49
45
|
try {
|
|
50
46
|
if (typeof done === 'function') {
|
|
51
47
|
done = arguments[arguments.length - 1]
|
|
52
48
|
|
|
53
49
|
arguments[arguments.length - 1] = function (err) {
|
|
54
|
-
publishError(err,
|
|
50
|
+
publishError(err, req)
|
|
55
51
|
|
|
56
52
|
if (name === 'onRequest' || name === 'preParsing') {
|
|
57
53
|
const parsingResource = new AsyncResource('bound-anonymous-fn')
|
|
@@ -71,13 +67,13 @@ function wrapAddHook (addHook) {
|
|
|
71
67
|
const promise = fn.apply(this, arguments)
|
|
72
68
|
|
|
73
69
|
if (promise && typeof promise.catch === 'function') {
|
|
74
|
-
return promise.catch(err => publishError(err,
|
|
70
|
+
return promise.catch(err => publishError(err, req))
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
return promise
|
|
78
74
|
}
|
|
79
75
|
} catch (e) {
|
|
80
|
-
throw publishError(e,
|
|
76
|
+
throw publishError(e, req)
|
|
81
77
|
}
|
|
82
78
|
})
|
|
83
79
|
|
|
@@ -90,14 +86,10 @@ function onRequest (request, reply, done) {
|
|
|
90
86
|
|
|
91
87
|
const req = getReq(request)
|
|
92
88
|
const res = getRes(reply)
|
|
93
|
-
const requestResource = new AsyncResource('bound-anonymous-fn')
|
|
94
89
|
|
|
95
|
-
|
|
90
|
+
handleChannel.publish({ req, res })
|
|
96
91
|
|
|
97
|
-
return
|
|
98
|
-
handleChannel.publish({ req, res })
|
|
99
|
-
return done()
|
|
100
|
-
})
|
|
92
|
+
return done()
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
function preHandler (request, reply, done) {
|
|
@@ -105,9 +97,8 @@ function preHandler (request, reply, done) {
|
|
|
105
97
|
if (!reply || typeof reply.send !== 'function') return done()
|
|
106
98
|
|
|
107
99
|
const req = getReq(request)
|
|
108
|
-
const requestResource = requestResources.get(req)
|
|
109
100
|
|
|
110
|
-
reply.send = wrapSend(reply.send,
|
|
101
|
+
reply.send = wrapSend(reply.send, req)
|
|
111
102
|
|
|
112
103
|
done()
|
|
113
104
|
}
|
|
@@ -133,12 +124,10 @@ function preParsing (request, reply, payload, done) {
|
|
|
133
124
|
parsingResource.runInAsyncScope(() => done())
|
|
134
125
|
}
|
|
135
126
|
|
|
136
|
-
function wrapSend (send,
|
|
137
|
-
return function sendWithTrace (
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
errorChannel.publish(payload)
|
|
141
|
-
})
|
|
127
|
+
function wrapSend (send, req) {
|
|
128
|
+
return function sendWithTrace (error) {
|
|
129
|
+
if (error instanceof Error) {
|
|
130
|
+
errorChannel.publish({ req, error })
|
|
142
131
|
}
|
|
143
132
|
|
|
144
133
|
return send.apply(this, arguments)
|
|
@@ -153,11 +142,9 @@ function getRes (reply) {
|
|
|
153
142
|
return reply && (reply.raw || reply.res || reply)
|
|
154
143
|
}
|
|
155
144
|
|
|
156
|
-
function publishError (error,
|
|
145
|
+
function publishError (error, req) {
|
|
157
146
|
if (error) {
|
|
158
|
-
|
|
159
|
-
errorChannel.publish(error)
|
|
160
|
-
})
|
|
147
|
+
errorChannel.publish({ error, req })
|
|
161
148
|
}
|
|
162
149
|
|
|
163
150
|
return error
|
|
@@ -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
|
})
|
|
@@ -126,13 +126,13 @@ function wrapMiddleware (fn, layer) {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
function fulfill (ctx, error) {
|
|
129
|
-
if (error) {
|
|
130
|
-
errorChannel.publish(error)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
129
|
const req = ctx.req
|
|
134
130
|
const route = ctx.routePath
|
|
135
131
|
|
|
132
|
+
if (error) {
|
|
133
|
+
errorChannel.publish({ req, error })
|
|
134
|
+
}
|
|
135
|
+
|
|
136
136
|
// TODO: make sure that the parent class cannot override this in `enter`
|
|
137
137
|
if (route) {
|
|
138
138
|
routeChannel.publish({ req, route })
|