dd-trace 2.10.0 → 2.11.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.
Files changed (32) hide show
  1. package/package.json +2 -2
  2. package/packages/datadog-instrumentations/index.js +4 -0
  3. package/packages/datadog-instrumentations/src/connect.js +3 -0
  4. package/packages/datadog-instrumentations/src/fastify.js +5 -3
  5. package/packages/datadog-instrumentations/src/graphql.js +6 -4
  6. package/packages/datadog-instrumentations/src/grpc/client.js +250 -0
  7. package/packages/datadog-instrumentations/src/grpc/server.js +144 -0
  8. package/packages/{datadog-plugin-grpc/src/kinds.js → datadog-instrumentations/src/grpc/types.js} +0 -0
  9. package/packages/datadog-instrumentations/src/grpc.js +4 -0
  10. package/packages/datadog-instrumentations/src/http2/client.js +67 -0
  11. package/packages/datadog-instrumentations/src/http2/server.js +3 -0
  12. package/packages/datadog-instrumentations/src/http2.js +4 -0
  13. package/packages/datadog-instrumentations/src/koa.js +11 -2
  14. package/packages/datadog-instrumentations/src/microgateway-core.js +66 -0
  15. package/packages/datadog-instrumentations/src/mocha.js +129 -63
  16. package/packages/datadog-instrumentations/src/next.js +140 -0
  17. package/packages/datadog-instrumentations/src/router.js +3 -0
  18. package/packages/datadog-plugin-graphql/src/resolve.js +12 -17
  19. package/packages/datadog-plugin-grpc/src/client.js +54 -283
  20. package/packages/datadog-plugin-grpc/src/index.js +31 -3
  21. package/packages/datadog-plugin-grpc/src/server.js +50 -145
  22. package/packages/datadog-plugin-http2/src/client.js +72 -120
  23. package/packages/datadog-plugin-http2/src/index.js +32 -3
  24. package/packages/datadog-plugin-http2/src/server.js +6 -214
  25. package/packages/datadog-plugin-microgateway-core/src/index.js +14 -145
  26. package/packages/datadog-plugin-mocha/src/index.js +8 -36
  27. package/packages/datadog-plugin-next/src/index.js +56 -168
  28. package/packages/datadog-plugin-router/src/index.js +7 -3
  29. package/packages/dd-trace/src/config.js +2 -1
  30. package/packages/dd-trace/src/opentracing/span.js +6 -3
  31. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  32. package/packages/dd-trace/src/plugins/util/web.js +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -58,7 +58,7 @@
58
58
  "node": ">=12"
59
59
  },
60
60
  "dependencies": {
61
- "@datadog/native-appsec": "^1.2.0",
61
+ "@datadog/native-appsec": "^1.2.1",
62
62
  "@datadog/native-metrics": "^1.4.0",
63
63
  "@datadog/pprof": "^0.5.1",
64
64
  "@datadog/sketches-js": "^1.0.5",
@@ -17,14 +17,17 @@ require('./src/find-my-way')
17
17
  require('./src/generic-pool')
18
18
  require('./src/google-cloud-pubsub')
19
19
  require('./src/graphql')
20
+ require('./src/grpc')
20
21
  require('./src/hapi')
21
22
  require('./src/http')
23
+ require('./src/http2')
22
24
  require('./src/ioredis')
23
25
  require('./src/jest')
24
26
  require('./src/kafkajs')
25
27
  require('./src/knex')
26
28
  require('./src/koa')
27
29
  require('./src/memcached')
30
+ require('./src/microgateway-core')
28
31
  require('./src/moleculer')
29
32
  require('./src/mongodb-core')
30
33
  require('./src/mongoose')
@@ -32,6 +35,7 @@ require('./src/mysql')
32
35
  require('./src/mysql2')
33
36
  require('./src/mocha')
34
37
  require('./src/net')
38
+ require('./src/next')
35
39
  require('./src/oracledb')
36
40
  require('./src/paperplane')
37
41
  require('./src/pino')
@@ -4,6 +4,7 @@ const shimmer = require('../../datadog-shimmer')
4
4
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
5
 
6
6
  const enterChannel = channel('apm:connect:middleware:enter')
7
+ const exitChannel = channel('apm:connect:middleware:exit')
7
8
  const errorChannel = channel('apm:connect:middleware:error')
8
9
  const nextChannel = channel('apm:connect:middleware:next')
9
10
  const handleChannel = channel('apm:connect:request:handle')
@@ -80,6 +81,7 @@ function wrapLayerHandle (layer) {
80
81
  } catch (e) {
81
82
  errorChannel.publish(e)
82
83
  nextChannel.publish({ req })
84
+ exitChannel.publish({ req })
83
85
 
84
86
  throw e
85
87
  }
@@ -94,6 +96,7 @@ function wrapNext (req, next) {
94
96
  }
95
97
 
96
98
  nextChannel.publish({ req })
99
+ exitChannel.publish({ req })
97
100
 
98
101
  next.apply(null, arguments)
99
102
  }
