@@ -82,17 +82,13 @@ interface HttpOptions {
82
82
} ;
83
83
}
84
84
85
- const instrumentSentryHttp = generateInstrumentOnce < { breadcrumbs ?: boolean } > (
85
+ export const instrumentSentryHttp = generateInstrumentOnce < { breadcrumbs ?: boolean } > (
86
86
`${ INTEGRATION_NAME } .sentry` ,
87
87
options => {
88
88
return new SentryHttpInstrumentation ( { breadcrumbs : options ?. breadcrumbs } ) ;
89
89
} ,
90
90
) ;
91
91
92
- /**
93
- * We only preload this one.
94
- * If we preload both this and `instrumentSentryHttp`, it leads to weird issues with instrumentation.
95
- */
96
92
export const instrumentOtelHttp = generateInstrumentOnce < HttpInstrumentationConfig > ( INTEGRATION_NAME , config => {
97
93
const instrumentation = new HttpInstrumentation ( config ) ;
98
94
@@ -111,82 +107,18 @@ export const instrumentOtelHttp = generateInstrumentOnce<HttpInstrumentationConf
111
107
} ) ;
112
108
113
109
/**
114
- * Instrument the HTTP module .
110
+ * Instrument the HTTP and HTTPS modules .
115
111
*/
116
112
const instrumentHttp = ( options : HttpOptions = { } ) : void => {
117
113
// This is the "regular" OTEL instrumentation that emits spans
118
114
if ( options . spans !== false ) {
119
- const instrumentationConfig = {
120
- ...options . instrumentation ?. _experimentalConfig ,
121
-
122
- disableIncomingRequestInstrumentation : options . disableIncomingRequestSpans ,
123
-
124
- ignoreOutgoingRequestHook : request => {
125
- const url = getRequestUrl ( request ) ;
126
-
127
- if ( ! url ) {
128
- return false ;
129
- }
130
-
131
- const _ignoreOutgoingRequests = options . ignoreOutgoingRequests ;
132
- if ( _ignoreOutgoingRequests && _ignoreOutgoingRequests ( url , request ) ) {
133
- return true ;
134
- }
135
-
136
- return false ;
137
- } ,
138
-
139
- ignoreIncomingRequestHook : request => {
140
- // request.url is the only property that holds any information about the url
141
- // it only consists of the URL path and query string (if any)
142
- const urlPath = request . url ;
143
-
144
- const method = request . method ?. toUpperCase ( ) ;
145
- // We do not capture OPTIONS/HEAD requests as transactions
146
- if ( method === 'OPTIONS' || method === 'HEAD' ) {
147
- return true ;
148
- }
149
-
150
- const _ignoreIncomingRequests = options . ignoreIncomingRequests ;
151
- if ( urlPath && _ignoreIncomingRequests && _ignoreIncomingRequests ( urlPath , request ) ) {
152
- return true ;
153
- }
154
-
155
- return false ;
156
- } ,
157
-
158
- requireParentforOutgoingSpans : false ,
159
- requireParentforIncomingSpans : false ,
160
- requestHook : ( span , req ) => {
161
- addOriginToSpan ( span , 'auto.http.otel.http' ) ;
162
- if ( ! _isClientRequest ( req ) && isKnownPrefetchRequest ( req ) ) {
163
- span . setAttribute ( 'sentry.http.prefetch' , true ) ;
164
- }
165
-
166
- options . instrumentation ?. requestHook ?.( span , req ) ;
167
- } ,
168
- responseHook : ( span , res ) => {
169
- const client = getClient < NodeClient > ( ) ;
170
- if ( client && client . getOptions ( ) . autoSessionTracking ) {
171
- setImmediate ( ( ) => {
172
- client [ '_captureRequestSession' ] ( ) ;
173
- } ) ;
174
- }
175
-
176
- options . instrumentation ?. responseHook ?.( span , res ) ;
177
- } ,
178
- applyCustomAttributesOnSpan : (
179
- span : Span ,
180
- request : ClientRequest | HTTPModuleRequestIncomingMessage ,
181
- response : HTTPModuleRequestIncomingMessage | ServerResponse ,
182
- ) => {
183
- options . instrumentation ?. applyCustomAttributesOnSpan ?.( span , request , response ) ;
184
- } ,
185
- } satisfies HttpInstrumentationConfig ;
186
-
115
+ const instrumentationConfig = getConfigWithDefaults ( options ) ;
187
116
instrumentOtelHttp ( instrumentationConfig ) ;
188
117
}
189
118
119
+ // This is the Sentry-specific instrumentation that isolates requests & creates breadcrumbs
120
+ // Note that this _has_ to be wrapped after the OTEL instrumentation,
121
+ // otherwise the isolation will not work correctly
190
122
instrumentSentryHttp ( options ) ;
191
123
} ;
192
124
@@ -221,3 +153,75 @@ function isKnownPrefetchRequest(req: HTTPModuleRequestIncomingMessage): boolean
221
153
// Currently only handles Next.js prefetch requests but may check other frameworks in the future.
222
154
return req . headers [ 'next-router-prefetch' ] === '1' ;
223
155
}
156
+
157
+ function getConfigWithDefaults ( options : Partial < HttpOptions > = { } ) : HttpInstrumentationConfig {
158
+ const instrumentationConfig = {
159
+ ...options . instrumentation ?. _experimentalConfig ,
160
+
161
+ disableIncomingRequestInstrumentation : options . disableIncomingRequestSpans ,
162
+
163
+ ignoreOutgoingRequestHook : request => {
164
+ const url = getRequestUrl ( request ) ;
165
+
166
+ if ( ! url ) {
167
+ return false ;
168
+ }
169
+
170
+ const _ignoreOutgoingRequests = options . ignoreOutgoingRequests ;
171
+ if ( _ignoreOutgoingRequests && _ignoreOutgoingRequests ( url , request ) ) {
172
+ return true ;
173
+ }
174
+
175
+ return false ;
176
+ } ,
177
+
178
+ ignoreIncomingRequestHook : request => {
179
+ // request.url is the only property that holds any information about the url
180
+ // it only consists of the URL path and query string (if any)
181
+ const urlPath = request . url ;
182
+
183
+ const method = request . method ?. toUpperCase ( ) ;
184
+ // We do not capture OPTIONS/HEAD requests as transactions
185
+ if ( method === 'OPTIONS' || method === 'HEAD' ) {
186
+ return true ;
187
+ }
188
+
189
+ const _ignoreIncomingRequests = options . ignoreIncomingRequests ;
190
+ if ( urlPath && _ignoreIncomingRequests && _ignoreIncomingRequests ( urlPath , request ) ) {
191
+ return true ;
192
+ }
193
+
194
+ return false ;
195
+ } ,
196
+
197
+ requireParentforOutgoingSpans : false ,
198
+ requireParentforIncomingSpans : false ,
199
+ requestHook : ( span , req ) => {
200
+ addOriginToSpan ( span , 'auto.http.otel.http' ) ;
201
+ if ( ! _isClientRequest ( req ) && isKnownPrefetchRequest ( req ) ) {
202
+ span . setAttribute ( 'sentry.http.prefetch' , true ) ;
203
+ }
204
+
205
+ options . instrumentation ?. requestHook ?.( span , req ) ;
206
+ } ,
207
+ responseHook : ( span , res ) => {
208
+ const client = getClient < NodeClient > ( ) ;
209
+ if ( client && client . getOptions ( ) . autoSessionTracking ) {
210
+ setImmediate ( ( ) => {
211
+ client [ '_captureRequestSession' ] ( ) ;
212
+ } ) ;
213
+ }
214
+
215
+ options . instrumentation ?. responseHook ?.( span , res ) ;
216
+ } ,
217
+ applyCustomAttributesOnSpan : (
218
+ span : Span ,
219
+ request : ClientRequest | HTTPModuleRequestIncomingMessage ,
220
+ response : HTTPModuleRequestIncomingMessage | ServerResponse ,
221
+ ) => {
222
+ options . instrumentation ?. applyCustomAttributesOnSpan ?.( span , request , response ) ;
223
+ } ,
224
+ } satisfies HttpInstrumentationConfig ;
225
+
226
+ return instrumentationConfig ;
227
+ }
0 commit comments