Skip to content

The Node SDK is configured entirely in code, through init(). The project's Settings → Loader Script tab only shapes the browser's CDN bundle — none of its toggles apply to @buglapse/node.

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

init({
    dsn: process.env.BUGLAPSE_DSN,
    environment: process.env.NODE_ENV,
    release: process.env.GIT_SHA,
    tracesSampleRate: 0.2,
    debug: process.env.BUGLAPSE_DEBUG === 'true',
    integrations: [httpServerIntegration()],
})

Option reference ​

  • dsn — the project's DSN, https://{key}@{host}, from Settings → General. Required unless you pass your own transport. A missing or malformed DSN doesn't throw: the SDK logs one [Buglapse] Missing or invalid "dsn" warning and drops events.
  • environment — stamped as contexts.environment on every event (production, staging, ...). Powers the environment filter and environment: search token on the dashboard, and the Settings → Filters list that drops events from listed environments before they're stored.
  • release — stamped as contexts.release on every event. A git SHA or version tag works well; it's also what Source maps match against if you bundle or minify your server code.
  • debug — logs what the SDK is doing ([Buglapse] ...) to the console: integration registration, captured and dropped events, sent and failed batches. Leave it off in production.
  • integrations — the integrations to register, merged with the defaults by name (see below).
  • tracesSampleRate — chance (0–1) that a trace is sent. Default 1. Rolled once per trace, so a trace arrives with all its spans or not at all. See Tracing → Sampling.
  • transport — a transport factory that replaces the default batching fetch transport, e.g. makeConsoleTransport for local development. See Transports.
  • transportOptions — tunes the default transport: timeout, retries, maxBatchSize, flushInterval, immediateTypes, onError. See Transports.
  • storage — where the per-request scope, active span and breadcrumbs are kept. init() uses an AsyncLocalStorage-backed AsyncLocalStorageContext, which keeps concurrent requests apart; there's normally no reason to change it (see Tags & Context).
  • resolveTraceId — supplies the trace id for a new root span. By default every root span starts its own trace — one per incoming request with HttpServerIntegration. Override it only to group several root operations into one trace yourself.

Integrations ​

Only UncaughtExceptionIntegration is on by default. Everything else is opt-in and imported from @buglapse/node/integrations:

IntegrationWhat it does
httpServerIntegrationOwn scope, breadcrumbs and http.server span per incoming request
httpTracingIntegrationOutgoing requests as http.client spans
httpErrorsIntegrationFailed outgoing requests as error logs
breadcrumbsIntegrationConsole calls and outgoing requests as breadcrumbs
nodeContextIntegrationNode version, OS and host name on every event
eventLoopBlockIntegrationWarning log when the event loop stalls
consoleIntegrationconsole.* calls as log events
dedupeIntegrationDrops an exception identical to the previous one
inboundFiltersIntegrationDrops exceptions by message

There are three ways to manage them:

ts
import { disable, init, use } from '@buglapse/node'
import { consoleIntegration, nodeContextIntegration } from '@buglapse/node/integrations'

// 1. Upfront, in init() — merged with the defaults; an entry with a default's name replaces it.
init({ dsn: process.env.BUGLAPSE_DSN, integrations: [nodeContextIntegration()] })

// 2. Later, with use() — also works before init(): the call is queued until then.
use(consoleIntegration())

// 3. Off, by name — before init() it keeps a default from being registered at all.
disable('uncaught-exception')

use() never replaces an integration that's already registered under the same name — call disable(name) first. Writing your own is covered in Create integration.

Calls before init() ​

Every call made before init() — captureException(), log.*(), setTag(), use(), ... — is queued and applied once the client exists, so modules imported ahead of your init() call can still report. The exceptions are span(), asyncSpan(), startInactiveSpan() and withScope(): they wrap code that has to run now, so before init() they just run it, untraced.

Call init() once. A second call replaces the client, and anything the first one still had buffered is lost.

Multiple clients ​

The flat API talks to one shared client. If a single process needs to report to several projects (e.g. a multi-tenant worker), build extra clients with createClient():

ts
import { AsyncLocalStorageContext, createClient } from '@buglapse/node'
import { nodeContextIntegration } from '@buglapse/node/integrations'

const billing = createClient({
    dsn: process.env.BUGLAPSE_BILLING_DSN,
    storage: new AsyncLocalStorageContext(),
    integrations: [nodeContextIntegration()],
})

billing.captureException(error)
await billing.flush()

A client made this way gets no defaults: pass storage: new AsyncLocalStorageContext() yourself (otherwise concurrent operations share one scope), and list every integration it should have. Don't give a second client httpServerIntegration or uncaughtExceptionIntegration while the shared one also has them — both would hook the same process-wide events.