1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
import { Integration , Transaction } from '@sentry/types' ;
3
2
import { logger } from '@sentry/utils' ;
4
3
@@ -30,27 +29,13 @@ type Method =
30
29
| 'use' ;
31
30
32
31
type Router = {
33
- [ method in Method ] : ( ...args : any ) => any ;
32
+ [ method in Method ] : ( ...args : unknown [ ] ) => unknown ;
34
33
} ;
35
34
36
- type ErrorRequestHandler = ( ...args : any ) => any ;
37
- type RequestHandler = ( ...args : any ) => any ;
38
- type NextFunction = ( ...args : any ) => any ;
39
-
40
- interface Response {
35
+ interface ExpressResponse {
41
36
once ( name : string , callback : ( ) => void ) : void ;
42
37
}
43
38
44
- interface Request {
45
- route ?: {
46
- path : string ;
47
- } ;
48
- method : string ;
49
- originalUrl : string ;
50
- baseUrl : string ;
51
- query : string ;
52
- }
53
-
54
39
/**
55
40
* Internal helper for `__sentry_transaction`
56
41
* @hidden
@@ -62,8 +47,7 @@ interface SentryTracingResponse {
62
47
/**
63
48
* Express integration
64
49
*
65
- * Provides an request and error handler for Express framework
66
- * as well as tracing capabilities
50
+ * Provides an request and error handler for Express framework as well as tracing capabilities
67
51
*/
68
52
export class Express implements Integration {
69
53
/**
@@ -79,26 +63,26 @@ export class Express implements Integration {
79
63
/**
80
64
* Express App instance
81
65
*/
82
- private readonly _app ?: Router ;
66
+ private readonly _router ?: Router ;
83
67
private readonly _methods ?: Method [ ] ;
84
68
85
69
/**
86
70
* @inheritDoc
87
71
*/
88
- public constructor ( options : { app ?: Router ; methods ?: Method [ ] } = { } ) {
89
- this . _app = options . app ;
72
+ public constructor ( options : { app ?: Router ; router ?: Router ; methods ?: Method [ ] } = { } ) {
73
+ this . _router = options . router || options . app ;
90
74
this . _methods = ( Array . isArray ( options . methods ) ? options . methods : [ ] ) . concat ( 'use' ) ;
91
75
}
92
76
93
77
/**
94
78
* @inheritDoc
95
79
*/
96
80
public setupOnce ( ) : void {
97
- if ( ! this . _app ) {
81
+ if ( ! this . _router ) {
98
82
logger . error ( 'ExpressIntegration is missing an Express instance' ) ;
99
83
return ;
100
84
}
101
- instrumentMiddlewares ( this . _app , this . _methods ) ;
85
+ instrumentMiddlewares ( this . _router , this . _methods ) ;
102
86
}
103
87
}
104
88
@@ -113,16 +97,17 @@ export class Express implements Integration {
113
97
* app.use(function (req, res, next) { ... })
114
98
* // error handler
115
99
* app.use(function (err, req, res, next) { ... })
100
+ *
101
+ * They all internally delegate to the `router[method]` of the given application instance.
116
102
*/
117
- // eslint-disable-next-line @typescript-eslint/ban-types
118
- function wrap ( fn : Function , method : Method ) : RequestHandler | ErrorRequestHandler {
103
+ // eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any
104
+ function wrap ( fn : Function , method : Method ) : ( ... args : any [ ] ) => void {
119
105
const arity = fn . length ;
120
106
121
107
switch ( arity ) {
122
108
case 2 : {
123
- return function ( this : NodeJS . Global , req : Request , res : Response & SentryTracingResponse ) : any {
109
+ return function ( this : NodeJS . Global , req : unknown , res : ExpressResponse & SentryTracingResponse ) : void {
124
110
const transaction = res . __sentry_transaction ;
125
- addExpressReqToTransaction ( transaction , req ) ;
126
111
if ( transaction ) {
127
112
const span = transaction . startChild ( {
128
113
description : fn . name ,
@@ -132,56 +117,43 @@ function wrap(fn: Function, method: Method): RequestHandler | ErrorRequestHandle
132
117
span . finish ( ) ;
133
118
} ) ;
134
119
}
135
- // eslint-disable-next-line prefer-rest-params
136
- return fn . apply ( this , arguments ) ;
120
+ return fn . call ( this , req , res ) ;
137
121
} ;
138
122
}
139
123
case 3 : {
140
124
return function (
141
125
this : NodeJS . Global ,
142
- req : Request ,
143
- res : Response & SentryTracingResponse ,
144
- next : NextFunction ,
145
- ) : any {
126
+ req : unknown ,
127
+ res : ExpressResponse & SentryTracingResponse ,
128
+ next : ( ) => void ,
129
+ ) : void {
146
130
const transaction = res . __sentry_transaction ;
147
- addExpressReqToTransaction ( transaction , req ) ;
148
- const span =
149
- transaction &&
150
- transaction . startChild ( {
151
- description : fn . name ,
152
- op : `middleware.${ method } ` ,
153
- } ) ;
154
- fn . call ( this , req , res , function ( this : NodeJS . Global ) : any {
155
- if ( span ) {
156
- span . finish ( ) ;
157
- }
158
- // eslint-disable-next-line prefer-rest-params
159
- return next . apply ( this , arguments ) ;
131
+ const span = transaction ?. startChild ( {
132
+ description : fn . name ,
133
+ op : `middleware.${ method } ` ,
134
+ } ) ;
135
+ fn . call ( this , req , res , function ( this : NodeJS . Global , ...args : unknown [ ] ) : void {
136
+ span ?. finish ( ) ;
137
+ next . call ( this , ...args ) ;
160
138
} ) ;
161
139
} ;
162
140
}
163
141
case 4 : {
164
142
return function (
165
143
this : NodeJS . Global ,
166
- err : any ,
144
+ err : Error ,
167
145
req : Request ,
168
146
res : Response & SentryTracingResponse ,
169
- next : NextFunction ,
170
- ) : any {
147
+ next : ( ) => void ,
148
+ ) : void {
171
149
const transaction = res . __sentry_transaction ;
172
- addExpressReqToTransaction ( transaction , req ) ;
173
- const span =
174
- transaction &&
175
- transaction . startChild ( {
176
- description : fn . name ,
177
- op : `middleware.${ method } ` ,
178
- } ) ;
179
- fn . call ( this , err , req , res , function ( this : NodeJS . Global ) : any {
180
- if ( span ) {
181
- span . finish ( ) ;
182
- }
183
- // eslint-disable-next-line prefer-rest-params
184
- return next . apply ( this , arguments ) ;
150
+ const span = transaction ?. startChild ( {
151
+ description : fn . name ,
152
+ op : `middleware.${ method } ` ,
153
+ } ) ;
154
+ fn . call ( this , err , req , res , function ( this : NodeJS . Global , ...args : unknown [ ] ) : void {
155
+ span ?. finish ( ) ;
156
+ next . call ( this , ...args ) ;
185
157
} ) ;
186
158
} ;
187
159
}
@@ -192,7 +164,7 @@ function wrap(fn: Function, method: Method): RequestHandler | ErrorRequestHandle
192
164
}
193
165
194
166
/**
195
- * Takes all the function arguments passed to the original `app. use` call
167
+ * Takes all the function arguments passed to the original `app` or `router` method, eg. `app. use` or `router.use`
196
168
* and wraps every function, as well as array of functions with a call to our `wrap` method.
197
169
* We have to take care of the arrays as well as iterate over all of the arguments,
198
170
* as `app.use` can accept middlewares in few various forms.
@@ -221,36 +193,21 @@ function wrapMiddlewareArgs(args: unknown[], method: Method): unknown[] {
221
193
}
222
194
223
195
/**
224
- * Patches original App to utilize our tracing functionality
196
+ * Patches original router to utilize our tracing functionality
225
197
*/
226
- function patchMiddleware ( app : Router , method : Method ) : Router {
227
- const originalAppCallback = app [ method ] ;
198
+ function patchMiddleware ( router : Router , method : Method ) : Router {
199
+ const originalCallback = router [ method ] ;
228
200
229
- app [ method ] = function ( ...args : unknown [ ] ) : any {
230
- return originalAppCallback . apply ( this , wrapMiddlewareArgs ( args , method ) ) ;
201
+ router [ method ] = function ( ...args : unknown [ ] ) : void {
202
+ return originalCallback . call ( this , ... wrapMiddlewareArgs ( args , method ) ) ;
231
203
} ;
232
204
233
- return app ;
205
+ return router ;
234
206
}
235
207
236
208
/**
237
- * Patches original application methods
209
+ * Patches original router methods
238
210
*/
239
- function instrumentMiddlewares ( app : Router , methods : Method [ ] = [ ] ) : void {
240
- methods . forEach ( ( method : Method ) => patchMiddleware ( app , method ) ) ;
241
- }
242
-
243
- /**
244
- * Set parameterized as transaction name e.g.: `GET /users/:id`
245
- * Also adds more context data on the transaction from the request
246
- */
247
- function addExpressReqToTransaction ( transaction : Transaction | undefined , req : Request ) : void {
248
- if ( transaction ) {
249
- if ( req . route && req . route . path ) {
250
- transaction . name = `${ req . method } ${ req . route . path } ` ;
251
- }
252
- transaction . setData ( 'url' , req . originalUrl ) ;
253
- transaction . setData ( 'baseUrl' , req . baseUrl ) ;
254
- transaction . setData ( 'query' , req . query ) ;
255
- }
211
+ function instrumentMiddlewares ( router : Router , methods : Method [ ] = [ ] ) : void {
212
+ methods . forEach ( ( method : Method ) => patchMiddleware ( router , method ) ) ;
256
213
}
0 commit comments