8
8
import { getActiveSpan , startInactiveSpan , startSpan , startSpanManual , withActiveSpan } from '@sentry/core' ;
9
9
import type { Span } from '@sentry/types' ;
10
10
import { SDK_VERSION , addNonEnumerableProperty , isThenable } from '@sentry/utils' ;
11
- import { getMiddlewareSpanOptions , instrumentObservable , isPatched } from './helpers' ;
11
+ import { getMiddlewareSpanOptions , getNextProxy , instrumentObservable , isPatched } from './helpers' ;
12
12
import type { CallHandler , CatchTarget , InjectableTarget , MinimalNestJsExecutionContext , Observable } from './types' ;
13
13
14
14
const supportedVersions = [ '>=8.0.0 <11' ] ;
@@ -101,23 +101,19 @@ export class SentryNestInstrumentation extends InstrumentationBase {
101
101
target . prototype . use = new Proxy ( target . prototype . use , {
102
102
apply : ( originalUse , thisArgUse , argsUse ) => {
103
103
const [ req , res , next , ...args ] = argsUse ;
104
- const prevSpan = getActiveSpan ( ) ;
105
104
106
- return startSpanManual ( getMiddlewareSpanOptions ( target ) , ( span : Span ) => {
107
- const nextProxy = new Proxy ( next , {
108
- apply : ( originalNext , thisArgNext , argsNext ) => {
109
- span . end ( ) ;
105
+ // Check that we can reasonably assume that the target is a middleware.
106
+ // Without these guards, instrumentation will fail if a function named 'use' on a service, which is
107
+ // decorated with @Injectable , is called.
108
+ if ( ! req || ! res || ! next || typeof next !== 'function' ) {
109
+ return originalUse . apply ( thisArgUse , argsUse ) ;
110
+ }
110
111
111
- if ( prevSpan ) {
112
- return withActiveSpan ( prevSpan , ( ) => {
113
- return Reflect . apply ( originalNext , thisArgNext , argsNext ) ;
114
- } ) ;
115
- } else {
116
- return Reflect . apply ( originalNext , thisArgNext , argsNext ) ;
117
- }
118
- } ,
119
- } ) ;
112
+ const prevSpan = getActiveSpan ( ) ;
120
113
114
+ return startSpanManual ( getMiddlewareSpanOptions ( target ) , ( span : Span ) => {
115
+ // proxy next to end span on call
116
+ const nextProxy = getNextProxy ( next , span , prevSpan ) ;
121
117
return originalUse . apply ( thisArgUse , [ req , res , nextProxy , args ] ) ;
122
118
} ) ;
123
119
} ,
@@ -133,6 +129,12 @@ export class SentryNestInstrumentation extends InstrumentationBase {
133
129
134
130
target . prototype . canActivate = new Proxy ( target . prototype . canActivate , {
135
131
apply : ( originalCanActivate , thisArgCanActivate , argsCanActivate ) => {
132
+ const context : MinimalNestJsExecutionContext = argsCanActivate [ 0 ] ;
133
+
134
+ if ( ! context ) {
135
+ return originalCanActivate . apply ( thisArgCanActivate , argsCanActivate ) ;
136
+ }
137
+
136
138
return startSpan ( getMiddlewareSpanOptions ( target ) , ( ) => {
137
139
return originalCanActivate . apply ( thisArgCanActivate , argsCanActivate ) ;
138
140
} ) ;
@@ -148,6 +150,13 @@ export class SentryNestInstrumentation extends InstrumentationBase {
148
150
149
151
target . prototype . transform = new Proxy ( target . prototype . transform , {
150
152
apply : ( originalTransform , thisArgTransform , argsTransform ) => {
153
+ const value = argsTransform [ 0 ] ;
154
+ const metadata = argsTransform [ 1 ] ;
155
+
156
+ if ( ! value || ! metadata ) {
157
+ return originalTransform . apply ( thisArgTransform , argsTransform ) ;
158
+ }
159
+
151
160
return startSpan ( getMiddlewareSpanOptions ( target ) , ( ) => {
152
161
return originalTransform . apply ( thisArgTransform , argsTransform ) ;
153
162
} ) ;
@@ -169,6 +178,11 @@ export class SentryNestInstrumentation extends InstrumentationBase {
169
178
const parentSpan = getActiveSpan ( ) ;
170
179
let afterSpan : Span ;
171
180
181
+ // Check that we can reasonably assume that the target is an interceptor.
182
+ if ( ! context || ! next || typeof next . handle !== 'function' ) {
183
+ return originalIntercept . apply ( thisArgIntercept , argsIntercept ) ;
184
+ }
185
+
172
186
return startSpanManual ( getMiddlewareSpanOptions ( target ) , ( beforeSpan : Span ) => {
173
187
// eslint-disable-next-line @typescript-eslint/unbound-method
174
188
next . handle = new Proxy ( next . handle , {
@@ -263,6 +277,13 @@ export class SentryNestInstrumentation extends InstrumentationBase {
263
277
264
278
target . prototype . catch = new Proxy ( target . prototype . catch , {
265
279
apply : ( originalCatch , thisArgCatch , argsCatch ) => {
280
+ const exception = argsCatch [ 0 ] ;
281
+ const host = argsCatch [ 1 ] ;
282
+
283
+ if ( ! exception || ! host ) {
284
+ return originalCatch . apply ( thisArgCatch , argsCatch ) ;
285
+ }
286
+
266
287
return startSpan ( getMiddlewareSpanOptions ( target ) , ( ) => {
267
288
return originalCatch . apply ( thisArgCatch , argsCatch ) ;
268
289
} ) ;
0 commit comments