@@ -154,9 +154,11 @@ function getRes (reply) {
154
154
  }
155
155
 
156
156
  function publishError (error, resource) {
157
- resource.runInAsyncScope(() => {
158
- errorChannel.publish(error)
159
- })
157
+ if (error) {
158
+ resource.runInAsyncScope(() => {
159
+ errorChannel.publish(error)
160
+ })
161
+ }
160
162
 
161
163
  return error
162
164
  }
@@ -195,9 +195,7 @@ function wrapResolve (resolve) {
195
195
 
196
196
  if (!context) return resolve.apply(this, arguments)
197
197
 
198
- const path = pathToArray(info && info.path)
199
-
200
- const field = assertField(context, info, path)
198
+ const field = assertField(context, info)
201
199
 
202
200
  return callInAsyncScope(resolve, field.asyncResource, this, arguments, (err) => {
203
201
  updateFieldCh.publish({ field, info, err })
@@ -242,7 +240,11 @@ function pathToArray (path) {
242
240
  return flattened.reverse()
243
241
  }
244
242
 
245
- function assertField (context, info, path) {
243
+ function assertField (context, info) {
244
+ const pathInfo = info && info.path
245
+
246
+ const path = pathToArray(pathInfo)
247
+
246
248
  const pathString = path.join('.')
247
249
  const fields = context.fields
248
250
 
@@ -0,0 +1,250 @@
1
+ 'use strict'
2
+
3
+ const types = require('./types')
4
+ const { addHook, channel, AsyncResource } = require('../helpers/instrument')
5
+ const shimmer = require('../../../datadog-shimmer')
6
+
7
+ const patched = new WeakSet()
8
+ const instances = new WeakMap()
9
+
10
+ const startChannel = channel('apm:grpc:client:request:start')
11
+ const errorChannel = channel('apm:grpc:client:request:error')
12
+ const finishChannel = channel('apm:grpc:client:request:finish')
13
+
14
+ function createWrapMakeRequest (type) {
15
+ return function wrapMakeRequest (makeRequest) {
16
+ return function (path) {
17
+ const args = ensureMetadata(this, arguments, 4)
18
+
19
+ return callMethod(this, makeRequest, args, path, args[4], type)
20
+ }
21
+ }
22
+ }
23
+
24
+ function createWrapLoadPackageDefinition () {
25
+ return function wrapLoadPackageDefinition (loadPackageDefinition) {
26
+ return function (packageDef) {
27
+ const result = loadPackageDefinition.apply(this, arguments)
28
+
29
+ if (!result) return result
30
+
31
+ wrapPackageDefinition(result)
32
+
33
+ return result
34
+ }
35
+ }
36
+ }
37
+
38
+ function createWrapMakeClientConstructor () {
39
+ return function wrapMakeClientConstructor (makeClientConstructor) {
40
+ return function (methods) {
41
+ const ServiceClient = makeClientConstructor.apply(this, arguments)
42
+
43
+ wrapClientConstructor(ServiceClient, methods)
44
+
45
+ return ServiceClient
46
+ }
47
+ }
48
+ }
49
+
50
+ function wrapPackageDefinition (def) {
51
+ for (const name in def) {
52
+ if (def[name].format) continue
53
+ if (def[name].service && def[name].prototype) {
54
+ wrapClientConstructor(def[name], def[name].service)
55
+ } else {
56
+ wrapPackageDefinition(def[name])
57
+ }
58
+ }
59
+ }
60
+
61
+ function wrapClientConstructor (ServiceClient, methods) {
62
+ const proto = ServiceClient.prototype
63
+
64
+ if (typeof methods !== 'object' || 'format' in methods) return
65
+
66
+ Object.keys(methods)
67
+ .forEach(name => {
68
+ if (!methods[name]) return
69
+
70
+ const originalName = methods[name].originalName
71
+ const path = methods[name].path
72
+ const type = getType(methods[name])
73
+
74
+ if (methods[name]) {
75
+ proto[name] = wrapMethod(proto[name], path, type)
76
+ }
77
+
78
+ if (originalName) {
79
+ proto[originalName] = wrapMethod(proto[originalName], path, type)
80
+ }
81
+ })
82
+ }
83
+
84
+ function wrapMethod (method, path, type) {
85
+ if (typeof method !== 'function' || patched.has(method)) {
86
+ return method
87
+ }
88
+
89
+ const wrapped = function () {
90
+ const args = ensureMetadata(this, arguments, 1)
91
+
92
+ return callMethod(this, method, args, path, args[1], type)
93
+ }
94
+
95
+ Object.assign(wrapped, method)
96
+
97
+ patched.add(wrapped)
98
+
99
+ return wrapped
100
+ }
101
+
102
+ function wrapCallback (requestResource, parentResource, callback) {
103
+ return function (err) {
104
+ if (err) {
105
+ requestResource.runInAsyncScope(() => {
106
+ errorChannel.publish(err)
107
+ })
108
+ }
109
+
110
+ if (callback) {
111
+ return parentResource.runInAsyncScope(() => {
112
+ return callback.apply(this, arguments)
113
+ })
114
+ }
115
+ }
116
+ }
117
+
118
+ function wrapStream (call, requestResource, parentResource) {
119
+ if (!call || typeof call.emit !== 'function') return
120
+
121
+ shimmer.wrap(call, 'emit', emit => {
122
+ return function (eventName, ...args) {
123
+ requestResource.runInAsyncScope(() => {
124
+ switch (eventName) {
125
+ case 'error':
126
+ errorChannel.publish(args[0])
127
+
128
+ break
129
+ case 'status':
130
+ finishChannel.publish(args[0])
131
+
132
+ break
133
+ }
134
+ })
135
+
136
+ return parentResource.runInAsyncScope(() => {
137
+ return emit.apply(this, arguments)
138
+ })
139
+ }
140
+ })
141
+ }
142
+
143
+ function callMethod (client, method, args, path, metadata, type) {
144
+ if (!startChannel.hasSubscribers) return method.apply(client, args)
145
+
146
+ const length = args.length
147
+ const callback = args[length - 1]
148
+ const parentResource = new AsyncResource('bound-anonymous-fn')
149
+ const requestResource = new AsyncResource('bound-anonymous-fn')
150
+
151
+ return requestResource.runInAsyncScope(() => {
152
+ startChannel.publish({ metadata, path, type })
153
+
154
+ if (type === types.unary || type === types.client_stream) {
155
+ if (typeof callback === 'function') {
156
+ args[length - 1] = wrapCallback(requestResource, parentResource, callback)
157
+ } else {
158
+ args[length] = wrapCallback(requestResource, parentResource)
159
+ }
160
+ }
161
+
162
+ const call = method.apply(client, args)
163
+
164
+ wrapStream(call, requestResource, parentResource)
165
+
166
+ return call
167
+ })
168
+ }
169
+
170
+ function ensureMetadata (client, args, index) {
171
+ const grpc = getGrpc(client)
172
+
173
+ if (!client || !grpc) return args
174
+
175
+ const meta = args[index]
176
+ const normalized = []
177
+
178
+ for (let i = 0; i < index; i++) {
179
+ normalized.push(args[i])
180
+ }
181
+
182
+ if (!meta || !meta.constructor || meta.constructor.name !== 'Metadata') {
183
+ normalized.push(new grpc.Metadata())
184
+ }
185
+
186
+ if (meta) {
187
+ normalized.push(meta)
188
+ }
189
+
190
+ for (let i = index + 1; i < args.length; i++) {
191
+ normalized.push(args[i])
192
+ }
193
+
194
+ return normalized
195
+ }
196
+
197
+ function getType (definition) {
198
+ if (definition.requestStream) {
199
+ if (definition.responseStream) {
200
+ return types.bidi
201
+ }
202
+
203
+ return types.client_stream
204
+ }
205
+
206
+ if (definition.responseStream) {
207
+ return types.server_stream
208
+ }
209
+
210
+ return types.unary
211
+ }
212
+
213
+ function getGrpc (client) {
214
+ let proto = client
215
+
216
+ do {
217
+ const instance = instances.get(proto)
218
+ if (instance) return instance
219
+ } while ((proto = Object.getPrototypeOf(proto)))
220
+ }
221
+
222
+ function patch (grpc) {
223
+ const proto = grpc.Client.prototype
224
+
225
+ instances.set(proto, grpc)
226
+
227
+ shimmer.wrap(proto, 'makeBidiStreamRequest', createWrapMakeRequest(types.bidi))
228
+ shimmer.wrap(proto, 'makeClientStreamRequest', createWrapMakeRequest(types.clientStream))
229
+ shimmer.wrap(proto, 'makeServerStreamRequest', createWrapMakeRequest(types.serverStream))
230
+ shimmer.wrap(proto, 'makeUnaryRequest', createWrapMakeRequest(types.unary))
231
+
232
+ return grpc
233
+ }
234
+
235
+ addHook({ name: 'grpc', versions: ['>=1.20.2'] }, patch)
236
+
237
+ addHook({ name: 'grpc', versions: ['>=1.20.2'], file: 'src/client.js' }, client => {
238
+ shimmer.wrap(client, 'makeClientConstructor', createWrapMakeClientConstructor())
239
+
240
+ return client
241
+ })
242
+
243
+ addHook({ name: '@grpc/grpc-js', versions: ['>=1.0.3'] }, patch)
244
+
245
+ addHook({ name: '@grpc/grpc-js', versions: ['>=1.0.3'], file: 'build/src/make-client.js' }, client => {
246
+ shimmer.wrap(client, 'makeClientConstructor', createWrapMakeClientConstructor())
247
+ shimmer.wrap(client, 'loadPackageDefinition', createWrapLoadPackageDefinition())
248
+
249
+ return client
250
+ })
@@ -0,0 +1,144 @@
1
+ 'use strict'
2
+
3
+ const types = require('./types')
4
+ const { channel, addHook, AsyncResource } = require('../helpers/instrument')
5
+ const shimmer = require('../../../datadog-shimmer')
6
+
7
+ const startChannel = channel('apm:grpc:server:request:start')
8
+ const errorChannel = channel('apm:grpc:server:request:error')
9
+ const updateChannel = channel('apm:grpc:server:request:update')
10
+ const finishChannel = channel('apm:grpc:server:request:finish')
11
+
12
+ // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
13
+ const OK = 0
14
+ const CANCELLED = 1
15
+
16
+ function wrapHandler (func, name) {
17
+ const isValid = (server, args) => {
18
+ if (!startChannel.hasSubscribers) return false
19
+ if (!server || !server.type) return false
20
+ if (!args[0]) return false
21
+ if (server.type !== 'unary' && !isEmitter(args[0])) return false
22
+ if (server.type === 'unary' && typeof args[1] !== 'function') return false
23
+
24
+ return true
25
+ }
26
+
27
+ return function (call, callback) {
28
+ if (!isValid(this, arguments)) return func.apply(this, arguments)
29
+
30
+ const metadata = call.metadata
31
+ const type = types[this.type]
32
+ const isStream = type !== 'unary'
33
+
34
+ const parentResource = new AsyncResource('bound-anonymous-fn')
35
+ const requestResource = new AsyncResource('bound-anonymous-fn')
36
+
37
+ return requestResource.runInAsyncScope(() => {
38
+ startChannel.publish({ name, metadata, type })
39
+
40
+ // Finish the span if the call was cancelled.
41
+ call.once('cancelled', requestResource.bind(() => {
42
+ finishChannel.publish({ code: CANCELLED })
43
+ }))
44
+
45
+ if (isStream) {
46
+ wrapStream(call, requestResource, parentResource)
47
+ } else {
48
+ arguments[1] = wrapCallback(callback, requestResource, parentResource)
49
+ }
50
+
51
+ shimmer.wrap(call, 'emit', emit => requestResource.bind(emit))
52
+
53
+ return func.apply(this, arguments)
54
+ })
55
+ }
56
+ }
57
+
58
+ function wrapRegister (register) {
59
+ return function (name, handler, serialize, deserialize, type) {
60
+ if (typeof handler === 'function') {
61
+ arguments[1] = wrapHandler(handler, name)
62
+ }
63
+
64
+ return register.apply(this, arguments)
65
+ }
66
+ }
67
+
68
+ function wrapStream (call, requestResource) {
69
+ if (call.call && call.call.sendStatus) {
70
+ call.call.sendStatus = wrapSendStatus(call.call.sendStatus, requestResource)
71
+ }
72
+
73
+ shimmer.wrap(call, 'emit', emit => {
74
+ return function (eventName, ...args) {
75
+ switch (eventName) {
76
+ case 'error':
77
+ errorChannel.publish(args[0])
78
+ finishChannel.publish({ code: args[0].code })
79
+
80
+ break
81
+
82
+ // Finish the span of the response only if it was successful.
83
+ // Otherwise it'll be finished in the `error` listener.
84
+ case 'finish':
85
+ if (call.status) {
86
+ updateChannel.publish(call.status)
87
+ }
88
+
89
+ if (!call.status || call.status.code === 0) {
90
+ finishChannel.publish()
91
+ }
92
+
93
+ break
94
+ }
95
+
96
+ return emit.apply(this, arguments)
97
+ }
98
+ })
99
+ }
100
+
101
+ function wrapCallback (callback, requestResource, parentResource) {
102
+ return function (err, value, trailer, flags) {
103
+ requestResource.runInAsyncScope(() => {
104
+ if (err instanceof Error) {
105
+ errorChannel.publish(err)
106
+ finishChannel.publish(err)
107
+ } else {
108
+ finishChannel.publish({ code: OK, trailer })
109
+ }
110
+ })
111
+
112
+ if (callback) {
113
+ return parentResource.runInAsyncScope(() => {
114
+ return callback.apply(this, arguments)
115
+ })
116
+ }
117
+ }
118
+ }
119
+
120
+ function wrapSendStatus (sendStatus, requestResource) {
121
+ return function (status) {
122
+ requestResource.runInAsyncScope(() => {
123
+ updateChannel.publish(status)
124
+ })
125
+
126
+ return sendStatus.apply(this, arguments)
127
+ }
128
+ }
129
+
130
+ function isEmitter (obj) {
131
+ return typeof obj.emit === 'function' && typeof obj.once === 'function'
132
+ }
133
+
134
+ addHook({ name: 'grpc', versions: ['>=1.20.2'], file: 'src/server.js' }, server => {
135
+ shimmer.wrap(server.Server.prototype, 'register', wrapRegister)
136
+
137
+ return server
138
+ })
139
+
140
+ addHook({ name: '@grpc/grpc-js', versions: ['>=1.0.3'], file: 'build/src/server.js' }, server => {
141
+ shimmer.wrap(server.Server.prototype, 'register', wrapRegister)
142
+
143
+ return server
144
+ })
@@ -0,0 +1,4 @@
1
+ 'use strict'
2
+
3
+ require('./grpc/client')
4
+ require('./grpc/server')
@@ -0,0 +1,67 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../../datadog-shimmer')
4
+ const { addHook, channel, AsyncResource } = require('../helpers/instrument')
5
+
6
+ const startChannel = channel('apm:http2:client:request:start')
7
+ const finishChannel = channel('apm:http2:client:request:finish')
8
+ const errorChannel = channel('apm:http2:client:request:error')
9
+ const responseChannel = channel('apm:http2:client:response')
10
+
11
+ function createWrapEmit (requestResource, parentResource) {
12
+ return function wrapEmit (emit) {
13
+ return function (event, arg1) {
14
+ requestResource.runInAsyncScope(() => {
15
+ switch (event) {
16
+ case 'response':
17
+ responseChannel.publish(arg1)
18
+ break
19
+ case 'error':
20
+ errorChannel.publish(arg1)
21
+ case 'close': // eslint-disable-line no-fallthrough
22
+ finishChannel.publish()
23
+ break
24
+ }
25
+ })
26
+
27
+ return parentResource.runInAsyncScope(() => {
28
+ return emit.apply(this, arguments)
29
+ })
30
+ }
31
+ }
32
+ }
33
+
34
+ function createWrapRequest (authority, options) {
35
+ return function wrapRequest (request) {
36
+ return function (headers) {
37
+ const parentResource = new AsyncResource('bound-anonymous-fn')
38
+ const requestResource = new AsyncResource('bound-anonymous-fn')
39
+
40
+ return requestResource.runInAsyncScope(() => {
41
+ startChannel.publish({ headers, authority, options })
42
+
43
+ const req = request.apply(this, arguments)
44
+
45
+ shimmer.wrap(req, 'emit', createWrapEmit(requestResource, parentResource))
46
+
47
+ return req
48
+ })
49
+ }
50
+ }
51
+ }
52
+
53
+ function wrapConnect (connect) {
54
+ return function (authority, options) {
55
+ const session = connect.apply(this, arguments)
56
+
57
+ shimmer.wrap(session, 'request', createWrapRequest(authority, options))
58
+
59
+ return session
60
+ }
61
+ }
62
+
63
+ addHook({ name: 'http2' }, http2 => {
64
+ shimmer.wrap(http2, 'connect', wrapConnect)
65
+
66
+ return http2
67
+ })
@@ -0,0 +1,3 @@
1
+ 'use strict'
2
+
3
+ // Instrumentation temporarily disabled. See https://github.com/DataDog/dd-trace-js/issues/312
@@ -0,0 +1,4 @@
1
+ 'use strict'
2
+
3
+ require('./http2/client')
4
+ require('./http2/server')
@@ -4,6 +4,7 @@ const shimmer = require('../../datadog-shimmer')
4
4
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
5
 
6
6
  const enterChannel = channel('apm:koa:middleware:enter')
7
+ const exitChannel = channel('apm:koa:middleware:exit')
7
8
  const errorChannel = channel('apm:koa:middleware:error')
8
9
  const nextChannel = channel('apm:koa:middleware:next')
9
10
  const handleChannel = channel('apm:koa:request:handle')
@@ -95,7 +96,7 @@ function wrapMiddleware (fn, layer) {
95
96
  enterChannel.publish({ req, name, route })
96
97
 
97
98
  if (typeof next === 'function') {
98
- arguments[1] = next
99
+ arguments[1] = wrapNext(req, next)
99
100
  }
100
101
 
101
102
  try {
@@ -137,7 +138,15 @@ function fulfill (ctx, error) {
137
138
  routeChannel.publish({ req, route })
138
139
  }
139
140
 
140
- nextChannel.publish(ctx)
141
+ exitChannel.publish({ req })
142
+ }
143
+
144
+ function wrapNext (req, next) {
145
+ return function () {
146
+ nextChannel.publish({ req })
147
+
148
+ return next.apply(null, arguments)
149
+ }
141
150
  }
142
151
 
143
152
  addHook({ name: 'koa', versions: ['>=2'] }, Koa => {
@@ -0,0 +1,66 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
+
6
+ const handleChannel = channel('apm:microgateway-core:request:handle')
7
+ const routeChannel = channel('apm:microgateway-core:request:route')
8
+ const errorChannel = channel('apm:microgateway-core:request:error')
9
+
10
+ const name = 'microgateway-core'
11
+ const versions = ['>=2.1']
12
+ const requestResources = new WeakMap()
13
+
14
+ function wrapConfigProxyFactory (configProxyFactory) {
15
+ return function () {
16
+ const configProxy = configProxyFactory.apply(this, arguments)
17
+
18
+ return function (req, res, next) {
19
+ const requestResource = new AsyncResource('bound-anonymous-fn')
20
+
21
+ requestResources.set(req, requestResource)
22
+
23
+ handleChannel.publish({ req, res })
24
+
25
+ return configProxy.apply(this, arguments)
26
+ }
27
+ }
28
+ }
29
+
30
+ function wrapPluginsFactory (pluginsFactory) {
31
+ return function (plugins) {
32
+ const pluginsMiddleware = pluginsFactory.apply(this, arguments)
33
+
34
+ return function pluginsMiddlewareWithTrace (req, res, next) {
35
+ arguments[2] = wrapNext(req, res, next)
36
+
37
+ return pluginsMiddleware.apply(this, arguments)
38
+ }
39
+ }
40
+ }
41
+
42
+ function wrapNext (req, res, next) {
43
+ return function nextWithTrace (err) {
44
+ const requestResource = requestResources.get(req)
45
+
46
+ requestResource.runInAsyncScope(() => {
47
+ if (err) {
48
+ errorChannel.publish(err)
49
+ }
50
+
51
+ if (res.proxy && res.proxy.base_path) {
52
+ routeChannel.publish({ req, res, route: res.proxy.base_path })
53
+ }
54
+ })
55
+
56
+ return next.apply(this, arguments)
57
+ }
58
+ }
59
+
60
+ addHook({ name, versions, file: 'lib/config-proxy-middleware.js' }, configProxyFactory => {
61
+ return shimmer.wrap(configProxyFactory, wrapConfigProxyFactory(configProxyFactory))
62
+ })
63
+
64
+ addHook({ name, versions, file: 'lib/plugins-middleware.js' }, pluginsFactory => {
65
+ return shimmer.wrap(pluginsFactory, wrapPluginsFactory(pluginsFactory))
66
+ })