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 owntransport. A missing or malformed DSN doesn't throw: the SDK logs one[Buglapse] Missing or invalid "dsn"warning and drops events.environment— stamped ascontexts.environmenton every event (production,staging, ...). Powers the environment filter andenvironment:search token on the dashboard, and the Settings → Filters list that drops events from listed environments before they're stored.release— stamped ascontexts.releaseon 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 byname(see below).tracesSampleRate— chance (0–1) that a trace is sent. Default1. 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 batchingfetchtransport, e.g.makeConsoleTransportfor 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 anAsyncLocalStorage-backedAsyncLocalStorageContext, 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:
| Integration | What it does |
|---|---|
httpServerIntegration | Own scope, breadcrumbs and http.server span per incoming request |
httpTracingIntegration | Outgoing requests as http.client spans |
httpErrorsIntegration | Failed outgoing requests as error logs |
breadcrumbsIntegration | Console calls and outgoing requests as breadcrumbs |
nodeContextIntegration | Node version, OS and host name on every event |
eventLoopBlockIntegration | Warning log when the event loop stalls |
consoleIntegration | console.* calls as log events |
dedupeIntegration | Drops an exception identical to the previous one |
inboundFiltersIntegration | Drops 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.