Skip to content

Overview ​

A Node process handles many requests at once, on one shared client. httpServerIntegration runs each incoming request's handlers inside its own scope, so the request gets its own:

  • tags and contexts — a withScope() inside a handler only affects that request's events (the global setTag() / setUser() still apply to the whole process — see Tags & Context);
  • breadcrumb trail — an error in one request never carries breadcrumbs from another;
  • trace — with spans on (the default), each request is an http.server root span named GET /users/42, and every span, log and error captured while handling it belongs to its trace.

Every event captured during a request is stamped with request.url, request.method and request.referrer. The span also records http.method, http.url and http.status_code. It gets status error for a 5xx response and cancelled when the client disconnects before the response is sent.

It hooks into node:http / node:https itself, so it works with anything built on them: Express, Koa, Fastify, Hono's Node adapter, Next.js's own server.

Usage ​

ts
import { init } from '@buglapse/node'
import { httpServerIntegration } from '@buglapse/node/integrations'

init({
    dsn: '{dsn}',
    integrations: [
        httpServerIntegration({
            ignoreRequest: (request) => request.url === '/health',
        }),
    ],
})

Call init() before the server receives its first request. Servers created earlier are covered too.

Options ​

OptionTypeDefaultDescription
spansbooleantrueRecord each request as an http.server root span. With false, requests still get their own scope and request.* contexts.
ignoreRequest(request: IncomingMessage) => boolean—Return true to leave a request uninstrumented (health checks, static files).

tracesSampleRate applies to the request spans like to any other trace.

For work that doesn't start from an HTTP request (queue jobs, cron tasks), wrap each unit of work in withScope() or asyncSpan() to give it the same isolation.