Node.js / Bun SDK
Full observability for Node.js and Bun — databases, HTTP, gRPC, messaging, and logging captured automatically via OpenTelemetry
Built on OpenTelemetry
The Node.js SDK is a thin wrapper that configures OpenTelemetry with the Obtrace ingest endpoint. Installing it gives you every OTel auto-instrumentation for Node.js with zero extra code. You get full observability for 40+ libraries out of the box.
Installation
Setup
Import this file early in your application entry point (e.g. top of src/index.ts or src/app.ts). That's it. No middleware, no wrappers, no extra code.
What's Captured Automatically
After initNodeSDK(), the SDK enables all available OpenTelemetry instrumentations for your installed packages. You don't need to write any code for any of this:
| What | How | Needs code? |
|---|---|---|
| All console output | console.log, console.warn, console.error etc. are intercepted and sent as structured logs | No |
| Every inbound HTTP request | OTel http instrumentation covers all frameworks: Express, Fastify, Hono, NestJS, Koa, etc. | No |
| Every outbound HTTP call | fetch, http.request, and https.request are instrumented via OTel | No |
| Databases | pg, mysql2, mongodb, ioredis, redis are instrumented when installed | No |
| Logging frameworks | pino, winston, bunyan log output is captured and correlated with traces | No |
| gRPC | @grpc/grpc-js calls are instrumented with spans | No |
| Messaging | amqplib (RabbitMQ), kafkajs (Kafka) are instrumented | No |
| GraphQL | graphql queries and resolvers are instrumented | No |
| DNS and Net | dns and net module calls are traced | No |
| Uncaught exceptions | process.on("uncaughtException") | No |
| Unhandled promise rejections | process.on("unhandledRejection") | No |
| Trace propagation | W3C traceparent header injected on outbound, read on inbound | No |
No Middleware Needed
Express, Fastify, NestJS, and other framework middleware is not required. OpenTelemetry instruments the Node.js http module directly, so every framework built on it gets automatic spans with method, path, status, and duration.
Framework-specific middleware (expressObtraceMiddleware, fastifyObtraceHook, etc.) still exist if you want route-level granularity, but they are optional.
Optional: Custom Telemetry
The automatic instrumentation covers infrastructure telemetry. For business-specific events, use the SDK methods directly.
initNodeSDK returns an object you can use:
Business Metrics
Track KPIs that the auto-instrumentation can't know about:
Structured Business Logs
console.log is captured automatically, but for events you want to query and alert on with specific attributes:
Error Capture
Unhandled errors are captured automatically. For handled errors you still want to track:
Framework Examples
Express
No middleware needed for basic instrumentation. For route-level detail:
Fastify
NestJS
Hono
Configuration Reference
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
apiKey | string | Yes | - | Your Obtrace API key |
serviceName | string | Yes | - | Identifies this service in Obtrace |
tenantId | string | No | - | Tenant ID (auto-resolved from API key) |
projectId | string | No | - | Project ID (auto-resolved from API key) |
appId | string | No | - | App ID within a project |
env | string | No | - | Environment (production, staging, etc.) |
serviceVersion | string | No | - | Deployment version |
debug | boolean | No | false | Log SDK internals to console |
flushIntervalMs | number | No | 2000 | Queue flush interval |
maxQueueSize | number | No | 1000 | Max queued items before dropping oldest |
requestTimeoutMs | number | No | 5000 | OTLP request timeout |
defaultHeaders | Record<string, string> | No | {} | Extra headers on OTLP requests |
validateSemanticMetrics | boolean | No | false | Warn on non-canonical metric names |
Shutdown
Call shutdown() during graceful shutdown to flush buffered telemetry:
Validation
After deploying:
- Open Obtrace UI — logs should appear under your
serviceName - Make any HTTP request to your server — a span with method, path, status, and duration should appear (via OTel
httpinstrumentation) - Call any external API with
fetch()— an outbound span should appear - Run a database query (pg, mysql2, mongodb, redis) — a span should appear automatically
- Add a
console.error("test")— should appear as an error log - Trigger an unhandled exception in test — a
fatallog should appear