1
1
import type * as http from 'node:http' ;
2
+ import type { RequestOptions } from 'node:http' ;
2
3
import type * as https from 'node:https' ;
3
4
import { VERSION } from '@opentelemetry/core' ;
4
5
import type { InstrumentationConfig } from '@opentelemetry/instrumentation' ;
5
6
import { InstrumentationBase , InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation' ;
7
+ import { getRequestInfo } from '@opentelemetry/instrumentation-http' ;
6
8
import { addBreadcrumb , getClient , getIsolationScope , withIsolationScope } from '@sentry/core' ;
7
9
import type { SanitizedRequestData } from '@sentry/types' ;
8
10
import {
@@ -12,12 +14,29 @@ import {
12
14
stripUrlQueryAndFragment ,
13
15
} from '@sentry/utils' ;
14
16
import type { NodeClient } from '../../sdk/client' ;
17
+ import { getRequestUrl } from '../../utils/getRequestUrl' ;
15
18
16
19
type Http = typeof http ;
17
20
type Https = typeof https ;
18
21
19
22
type SentryHttpInstrumentationOptions = InstrumentationConfig & {
23
+ /**
24
+ * Whether breadcrumbs should be recorded for requests.
25
+ *
26
+ * @default `true`
27
+ */
20
28
breadcrumbs ?: boolean ;
29
+
30
+ /**
31
+ * Do not capture breadcrumbs for outgoing HTTP requests to URLs where the given callback returns `true`.
32
+ * For the scope of this instrumentation, this callback only controls breadcrumb creation.
33
+ * The same option can be passed to the top-level httpIntegration where it controls both, breadcrumb and
34
+ * span creation.
35
+ *
36
+ * @param url Contains the entire URL, including query string (if any), protocol, host, etc. of the outgoing request.
37
+ * @param request Contains the {@type RequestOptions} object used to make the outgoing request.
38
+ */
39
+ ignoreOutgoingRequests ?: ( url : string , request : RequestOptions ) => boolean ;
21
40
} ;
22
41
23
42
/**
@@ -140,20 +159,42 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
140
159
private _getPatchOutgoingRequestFunction ( ) : (
141
160
// eslint-disable-next-line @typescript-eslint/no-explicit-any
142
161
original : ( ...args : any [ ] ) => http . ClientRequest ,
143
- ) => ( ...args : unknown [ ] ) => http . ClientRequest {
162
+ ) => ( options : URL | http . RequestOptions | string , ...args : unknown [ ] ) => http . ClientRequest {
144
163
// eslint-disable-next-line @typescript-eslint/no-this-alias
145
164
const instrumentation = this ;
146
165
147
166
return ( original : ( ...args : unknown [ ] ) => http . ClientRequest ) : ( ( ...args : unknown [ ] ) => http . ClientRequest ) => {
148
167
return function outgoingRequest ( this : unknown , ...args : unknown [ ] ) : http . ClientRequest {
149
168
instrumentation . _diag . debug ( 'http instrumentation for outgoing requests' ) ;
150
169
170
+ // Making a copy to avoid mutating the original args array
171
+ // We need to access and reconstruct the request options object passed to `ignoreOutgoingRequests`
172
+ // so that it matches what Otel instrumentation passes to `ignoreOutgoingRequestHook`.
173
+ // @see https://github.com/open-telemetry/opentelemetry-js/blob/7293e69c1e55ca62e15d0724d22605e61bd58952/experimental/packages/opentelemetry-instrumentation-http/src/http.ts#L756-L789
174
+ const argsCopy = [ ...args ] ;
175
+
176
+ const options = argsCopy . shift ( ) as URL | http . RequestOptions | string ;
177
+
178
+ const extraOptions =
179
+ typeof argsCopy [ 0 ] === 'object' && ( typeof options === 'string' || options instanceof URL )
180
+ ? ( argsCopy . shift ( ) as http . RequestOptions )
181
+ : undefined ;
182
+
183
+ const { optionsParsed } = getRequestInfo ( options , extraOptions ) ;
184
+
151
185
const request = original . apply ( this , args ) as ReturnType < typeof http . request > ;
152
186
153
187
request . prependListener ( 'response' , ( response : http . IncomingMessage ) => {
154
- const breadcrumbs = instrumentation . getConfig ( ) . breadcrumbs ;
155
- const _breadcrumbs = typeof breadcrumbs === 'undefined' ? true : breadcrumbs ;
156
- if ( _breadcrumbs ) {
188
+ const _breadcrumbs = instrumentation . getConfig ( ) . breadcrumbs ;
189
+ const breadCrumbsEnabled = typeof _breadcrumbs === 'undefined' ? true : _breadcrumbs ;
190
+
191
+ const _ignoreOutgoingRequests = instrumentation . getConfig ( ) . ignoreOutgoingRequests ;
192
+ const shouldCreateBreadcrumb =
193
+ typeof _ignoreOutgoingRequests === 'function'
194
+ ? ! _ignoreOutgoingRequests ( getRequestUrl ( request ) , optionsParsed )
195
+ : true ;
196
+
197
+ if ( breadCrumbsEnabled && shouldCreateBreadcrumb ) {
157
198
addRequestBreadcrumb ( request , response ) ;
158
199
}
159
200
} ) ;
0 commit comments