-
Notifications
You must be signed in to change notification settings - Fork 404
/
Copy pathexpress.js
176 lines (155 loc) · 4.73 KB
/
express.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
* Copyright 2020 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
'use strict'
const { MiddlewareSpec, MiddlewareMounterSpec, RenderSpec } = require('../../lib/shim/specs')
/**
* Express middleware generates traces where middleware are considered siblings
* (ended on 'next' invocation) and not nested. Middleware are nested below the
* routers they are mounted to.
*/
module.exports = function initialize(agent, express, moduleName, shim) {
if (!express || !express.Router) {
shim.logger.debug('Could not find Express Router, not instrumenting.')
return false
}
shim.setFramework(shim.EXPRESS)
shim.setErrorPredicate(function expressErrorPredicate(err) {
return err !== 'route' && err !== 'router'
})
shim.wrapMiddlewareMounter(
express.application,
'use',
new MiddlewareMounterSpec({
route: shim.FIRST,
wrapper: wrapMiddleware
})
)
wrapExpressRouter(shim, express.Router.use ? express.Router : express.Router.prototype)
wrapResponse(shim, express.response)
}
function wrapExpressRouter(shim, router) {
shim.wrapMiddlewareMounter(
router,
'use',
new MiddlewareMounterSpec({
route: shim.FIRST,
wrapper: wrapMiddleware
})
)
shim.wrap(router, 'route', function wrapRoute(shim, fn) {
if (!shim.isFunction(fn)) {
return fn
}
return function wrappedRoute() {
const route = fn.apply(this, arguments)
// Express should create a new route and layer every time Router#route is
// called, but just to be on the safe side, make sure we haven't wrapped
// this already.
if (!shim.isWrapped(route, 'get')) {
wrapRouteMethods(shim, route, '')
const layer = this.stack[this.stack.length - 1]
// This wraps a 'done' function but not a traditional 'next' function. This allows
// the route to stay on the stack for middleware nesting after the router.
// The segment will be automatically ended by the http/https instrumentation.
shim.recordMiddleware(
layer,
'handle',
new MiddlewareSpec({
type: shim.ROUTE,
req: shim.FIRST,
next: shim.LAST,
matchArity: true,
route: route.path
})
)
}
return route
}
})
shim.wrapMiddlewareMounter(
router,
'param',
new MiddlewareMounterSpec({
route: shim.FIRST,
wrapper: function wrapParamware(shim, middleware, fnName, route) {
return shim.recordParamware(
middleware,
new MiddlewareSpec({
name: route,
req: shim.FIRST,
next: shim.THIRD
})
)
}
})
)
}
function wrapRouteMethods(shim, route, path) {
const methods = ['all', 'delete', 'get', 'head', 'opts', 'post', 'put', 'patch']
shim.wrapMiddlewareMounter(
route,
methods,
new MiddlewareMounterSpec({ route: path, wrapper: wrapMiddleware })
)
}
function wrapResponse(shim, response) {
shim.recordRender(
response,
'render',
new RenderSpec({
view: shim.FIRST,
callback: function bindCallback(shim, render, name, segment, args) {
let cbIdx = shim.normalizeIndex(args.length, shim.LAST)
if (cbIdx === null) {
return
}
const res = this
let cb = args[cbIdx]
if (!shim.isFunction(cb)) {
++cbIdx
cb = function defaultRenderCB(err, str) {
// https://github.com/expressjs/express/blob/4.x/lib/response.js#L961-L962
if (err) {
return res.req.next(err)
}
res.send(str)
}
args.push(cb)
}
args[cbIdx] = shim.bindSegment(cb, segment, true)
}
})
)
}
function wrapMiddleware(shim, middleware, name, route) {
let method = null
const spec = new MiddlewareSpec({
route,
type: shim.MIDDLEWARE,
matchArity: true,
req: shim.FIRST
})
if (middleware.lazyrouter) {
method = 'handle'
spec.type = shim.APPLICATION
} else if (middleware.stack) {
method = 'handle'
spec.type = shim.ROUTER
} else if (middleware.length === 4) {
spec.type = shim.ERRORWARE
spec.req = shim.SECOND
}
// Express apps just pass their middleware through to their router. We do not
// want to count the same middleware twice, so we check if it has already been
// wrapped. Express also wraps apps mounted on apps, so we need to check if
// this middleware is that app wrapper.
//
// NOTE: Express did not name its app wrapper until 4.6.0.
if (shim.isWrapped(middleware, method) || name === 'mounted_app') {
// Don't double-wrap middleware
return middleware
}
return shim.recordMiddleware(middleware, method, spec)
}