@@ -14,21 +14,28 @@ import {
1414import  *  as  domain  from  'domain' ; 
1515import  *  as  http  from  'http' ; 
1616import  *  as  os  from  'os' ; 
17- import  *  as  url  from  'url' ; 
1817
1918import  {  NodeClient  }  from  './client' ; 
2019import  {  flush  }  from  './sdk' ; 
2120
2221const  DEFAULT_SHUTDOWN_TIMEOUT  =  2000 ; 
2322
24- interface  ExpressRequest  { 
23+ interface  ExpressRequest  extends  http . IncomingMessage  { 
24+   [ key : string ] : any ; 
25+   baseUrl ?: string ; 
26+   ip ?: string ; 
27+   originalUrl ?: string ; 
2528  route ?: { 
2629    path : string ; 
30+     stack : [ 
31+       { 
32+         name : string ; 
33+       } , 
34+     ] ; 
35+   } ; 
36+   user ?: { 
37+     [ key : string ] : any ; 
2738  } ; 
28-   method : string ; 
29-   originalUrl : string ; 
30-   baseUrl : string ; 
31-   query : string ; 
3239} 
3340
3441/** 
@@ -45,19 +52,14 @@ export function tracingHandler(): (
4552    res : http . ServerResponse , 
4653    next : ( error ?: any )  =>  void , 
4754  ) : void { 
48-     // TODO: At this point `req.route.path` (which we use in `extractTransaction`) is not available 
49-     // but `req.path` or `req.url` should do the job as well. We could unify this here. 
50-     const  reqMethod  =  ( req . method  ||  '' ) . toUpperCase ( ) ; 
51-     const  reqUrl  =  req . url  &&  stripUrlQueryAndFragment ( req . url ) ; 
52- 
5355    // If there is a trace header set, we extract the data from it (parentSpanId, traceId, and sampling decision) 
5456    let  traceparentData ; 
5557    if  ( req . headers  &&  isString ( req . headers [ 'sentry-trace' ] ) )  { 
5658      traceparentData  =  extractTraceparentData ( req . headers [ 'sentry-trace' ]  as  string ) ; 
5759    } 
5860
5961    const  transaction  =  startTransaction ( { 
60-       name : ` ${ reqMethod }   ${ reqUrl } ` , 
62+       name : extractRouteInfo ( req ,   {   path :  true ,   method :  true   } ) , 
6163      op : 'http.server' , 
6264      ...traceparentData , 
6365    } ) ; 
@@ -75,7 +77,7 @@ export function tracingHandler(): (
7577    res . once ( 'finish' ,  ( )  =>  { 
7678      // We schedule the immediate execution of the `finish` to let all the spans being closed first. 
7779      setImmediate ( ( )  =>  { 
78-         addExpressReqToTransaction ( transaction ,  ( req   as   unknown )   as   ExpressRequest ) ; 
80+         addExpressReqToTransaction ( transaction ,  req ) ; 
7981        transaction . setHttpStatus ( res . statusCode ) ; 
8082        transaction . finish ( ) ; 
8183      } ) ; 
@@ -91,56 +93,56 @@ export function tracingHandler(): (
9193 */ 
9294function  addExpressReqToTransaction ( transaction : Transaction  |  undefined ,  req : ExpressRequest ) : void { 
9395  if  ( ! transaction )  return ; 
94-   if  ( req . route )  { 
95-     transaction . name  =  `${ req . method } ${ req . baseUrl } ${ req . route . path }  ; 
96-   } 
96+   transaction . name  =  extractRouteInfo ( req ,  {  path : true ,  method : true  } ) ; 
9797  transaction . setData ( 'url' ,  req . originalUrl ) ; 
9898  transaction . setData ( 'baseUrl' ,  req . baseUrl ) ; 
9999  transaction . setData ( 'query' ,  req . query ) ; 
100100} 
101101
102+ /** 
103+  * Extracts complete generalized path from the request object. 
104+  * eg. /mountpoint/user/:id 
105+  */ 
106+ function  extractRouteInfo ( req : ExpressRequest ,  options : {  path ?: boolean ;  method ?: boolean  }  =  { } ) : string  { 
107+   const  method  =  req . method ?. toUpperCase ( ) ; 
108+   let  path ; 
109+   if  ( req . baseUrl  &&  req . route )  { 
110+     path  =  `${ req . baseUrl } ${ req . route . path }  ; 
111+   }  else  if  ( req . originalUrl  ||  req . url )  { 
112+     path  =  stripUrlQueryAndFragment ( req . originalUrl  ||  req . url  ||  '' ) ; 
113+   }  else  { 
114+     path  =  req . route ?. path  ||  '' ; 
115+   } 
116+ 
117+   let  info  =  '' ; 
118+   if  ( options . method  &&  method )  { 
119+     info  +=  method ; 
120+   } 
121+   if  ( options . method  &&  options . path )  { 
122+     info  +=  ` ` ; 
123+   } 
124+   if  ( options . path  &&  path )  { 
125+     info  +=  path ; 
126+   } 
127+ 
128+   return  info ; 
129+ } 
130+ 
102131type  TransactionTypes  =  'path'  |  'methodPath'  |  'handler' ; 
103132
104133/** JSDoc */ 
105- function  extractTransaction ( req : {  [ key : string ] : any  } ,  type : boolean  |  TransactionTypes ) : string  |  undefined  { 
106-   try  { 
107-     // Express.js shape 
108-     const  request  =  req  as  { 
109-       url : string ; 
110-       originalUrl : string ; 
111-       method : string ; 
112-       route : { 
113-         path : string ; 
114-         stack : [ 
115-           { 
116-             name : string ; 
117-           } , 
118-         ] ; 
119-       } ; 
120-     } ; 
121- 
122-     let  routePath ; 
123-     try  { 
124-       routePath  =  url . parse ( request . originalUrl  ||  request . url ) . pathname ; 
125-     }  catch  ( _oO )  { 
126-       routePath  =  request . route . path ; 
134+ function  extractTransaction ( req : ExpressRequest ,  type : boolean  |  TransactionTypes ) : string  { 
135+   switch  ( type )  { 
136+     case  'path' : { 
137+       return  extractRouteInfo ( req ,  {  path : true  } ) ; 
127138    } 
128- 
129-     switch  ( type )  { 
130-       case  'path' : { 
131-         return  routePath ; 
132-       } 
133-       case  'handler' : { 
134-         return  request . route . stack [ 0 ] . name ; 
135-       } 
136-       case  'methodPath' :
137-       default : { 
138-         const  method  =  request . method . toUpperCase ( ) ; 
139-         return  `${ method } ${ routePath }  ; 
140-       } 
139+     case  'handler' : { 
140+       return  req . route ?. stack [ 0 ] . name  ||  '<anonymous>' ; 
141+     } 
142+     case  'methodPath' :
143+     default : { 
144+       return  extractRouteInfo ( req ,  {  path : true ,  method : true  } ) ; 
141145    } 
142-   }  catch  ( _oO )  { 
143-     return  undefined ; 
144146  } 
145147} 
146148
@@ -186,20 +188,7 @@ export interface ParseRequestOptions {
186188 * @param  options object containing flags to enable functionality 
187189 * @hidden  
188190 */ 
189- export  function  parseRequest ( 
190-   event : Event , 
191-   req : { 
192-     [ key : string ] : any ; 
193-     user ?: { 
194-       [ key : string ] : any ; 
195-     } ; 
196-     ip ?: string ; 
197-     connection ?: { 
198-       remoteAddress ?: string ; 
199-     } ; 
200-   } , 
201-   options ?: ParseRequestOptions , 
202- ) : Event  { 
191+ export  function  parseRequest ( event : Event ,  req : ExpressRequest ,  options ?: ParseRequestOptions ) : Event  { 
203192  // eslint-disable-next-line no-param-reassign 
204193  options  =  { 
205194    ip : false , 
@@ -261,10 +250,7 @@ export function parseRequest(
261250  } 
262251
263252  if  ( options . transaction  &&  ! event . transaction )  { 
264-     const  transaction  =  extractTransaction ( req ,  options . transaction ) ; 
265-     if  ( transaction )  { 
266-       event . transaction  =  transaction ; 
267-     } 
253+     event . transaction  =  extractTransaction ( req ,  options . transaction ) ; 
268254  } 
269255
270256  return  event ; 
0 commit comments