1- /* eslint-disable @typescript-eslint/no-explicit-any */
21import { Integration , Transaction } from '@sentry/types' ;
32import { logger } from '@sentry/utils' ;
43
@@ -30,27 +29,13 @@ type Method =
3029 | 'use' ;
3130
3231type Router = {
33- [ method in Method ] : ( ...args : any ) => any ;
32+ [ method in Method ] : ( ...args : unknown [ ] ) => unknown ;
3433} ;
3534
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 {
4136 once ( name : string , callback : ( ) => void ) : void ;
4237}
4338
44- interface Request {
45- route ?: {
46- path : string ;
47- } ;
48- method : string ;
49- originalUrl : string ;
50- baseUrl : string ;
51- query : string ;
52- }
53-
5439/**
5540 * Internal helper for `__sentry_transaction`
5641 * @hidden
@@ -62,8 +47,7 @@ interface SentryTracingResponse {
6247/**
6348 * Express integration
6449 *
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
6751 */
6852export class Express implements Integration {
6953 /**
@@ -79,26 +63,26 @@ export class Express implements Integration {
7963 /**
8064 * Express App instance
8165 */
82- private readonly _app ?: Router ;
66+ private readonly _router ?: Router ;
8367 private readonly _methods ?: Method [ ] ;
8468
8569 /**
8670 * @inheritDoc
8771 */
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 ;
9074 this . _methods = ( Array . isArray ( options . methods ) ? options . methods : [ ] ) . concat ( 'use' ) ;
9175 }
9276
9377 /**
9478 * @inheritDoc
9579 */
9680 public setupOnce ( ) : void {
97- if ( ! this . _app ) {
81+ if ( ! this . _router ) {
9882 logger . error ( 'ExpressIntegration is missing an Express instance' ) ;
9983 return ;
10084 }
101- instrumentMiddlewares ( this . _app , this . _methods ) ;
85+ instrumentMiddlewares ( this . _router , this . _methods ) ;
10286 }
10387}
10488
@@ -113,16 +97,17 @@ export class Express implements Integration {
11397 * app.use(function (req, res, next) { ... })
11498 * // error handler
11599 * app.use(function (err, req, res, next) { ... })
100+ *
101+ * They all internally delegate to the `router[method]` of the given application instance.
116102 */
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 {
119105 const arity = fn . length ;
120106
121107 switch ( arity ) {
122108 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 {
124110 const transaction = res . __sentry_transaction ;
125- addExpressReqToTransaction ( transaction , req ) ;
126111 if ( transaction ) {
127112 const span = transaction . startChild ( {
128113 description : fn . name ,
@@ -132,56 +117,43 @@ function wrap(fn: Function, method: Method): RequestHandler | ErrorRequestHandle
132117 span . finish ( ) ;
133118 } ) ;
134119 }
135- // eslint-disable-next-line prefer-rest-params
136- return fn . apply ( this , arguments ) ;
120+ return fn . call ( this , req , res ) ;
137121 } ;
138122 }
139123 case 3 : {
140124 return function (
141125 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 {
146130 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 ) ;
160138 } ) ;
161139 } ;
162140 }
163141 case 4 : {
164142 return function (
165143 this : NodeJS . Global ,
166- err : any ,
144+ err : Error ,
167145 req : Request ,
168146 res : Response & SentryTracingResponse ,
169- next : NextFunction ,
170- ) : any {
147+ next : ( ) => void ,
148+ ) : void {
171149 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 ) ;
185157 } ) ;
186158 } ;
187159 }
@@ -192,7 +164,7 @@ function wrap(fn: Function, method: Method): RequestHandler | ErrorRequestHandle
192164}
193165
194166/**
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`
196168 * and wraps every function, as well as array of functions with a call to our `wrap` method.
197169 * We have to take care of the arrays as well as iterate over all of the arguments,
198170 * as `app.use` can accept middlewares in few various forms.
@@ -221,36 +193,21 @@ function wrapMiddlewareArgs(args: unknown[], method: Method): unknown[] {
221193}
222194
223195/**
224- * Patches original App to utilize our tracing functionality
196+ * Patches original router to utilize our tracing functionality
225197 */
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 ] ;
228200
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 ) ) ;
231203 } ;
232204
233- return app ;
205+ return router ;
234206}
235207
236208/**
237- * Patches original application methods
209+ * Patches original router methods
238210 */
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 ) ) ;
256213}
0 commit comments