Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f1ac205. Configure here.
size-limit report 📦
|
Platform-portable Connect tracing integration in `@sentry/core` (`patchConnectModule`, `setupConnectErrorHandler`), similar to portable Express integration, and rewire the Node SDK's Connect integration to call into it through the otel InstrumentationBase class. Remove OTel-specific span attribute fix-up. Spans created with correct origin (`auto.http.connect`) and op directly in the middleware.
Add platform-portable building blocks that server SDKs use to instrument incoming HTTP requests without depending on OTel HTTP instrumentation: - `getHttpServerSubscriptions`: diagnostics_channel listener for `http.server.request.start`, set up isolation scope, request data, trace continuation, optional body capture and request-session tracking - `getHttpServerSpanSubscriptions`: wrapper that creates the root server span around the request lifecycle, applying static-asset/status-code filtering, `ignoreIncomingRequests` and `onSpanCreated` hooks - `recordRequestSession`: release-health session aggregation per request - `patchRequestToCaptureBody`: opt-in incoming request body capture Add `kind` field on `StartSpanOptions` so OTel-based SDKs can set SpanKind on the underlying span, and update `headersToDict` to allow `number`-valued headers to support Node.js types.
Replace inline `instrumentServer` Proxy/emit-wrapping implementation in node-light's HTTP integration with core's `getHttpServerSubscriptions`, which does the same work (isolation scope, request data, body capture, trace continuation, best-effort transaction name). Centralized implementation lets Bun, Deno, Workers, and the OTel-based Node SDK share server-side primitives. Also drop `wrappedEmitFns` and the import of several core utilities that are now consumed via the subscriptions.
…erIntegration Replace inline `instrumentServer` Proxy/emit-wrapping in `httpServerIntegration.ts` with core's `getHttpServerSubscriptions`. OTel-specific concerns (header propagation, double-wrap context guard, `_startSpanCallback` dispatch) move into a `wrapServerEmitRequest` callback that `instrumentServer` invokes inside the per-request lifecycle. Re-export `recordRequestSession` from core so existing test continues to pass. Duplicated request-isolation/session/body-capture plumbing removed, logic now lives in `@sentry/core`'s subscription factory.
`patchRequestToCaptureBody` lives in `@sentry/core` now and both the light SDK and the OTel-based `httpServerIntegration` consume it from there.
f1ac205 to
2954cdc
Compare
|
|
||
| // Ensure we also remove callbacks correctly | ||
| // eslint-disable-next-line @typescript-eslint/unbound-method | ||
| req.off = new Proxy(req.off, { |
There was a problem hiding this comment.
I think I've never ever used double assignment in JavaScript. That's pretty clever
JPeer264
left a comment
There was a problem hiding this comment.
Got couple of comments. Nice splitting.
| try { | ||
| const chunk = args[0] as Buffer | string; | ||
| const bufferifiedChunk = Buffer.from(chunk); | ||
| const bufferifiedChunk = Buffer.from(chunk as string); |
There was a problem hiding this comment.
q: Is this type assertion needed?
| const callbackMap = new WeakMap(); | ||
|
|
||
| const maxBodySize = getMaxBodyByteLength(maxIncomingRequestBodySize); | ||
| const maxBodySize = |
There was a problem hiding this comment.
m: Is there any reason why the function got moved to the previous behavior? Maybe it wasn't rebased yet when it got implemented.
| req: HttpIncomingMessage, | ||
| isolationScope: Scope, | ||
| maxIncomingRequestBodySize: Exclude<MaxRequestBodySize, 'none'>, | ||
| maxIncomingRequestBodySize: 'small' | 'medium' | 'always', |
There was a problem hiding this comment.
m: Here the reusable type got removed any specific reason? Also here, maybe it wasn't rebased yet when it got implemented.
| await runner.completed(); | ||
| }); | ||
| }, | ||
| { failsOnEsm: true }, |
There was a problem hiding this comment.
Absolutely amazing that this works now 🥇
| const name = `${method} ${httpTargetWithoutQueryFragment}`; | ||
| const headers = request.headers; | ||
| const userAgent = headers['user-agent']; | ||
| const ips = headers['x-forwarded-for']; |
There was a problem hiding this comment.
l/m: I know this code has been here in some form already, but is it guaranteed that the headers are always lower case? Given that with HTTP1 you could still send X-Forwarded-For
|
|
||
| const INTEGRATION_NAME = 'Http.SentryServerSpans'; | ||
|
|
||
| export function getHttpServerSpanSubscriptions(options: HttpInstrumentationOptions): HttpServerSubscriptions { |
There was a problem hiding this comment.
q: How is this supposed to be used? It is exported but not used - so I wonder how this fits into the bigger picture. It also has no e2e/integration/unit tests, but would it would be nice to have some for this.
I also wonder if it would be added as one of our integrations, as it has Http.SentryServerSpans as integration name, but then it wouldn't match the other exported integration names. I'm slightly confused on this.
| const timeout = setTimeout(() => { | ||
| DEBUG_BUILD && debug.log('Sending request session aggregate due to flushing schedule'); | ||
| flushPendingClientAggregates(); | ||
| }, sessionFlushingDelayMS).unref?.(); |
There was a problem hiding this comment.
l: Since this line has been moved, you could change that to safeUnref from core, which takes case of that.

Before submitting a pull request, please take a look at our
Contributing guidelines and verify:
yarn lint) & (yarn test).Closes #issue_link_here