Skip to content

Commit 90493f8

Browse files
committed
fixup! fixup! fixup! fixup! fixup! feat(http): portable node:http client instrumentation (#20393)
1 parent 46a579d commit 90493f8

File tree

3 files changed

+46
-13
lines changed

3 files changed

+46
-13
lines changed

packages/core/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ export { growthbookIntegration } from './integrations/featureFlags';
147147
export { conversationIdIntegration } from './integrations/conversationId';
148148
export { patchHttpModuleClient, patchHttpsModuleClient } from './integrations/http/client-patch';
149149
export { getHttpClientSubscriptions } from './integrations/http/client-subscriptions';
150+
export { addOutgoingRequestBreadcrumb } from './integrations/http/add-outgoing-request-breadcrumb';
150151
export {
151152
HTTP_ON_CLIENT_REQUEST,
152-
HTTP_ON_CLIENT_REQUEST_FALLBACK,
153153
HTTP_ON_SERVER_REQUEST,
154154
} from './integrations/http/constants';
155155
export type {
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
export const LOG_PREFIX = '@sentry/instrumentation-http';
22
export const HTTP_ON_CLIENT_REQUEST = 'http.client.request.created';
3-
/** Used by node-light SDK to instrument on older node versions */
4-
export const HTTP_ON_CLIENT_REQUEST_FALLBACK = 'http.client.request.start';
53
export const HTTP_ON_SERVER_REQUEST = 'http.server.request.start';
64
export type ClientSubscriptionName = typeof HTTP_ON_CLIENT_REQUEST;
75
export type ServerSubscriptionName = typeof HTTP_ON_SERVER_REQUEST;

packages/node-core/src/light/integrations/httpIntegration.ts

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
import { subscribe } from 'node:diagnostics_channel';
22
import type { RequestOptions } from 'node:http';
3-
import type { Integration, IntegrationFn } from '@sentry/core';
3+
import type { HttpClientRequest, HttpIncomingMessage, Integration, IntegrationFn } from '@sentry/core';
44
import {
5+
addOutgoingRequestBreadcrumb,
56
continueTrace,
67
debug,
78
generateSpanId,
89
getCurrentScope,
910
getHttpClientSubscriptions,
1011
getIsolationScope,
1112
HTTP_ON_CLIENT_REQUEST,
12-
HTTP_ON_CLIENT_REQUEST_FALLBACK,
1313
httpRequestToRequestData,
1414
stripUrlQueryAndFragment,
1515
withIsolationScope,
1616
} from '@sentry/core';
1717
import type { ClientRequest, IncomingMessage, Server } from 'node:http';
1818
import { DEBUG_BUILD } from '../../debug-build';
1919
import { patchRequestToCaptureBody } from '../../utils/captureRequestBody';
20-
import { getRequestOptions } from '../../utils/outgoingHttpRequest';
20+
import { getClientRequestUrl, getRequestOptions } from '../../utils/outgoingHttpRequest';
2121
import type { LightNodeClient } from '../client';
2222
import { errorMonitor } from 'node:events';
2323
import { NODE_VERSION } from '../../nodeVersion';
@@ -106,10 +106,6 @@ const _httpIntegration = ((options: HttpIntegrationOptions = {}) => {
106106

107107
const { ignoreOutgoingRequests } = _options;
108108

109-
const channel = FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL
110-
? HTTP_ON_CLIENT_REQUEST
111-
: HTTP_ON_CLIENT_REQUEST_FALLBACK;
112-
113109
const { [HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = getHttpClientSubscriptions({
114110
breadcrumbs: _options.breadcrumbs,
115111
propagateTrace: _options.tracePropagation,
@@ -122,13 +118,52 @@ const _httpIntegration = ((options: HttpIntegrationOptions = {}) => {
122118
});
123119

124120
subscribe('http.server.request.start', onHttpServerRequestStart);
125-
// Subscribe on the request creation in node versions that support it,
126-
// or to the request start (ie, .end() being called) on older versions.
127-
subscribe(channel, onHttpClientRequestCreated);
121+
122+
// Subscribe on the request creation in node versions that support it
123+
subscribe(HTTP_ON_CLIENT_REQUEST, onHttpClientRequestCreated);
124+
125+
// fall back to just doing breadcrumbs on the request.end() channel
126+
// if we do not have earlier access to the request object at creation
127+
// time. The http.client.request.error channel is only available on
128+
// the same node versions as client.request.created, so no help.
129+
if (_options.breadcrumbs && !FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL) {
130+
subscribe('http.client.response.finish', (data: unknown) => {
131+
const { request, response } = data as {
132+
request: HttpClientRequest;
133+
response: HttpIncomingMessage;
134+
};
135+
onOutgoingResponseFinish(request, response, _options);
136+
});
137+
}
128138
},
129139
};
130140
}) satisfies IntegrationFn;
131141

142+
function onOutgoingResponseFinish(
143+
request: HttpClientRequest,
144+
response: HttpIncomingMessage | undefined,
145+
options: {
146+
breadcrumbs: boolean;
147+
ignoreOutgoingRequests?: (url: string, request: RequestOptions) => boolean;
148+
},
149+
): void {
150+
if (!options.breadcrumbs) {
151+
return;
152+
}
153+
// Check if tracing is suppressed (e.g. for Sentry's own transport requests)
154+
if (getCurrentScope().getScopeData().sdkProcessingMetadata.__SENTRY_SUPPRESS_TRACING__) {
155+
return;
156+
}
157+
const { ignoreOutgoingRequests } = options;
158+
if (ignoreOutgoingRequests) {
159+
const url = getClientRequestUrl(request as ClientRequest);
160+
if (ignoreOutgoingRequests(url, getRequestOptions(request as ClientRequest))) {
161+
return;
162+
}
163+
}
164+
addOutgoingRequestBreadcrumb(request, response);
165+
}
166+
132167
/**
133168
* This integration handles incoming and outgoing HTTP requests in light mode (without OpenTelemetry).
134169
*

0 commit comments

Comments
 (0)