|
1 | 1 | import type { ClientRequest, IncomingMessage, RequestOptions, ServerResponse } from 'node:http';
|
2 | 2 | import { diag } from '@opentelemetry/api';
|
3 |
| -import { HttpInstrumentation, HttpInstrumentationConfig } from '@opentelemetry/instrumentation-http'; |
| 3 | +import type { HttpInstrumentationConfig } from '@opentelemetry/instrumentation-http'; |
| 4 | +import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; |
4 | 5 |
|
5 | 6 | import { defineIntegration } from '@sentry/core';
|
6 | 7 | import { getClient } from '@sentry/opentelemetry';
|
@@ -92,110 +93,102 @@ const instrumentSentryHttp = generateInstrumentOnce<{ breadcrumbs?: boolean }>(
|
92 | 93 | * We only preload this one.
|
93 | 94 | * If we preload both this and `instrumentSentryHttp`, it leads to weird issues with instrumentation.
|
94 | 95 | */
|
95 |
| -export const instrumentOtelHttp = generateInstrumentOnce<HttpInstrumentationConfig>( |
96 |
| - `${INTEGRATION_NAME}.otel`, |
97 |
| - config => { |
98 |
| - const instrumentation = new HttpInstrumentation(config); |
99 |
| - |
100 |
| - // We want to update the logger namespace so we can better identify what is happening here |
101 |
| - try { |
102 |
| - instrumentation['_diag'] = diag.createComponentLogger({ |
103 |
| - namespace: INSTRUMENTATION_NAME, |
104 |
| - }); |
105 |
| - // @ts-expect-error We are writing a read-only property here... |
106 |
| - instrumentation.instrumentationName = INSTRUMENTATION_NAME; |
107 |
| - } catch { |
108 |
| - // ignore errors here... |
109 |
| - } |
110 |
| - |
111 |
| - return instrumentation; |
112 |
| - }, |
113 |
| -); |
| 96 | +export const instrumentOtelHttp = generateInstrumentOnce<HttpInstrumentationConfig>(INTEGRATION_NAME, config => { |
| 97 | + const instrumentation = new HttpInstrumentation(config); |
| 98 | + |
| 99 | + // We want to update the logger namespace so we can better identify what is happening here |
| 100 | + try { |
| 101 | + instrumentation['_diag'] = diag.createComponentLogger({ |
| 102 | + namespace: INSTRUMENTATION_NAME, |
| 103 | + }); |
| 104 | + // @ts-expect-error We are writing a read-only property here... |
| 105 | + instrumentation.instrumentationName = INSTRUMENTATION_NAME; |
| 106 | + } catch { |
| 107 | + // ignore errors here... |
| 108 | + } |
| 109 | + |
| 110 | + return instrumentation; |
| 111 | +}); |
114 | 112 |
|
115 | 113 | /**
|
116 | 114 | * Instrument the HTTP module.
|
117 | 115 | */
|
118 |
| -const instrumentHttp = Object.assign( |
119 |
| - function (options: HttpOptions = {}) { |
120 |
| - // This is the "regular" OTEL instrumentation that emits spans |
121 |
| - if (options.spans !== false) { |
122 |
| - const instrumentationConfig = { |
123 |
| - ...options.instrumentation?._experimentalConfig, |
124 |
| - |
125 |
| - disableIncomingRequestInstrumentation: options.disableIncomingRequestSpans, |
126 |
| - |
127 |
| - ignoreOutgoingRequestHook: request => { |
128 |
| - const url = getRequestUrl(request); |
129 |
| - |
130 |
| - if (!url) { |
131 |
| - return false; |
132 |
| - } |
133 |
| - |
134 |
| - const _ignoreOutgoingRequests = options.ignoreOutgoingRequests; |
135 |
| - if (_ignoreOutgoingRequests && _ignoreOutgoingRequests(url, request)) { |
136 |
| - return true; |
137 |
| - } |
| 116 | +const instrumentHttp = (options: HttpOptions = {}): void => { |
| 117 | + // This is the "regular" OTEL instrumentation that emits spans |
| 118 | + if (options.spans !== false) { |
| 119 | + const instrumentationConfig = { |
| 120 | + ...options.instrumentation?._experimentalConfig, |
138 | 121 |
|
139 |
| - return false; |
140 |
| - }, |
141 |
| - |
142 |
| - ignoreIncomingRequestHook: request => { |
143 |
| - // request.url is the only property that holds any information about the url |
144 |
| - // it only consists of the URL path and query string (if any) |
145 |
| - const urlPath = request.url; |
146 |
| - |
147 |
| - const method = request.method?.toUpperCase(); |
148 |
| - // We do not capture OPTIONS/HEAD requests as transactions |
149 |
| - if (method === 'OPTIONS' || method === 'HEAD') { |
150 |
| - return true; |
151 |
| - } |
| 122 | + disableIncomingRequestInstrumentation: options.disableIncomingRequestSpans, |
152 | 123 |
|
153 |
| - const _ignoreIncomingRequests = options.ignoreIncomingRequests; |
154 |
| - if (urlPath && _ignoreIncomingRequests && _ignoreIncomingRequests(urlPath, request)) { |
155 |
| - return true; |
156 |
| - } |
| 124 | + ignoreOutgoingRequestHook: request => { |
| 125 | + const url = getRequestUrl(request); |
157 | 126 |
|
| 127 | + if (!url) { |
158 | 128 | return false;
|
159 |
| - }, |
160 |
| - |
161 |
| - requireParentforOutgoingSpans: false, |
162 |
| - requireParentforIncomingSpans: false, |
163 |
| - requestHook: (span, req) => { |
164 |
| - addOriginToSpan(span, 'auto.http.otel.http'); |
165 |
| - if (!_isClientRequest(req) && isKnownPrefetchRequest(req)) { |
166 |
| - span.setAttribute('sentry.http.prefetch', true); |
167 |
| - } |
168 |
| - |
169 |
| - options.instrumentation?.requestHook?.(span, req); |
170 |
| - }, |
171 |
| - responseHook: (span, res) => { |
172 |
| - const client = getClient<NodeClient>(); |
173 |
| - if (client && client.getOptions().autoSessionTracking) { |
174 |
| - setImmediate(() => { |
175 |
| - client['_captureRequestSession'](); |
176 |
| - }); |
177 |
| - } |
178 |
| - |
179 |
| - options.instrumentation?.responseHook?.(span, res); |
180 |
| - }, |
181 |
| - applyCustomAttributesOnSpan: ( |
182 |
| - span: Span, |
183 |
| - request: ClientRequest | HTTPModuleRequestIncomingMessage, |
184 |
| - response: HTTPModuleRequestIncomingMessage | ServerResponse, |
185 |
| - ) => { |
186 |
| - options.instrumentation?.applyCustomAttributesOnSpan?.(span, request, response); |
187 |
| - }, |
188 |
| - } satisfies HttpInstrumentationConfig; |
189 |
| - |
190 |
| - instrumentOtelHttp(instrumentationConfig); |
191 |
| - } |
192 |
| - |
193 |
| - instrumentSentryHttp(options); |
194 |
| - }, |
195 |
| - { |
196 |
| - id: INTEGRATION_NAME, |
197 |
| - }, |
198 |
| -); |
| 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 | + |
| 187 | + instrumentOtelHttp(instrumentationConfig); |
| 188 | + } |
| 189 | + |
| 190 | + instrumentSentryHttp(options); |
| 191 | +}; |
199 | 192 |
|
200 | 193 | const _httpIntegration = ((options: HttpOptions = {}) => {
|
201 | 194 | return {
|
|
0 commit comments