Skip to content

Commit c7b07dc

Browse files
committed
improve dedupe logic
1 parent 446314b commit c7b07dc

File tree

1 file changed

+26
-19
lines changed

1 file changed

+26
-19
lines changed

packages/node/src/integrations/http/SentryHttpInstrumentation.ts

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -108,42 +108,43 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
108108

109109
/** @inheritdoc */
110110
public init(): [InstrumentationNodeModuleDefinition, InstrumentationNodeModuleDefinition] {
111-
const handledRequests = new WeakSet<http.ClientRequest>();
112-
113-
const handleOutgoingRequestFinishOnce = (request: http.ClientRequest, response?: http.IncomingMessage): void => {
114-
if (handledRequests.has(request)) {
115-
return;
116-
}
117-
118-
handledRequests.add(request);
119-
this._onOutgoingRequestFinish(request, response);
120-
};
111+
// We register handlers when either http or https is instrumented
112+
// but we only want to register them once, whichever is instrumented first
113+
let hasRegisteredHandlers = false;
121114

122115
const onHttpServerRequestStart = ((_data: unknown) => {
123116
const data = _data as { server: http.Server };
124117
this._patchServerEmitOnce(data.server);
125118
}) satisfies ChannelListener;
126119

127-
const onHttpsServerRequestStart = ((_data: unknown) => {
128-
const data = _data as { server: http.Server };
129-
this._patchServerEmitOnce(data.server);
130-
}) satisfies ChannelListener;
131-
132120
const onHttpClientResponseFinish = ((_data: unknown) => {
133121
const data = _data as { request: http.ClientRequest; response: http.IncomingMessage };
134-
handleOutgoingRequestFinishOnce(data.request, data.response);
122+
this._onOutgoingRequestFinish(data.request, data.response);
135123
}) satisfies ChannelListener;
136124

137125
const onHttpClientRequestError = ((_data: unknown) => {
138126
const data = _data as { request: http.ClientRequest };
139-
handleOutgoingRequestFinishOnce(data.request, undefined);
127+
this._onOutgoingRequestFinish(data.request, undefined);
140128
}) satisfies ChannelListener;
141129

130+
/**
131+
* You may be wondering why we register these diagnostics-channel listenrers in such InstrumentationNodeModuleDefinition,
132+
* instead of simply subscribing to the events once in here.
133+
* The reason for this is timing semantics: These functions are called once the http or https module is loaded.
134+
* If we'd subscribe before that, there seem to be conflicts with the OTEL native instrumentation in some scenarios,
135+
* especially the "import-on-top" pattern of setting up ESM applications.
136+
*/
142137
return [
143138
new InstrumentationNodeModuleDefinition(
144139
'http',
145140
['*'],
146141
(moduleExports: Http): Http => {
142+
if (hasRegisteredHandlers) {
143+
return moduleExports;
144+
}
145+
146+
hasRegisteredHandlers = true;
147+
147148
subscribe('http.server.request.start', onHttpServerRequestStart);
148149
subscribe('http.client.response.finish', onHttpClientResponseFinish);
149150

@@ -163,7 +164,13 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
163164
'https',
164165
['*'],
165166
(moduleExports: Https): Https => {
166-
subscribe('http.server.request.start', onHttpsServerRequestStart);
167+
if (hasRegisteredHandlers) {
168+
return moduleExports;
169+
}
170+
171+
hasRegisteredHandlers = true;
172+
173+
subscribe('http.server.request.start', onHttpServerRequestStart);
167174
subscribe('http.client.response.finish', onHttpClientResponseFinish);
168175

169176
// When an error happens, we still want to have a breadcrumb
@@ -173,7 +180,7 @@ export class SentryHttpInstrumentation extends InstrumentationBase<SentryHttpIns
173180
return moduleExports;
174181
},
175182
() => {
176-
unsubscribe('http.server.request.start', onHttpsServerRequestStart);
183+
unsubscribe('http.server.request.start', onHttpServerRequestStart);
177184
unsubscribe('http.client.response.finish', onHttpClientResponseFinish);
178185
unsubscribe('http.client.request.error', onHttpClientRequestError);
179186
},

0 commit comments

Comments
 (0)