1
- import {
2
- addTracingExtensions ,
3
- captureException ,
4
- getCurrentScope ,
5
- runWithAsyncContext ,
6
- startTransaction ,
7
- } from '@sentry/core' ;
8
- import { tracingContextFromHeaders , winterCGHeadersToDict } from '@sentry/utils' ;
1
+ import { addTracingExtensions , captureException , continueTrace , runWithAsyncContext , trace } from '@sentry/core' ;
2
+ import { winterCGHeadersToDict } from '@sentry/utils' ;
9
3
10
4
import { isNotFoundNavigationError , isRedirectNavigationError } from '../common/nextNavigationErrorUtils' ;
11
5
import type { ServerComponentContext } from '../common/types' ;
@@ -28,88 +22,57 @@ export function wrapServerComponentWithSentry<F extends (...args: any[]) => any>
28
22
return new Proxy ( appDirComponent , {
29
23
apply : ( originalFunction , thisArg , args ) => {
30
24
return runWithAsyncContext ( ( ) => {
31
- const currentScope = getCurrentScope ( ) ;
32
- let maybePromiseResult ;
33
-
34
25
const completeHeadersDict : Record < string , string > = context . headers
35
26
? winterCGHeadersToDict ( context . headers )
36
27
: { } ;
37
28
38
- const { traceparentData , dynamicSamplingContext , propagationContext } = tracingContextFromHeaders (
29
+ const transactionContext = continueTrace ( {
39
30
// eslint-disable-next-line deprecation/deprecation
40
- context . sentryTraceHeader ?? completeHeadersDict [ 'sentry-trace' ] ,
31
+ sentryTrace : context . sentryTraceHeader ?? completeHeadersDict [ 'sentry-trace' ] ,
41
32
// eslint-disable-next-line deprecation/deprecation
42
- context . baggageHeader ?? completeHeadersDict [ 'baggage' ] ,
43
- ) ;
44
- currentScope . setPropagationContext ( propagationContext ) ;
45
-
46
- const transaction = startTransaction ( {
47
- op : 'function.nextjs' ,
48
- name : `${ componentType } Server Component (${ componentRoute } )` ,
49
- status : 'ok' ,
50
- origin : 'auto.function.nextjs' ,
51
- ...traceparentData ,
52
- metadata : {
53
- request : {
54
- headers : completeHeadersDict ,
55
- } ,
56
- source : 'component' ,
57
- dynamicSamplingContext : traceparentData && ! dynamicSamplingContext ? { } : dynamicSamplingContext ,
58
- } ,
33
+ baggage : context . baggageHeader ?? completeHeadersDict [ 'baggage' ] ,
59
34
} ) ;
60
35
61
- currentScope . setSpan ( transaction ) ;
62
-
63
- const handleErrorCase = ( e : unknown ) : void => {
64
- if ( isNotFoundNavigationError ( e ) ) {
65
- // We don't want to report "not-found"s
66
- transaction . setStatus ( 'not_found' ) ;
67
- } else if ( isRedirectNavigationError ( e ) ) {
68
- // We don't want to report redirects
69
- } else {
70
- transaction . setStatus ( 'internal_error' ) ;
71
-
72
- captureException ( e , {
73
- mechanism : {
74
- handled : false ,
36
+ const res = trace (
37
+ {
38
+ ...transactionContext ,
39
+ op : 'function.nextjs' ,
40
+ name : `${ componentType } Server Component (${ componentRoute } )` ,
41
+ status : 'ok' ,
42
+ origin : 'auto.function.nextjs' ,
43
+ metadata : {
44
+ ...transactionContext . metadata ,
45
+ request : {
46
+ headers : completeHeadersDict ,
75
47
} ,
76
- } ) ;
77
- }
78
-
79
- transaction . finish ( ) ;
80
- } ;
81
-
82
- try {
83
- maybePromiseResult = originalFunction . apply ( thisArg , args ) ;
84
- } catch ( e ) {
85
- handleErrorCase ( e ) ;
86
- void flushQueue ( ) ;
87
- throw e ;
88
- }
48
+ source : 'component' ,
49
+ } ,
50
+ } ,
51
+ ( ) => originalFunction . apply ( thisArg , args ) ,
52
+ ( e , span ) => {
53
+ if ( isNotFoundNavigationError ( e ) ) {
54
+ // We don't want to report "not-found"s
55
+ span ?. setStatus ( 'not_found' ) ;
56
+ } else if ( isRedirectNavigationError ( e ) ) {
57
+ // We don't want to report redirects
58
+ // Since `trace` will automatically set the span status to "internal_error" we need to set it back to "ok"
59
+ span ?. setStatus ( 'ok' ) ;
60
+ } else {
61
+ span ?. setStatus ( 'internal_error' ) ;
89
62
90
- if ( typeof maybePromiseResult === 'object' && maybePromiseResult !== null && 'then' in maybePromiseResult ) {
91
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
92
- Promise . resolve ( maybePromiseResult )
93
- . then (
94
- ( ) => {
95
- transaction . finish ( ) ;
96
- } ,
97
- e => {
98
- handleErrorCase ( e ) ;
99
- } ,
100
- )
101
- . finally ( ( ) => {
102
- void flushQueue ( ) ;
103
- } ) ;
63
+ captureException ( e , {
64
+ mechanism : {
65
+ handled : false ,
66
+ } ,
67
+ } ) ;
68
+ }
69
+ } ,
70
+ ( ) => {
71
+ void flushQueue ( ) ;
72
+ } ,
73
+ ) ;
104
74
105
- // It is very important that we return the original promise here, because Next.js attaches various properties
106
- // to that promise and will throw if they are not on the returned value.
107
- return maybePromiseResult ;
108
- } else {
109
- transaction . finish ( ) ;
110
- void flushQueue ( ) ;
111
- return maybePromiseResult ;
112
- }
75
+ return res ;
113
76
} ) ;
114
77
} ,
115
78
} ) ;
0 commit comments