feat(bun): Add bunHttpServerIntegration - #22870
Conversation
7bc2c44 to
aa5fc6a
Compare
bunHttpIntegration for node:http request isolationbunHttpServerIntegration
isaacs
left a comment
There was a problem hiding this comment.
Only real concern that I saw is the missing errorMonitor symbol, and the other settings nits. (Posting as a comment rather than "request changes" because I'm going to be away next week and don't want to block landing once addressed.)
|
|
||
| const { [HTTP_ON_SERVER_REQUEST]: onServerRequest } = getHttpServerSubscriptions({ | ||
| spans: options.spans ?? true, | ||
| sessions: options.sessions ?? true, |
There was a problem hiding this comment.
It's interesting that Deno uses this same interface but sets sessions: false. I got confused at first and thought this was a bug, but actually it looks like Deno is the one that's wrong, and this is correct. Posted in #22888.
Bun does not emit the `http.server.request.start` diagnostics channel that the Node SDK relies on to isolate each incoming request. As a result, servers built on `node:http` (such as Next.js running via `bun --bun`) do not get a fresh isolation scope and trace per request, so unrelated requests can share one trace. `bunHttpIntegration` closes this gap by patching `http.Server.prototype.emit` and, on each server's first `request` event, handing the server to the same core instrumentation the Node SDK uses (`getHttpServerSubscriptions` → `instrumentServer`). We patch the prototype rather than `createServer` because the server is typically created and `listen()`ed before Sentry initializes (e.g. Next.js creates its server before running the `instrumentation.ts` `register()` hook). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds an assertion that an `http.server` span is created for incoming requests when spans are enabled, alongside the existing isolation and trace-continuation coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: isaacs <i@izs.me>
2c2d1bd to
5c0580d
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5c0580d. Configure here.
| /** | ||
| * Do not capture the request body for incoming HTTP requests to URLs where the given callback returns `true`. | ||
| */ | ||
| ignoreRequestBody?: (url: string, request: http.RequestOptions) => boolean; |
There was a problem hiding this comment.
Wrong ignoreRequestBody request type
Medium Severity
ignoreRequestBody is typed to receive http.RequestOptions, but core invokes that callback with an incoming HttpIncomingMessage. Sibling options in the same interface already use HttpIncomingMessage, and Deno's equivalent integration types this correctly.
Reviewed by Cursor Bugbot for commit 5c0580d. Configure here.
There was a problem hiding this comment.
this is fine, we do the same in node


Adds a
bunHttpIntegrationto@sentry/bunthat isolates incoming requests for servers built onnode:httpwhen running under the Bun runtime.Problem
Bun does not emit the
http.server.request.startdiagnostics channel that the Node SDK relies on (getHttpServerSubscriptionsin@sentry/core) to isolate each incoming request. As a result, servers built onnode:http— notably Next.js running viabun --bun— do not get a fresh isolation scope and propagation context per request. Two unrelated incoming requests can therefore end up sharing a singletrace_id.This was surfaced by the
nextjs-16-bune2e app:propagation.test.ts › Does not propagate outgoing fetch requests not covered by tracePropagationTargetsfailed because the inbound and outbound transactions shared one trace.Approach
bunHttpServerIntegrationpatcheshttp.Server.prototype.emitand, on each server's first'request'event, hands that server to the exact same core instrumentation the Node SDK uses (getHttpServerSubscriptions→instrumentServer). Core then installs its per-instanceemitwrapper, which shadows the prototype patch for all subsequent requests to that server. No changes to@sentry/core,@sentry/opentelemetry, or the tracer — this only reuses existing core logic at a Bun-specific entry point.Two decisions worth calling out:
createServer. The server is typically created andlisten()ed before Sentry initializes. Next.js in particular creates itshttp.Serverand callslisten()before running theinstrumentation.tsregister()hook that loads the Sentry config, so acreateServerpatch installs too late to see the already-created server. PatchingServer.prototype.emitcatches pre-existing servers on their next request.spansoption. When another layer already emits incoming-request spans (Next.js emits its own OpenTelemetryhttp.serverspans), passspans: falseso the integration only isolates the request and resets its trace, without creating duplicate transactions. This mirrors how the NodehttpIntegrationusesdisableIncomingRequestSpans.The integration is a no-op outside Bun (guarded on
process.versions.bun), and is added by default when using the bun sdk.e2e wiring
The
nextjs-16-buntest app uses@sentry/nextjs(→@sentry/node), so it does not pick this up automatically.@sentry/bunis added as a dependency of that app andbunHttpIntegration({ spans: false })is added to its server config.Known limitation
Servers created via an ES module namespace import (
import * as http from 'node:http') are covered, since we patch the sharedhttp.Serverclass rather than a module binding.