Skip to content

Commit 84243e6

Browse files
mydeaLms24
andauthored
feat(node): Update httpIntegration handling of incoming requests (#17371)
This PR updates the handling of the Node SDK of incoming requests. Instead of relying on @opentelemetry/instrumentation-http for this, we now handle this internally, ensuring that we can optimize performance as much as possible and avoid interop problems. This will also allow us to extract this out of an OTEL instrumentation, eventually paving the way for a non-OTEL SDK with basic tracing capabilities. This change should not affect users, unless they are relying on very in-depth implementation details. Importantly, this also drops the `_experimentalConfig` option of the integration - this will no longer do anything. Finally, you can still pass `instrumentation.{requestHook,responseHook,applyCustomAttributesOnSpan}` options, but they are deprecated and will be removed in v11. Instead, you can use the new `incomingRequestSpanHook` configuration option if you want to adjust the incoming request span. I have tried to ensure the spans look as similar as possible as before, this should be reflected in the tests. --------- Co-authored-by: Lukas Stracke <[email protected]>
1 parent 12528ec commit 84243e6

File tree

16 files changed

+783
-209
lines changed

16 files changed

+783
-209
lines changed

.size-limit.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ module.exports = [
224224
import: createImport('init'),
225225
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
226226
gzip: true,
227-
limit: '116 KB',
227+
limit: '51 KB',
228228
},
229229
// Node SDK (ESM)
230230
{
@@ -233,14 +233,14 @@ module.exports = [
233233
import: createImport('init'),
234234
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
235235
gzip: true,
236-
limit: '150 KB',
236+
limit: '152 KB',
237237
},
238238
{
239239
name: '@sentry/node - without tracing',
240240
path: 'packages/node/build/esm/index.js',
241241
import: createImport('initWithoutDefaultIntegrations', 'getDefaultIntegrationsWithoutPerformance'),
242242
gzip: true,
243-
limit: '110 KB',
243+
limit: '95 KB',
244244
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
245245
modifyWebpackConfig: function (config) {
246246
const webpack = require('webpack');
@@ -263,7 +263,7 @@ module.exports = [
263263
import: createImport('init'),
264264
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
265265
gzip: true,
266-
limit: '135 KB',
266+
limit: '107 KB',
267267
},
268268
];
269269

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
66

7+
### Important Changes
8+
9+
- **feat(node)**: Update `httpIntegration` handling of incoming requests
10+
11+
This version updates the handling of the Node SDK of incoming requests. Instead of relying on @opentelemetry/instrumentation-http, we now handle incoming request instrumentation internally, ensuring that we can optimize performance as much as possible and avoid interop problems.
12+
13+
This change should not affect users, unless they are relying on very in-depth implementation details. Importantly, this also drops the `_experimentalConfig` option of the integration - this will no longer do anything.
14+
Finally, you can still pass `instrumentation.{requestHook,responseHook,applyCustomAttributesOnSpan}` options, but they are deprecated and will be removed in v11. Instead, you can use the new `incomingRequestSpanHook` configuration option if you want to adjust the incoming request span.
15+
716
## 10.8.0
817

918
### Important Changes

dev-packages/e2e-tests/test-applications/node-express-esm-preload/tests/server.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,7 @@ test('Should record a transaction for route with parameters', async ({ request }
117117
});
118118
});
119119

120-
// This fails https://github.com/getsentry/sentry-javascript/pull/12587#issuecomment-2181019422
121-
// Skipping this for now so we don't block releases
122-
test.skip('Should record spans from http instrumentation', async ({ request }) => {
120+
test('Should record spans from http instrumentation', async ({ request }) => {
123121
const transactionEventPromise = waitForTransaction('node-express-esm-preload', transactionEvent => {
124122
return transactionEvent.contexts?.trace?.data?.['http.target'] === '/http-req';
125123
});

dev-packages/node-integration-tests/suites/express/tracing/updateName/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ describe('express tracing', () => {
2929

3030
// Also calling `updateName` AND setting a source doesn't change anything - Otel has no concept of source, this is sentry-internal.
3131
// Therefore, only the source is updated but the name is still overwritten by Otel.
32-
test("calling `span.updateName` and setting attribute source doesn't update the final name in express but it updates the source", async () => {
32+
test('calling `span.updateName` and setting attribute source updates the final name in express', async () => {
3333
const runner = createRunner(__dirname, 'server.js')
3434
.expect({
3535
transaction: {
36-
transaction: 'GET /test/:id/span-updateName-source',
36+
transaction: 'new-name',
3737
transaction_info: {
3838
source: 'custom',
3939
},

dev-packages/node-integration-tests/suites/tracing/httpIntegration/instrument-options.mjs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@ import { loggingTransport } from '@sentry-internal/node-integration-tests';
44
Sentry.init({
55
dsn: 'https://[email protected]/1337',
66
release: '1.0',
7-
// disable attaching headers to /test/* endpoints
8-
tracePropagationTargets: [/^(?!.*test).*$/],
97
tracesSampleRate: 1.0,
108
transport: loggingTransport,
119

1210
integrations: [
1311
Sentry.httpIntegration({
12+
incomingRequestSpanHook: (span, req, res) => {
13+
span.setAttribute('incomingRequestSpanHook', 'yes');
14+
Sentry.setExtra('incomingRequestSpanHookCalled', {
15+
reqUrl: req.url,
16+
reqMethod: req.method,
17+
resUrl: res.req.url,
18+
resMethod: res.req.method,
19+
});
20+
},
1421
instrumentation: {
1522
requestHook: (span, req) => {
1623
span.setAttribute('attr1', 'yes');
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as Sentry from '@sentry/node';
2+
import { loggingTransport } from '@sentry-internal/node-integration-tests';
3+
4+
Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
transport: loggingTransport,
9+
// We deliberately disable dedupe here, to make sure we do not double wrap the emit function
10+
// Otherwise, duplicate spans (that we want to test against) may be dropped by dedupe detection
11+
integrations: integrations => integrations.filter(integration => integration.name !== 'Dedupe'),
12+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { sendPortToRunner } from '@sentry-internal/node-integration-tests';
2+
import http from 'http';
3+
4+
const server = http.createServer(function (request, response) {
5+
const useProxy = request.url.includes('proxy');
6+
const patchOriginalEmit = request.url.includes('original');
7+
8+
// Monkey patch it again to ensure it still works later
9+
// We cover multiple possible scenarios here:
10+
// 1. Use proxy to overwrite server.emit
11+
// 2. Use proxy to overwrite server.emit, using initial server.emit
12+
// 3. Use classic monkey patching to overwrite server.emit
13+
// 4. Use classic monkey patching to overwrite server.emit, using initial server.emit
14+
monkeyPatchEmit(server, { useProxy, patchOriginalEmit });
15+
16+
response.end('Hello Node.js Server!');
17+
});
18+
19+
const initialServerEmit = server.emit;
20+
21+
server.listen(0, () => {
22+
sendPortToRunner(server.address().port);
23+
});
24+
25+
function monkeyPatchEmit(server, { useProxy = false, patchOriginalEmit = false }) {
26+
const originalEmit = patchOriginalEmit ? initialServerEmit : server.emit;
27+
28+
if (useProxy) {
29+
server.emit = new Proxy(originalEmit, {
30+
apply(target, thisArg, args) {
31+
return target.apply(thisArg, args);
32+
},
33+
});
34+
} else {
35+
server.emit = function () {
36+
return originalEmit.apply(server, arguments);
37+
};
38+
}
39+
}

dev-packages/node-integration-tests/suites/tracing/httpIntegration/server-experimental.js

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)