npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@emeryld/otel-bootstrap

v0.1.7

Published

Node helper to bootstrap OpenTelemetry traces + logs with OTLP exports

Readme

@rumbl/otel-bootstrap

Minimal OpenTelemetry bootstrap for Node services that sends traces and logs to an OTLP collector. It is safe to import once at process startup, idempotently patches console.* to emit log records with trace context, and exposes a helper logger that tack on trace_id + span_id attributes. The package is published on npm as @rumbl/otel-bootstrap, so you can add it directly to any Node project.

Installation

npm install @rumbl/otel-bootstrap

Then either import '@rumbl/otel-bootstrap'; at the top of your entrypoint or preload it via NODE_OPTIONS (see below).

Runtime behavior

  • Auto-instruments Node core modules via @opentelemetry/auto-instrumentations-node (HTTP, gRPC, Express, etc.).
  • Sends traces to OTLP (default HTTP protocol + /v1/traces).
  • Registers a log emitter that exports OTLP log records (default HTTP + /v1/logs).
  • Automatically patches console.log/info/warn/error/debug to emit correlated logs.
  • Exposes createLogger, initTelemetry, and shutdownTelemetry for manual control in tests.

Environment variables

| Name | Purpose | Default | | --- | --- | --- | | OTEL_SERVICE_NAME | Service name attached to traces/logs | rumbl-node-service | | OTEL_EXPORTER_OTLP_ENDPOINT | Base OTLP endpoint for traces & logs | http://localhost:4318 | | OTEL_EXPORTER_OTLP_PROTOCOL | http/protobuf or grpc | http/protobuf | | OTEL_RESOURCE_ATTRIBUTES | key=value pairs separated by commas (e.g. environment=dev,team=rumbl) | – | | OTEL_LOG_LEVEL | Sets the OpenTelemetry diagnostic logger (info, debug, warn, error, verbose) | info |

Copy ./.env.example to .env (or load the file via dotenv) so your service defines these values before importing @rumbl/otel-bootstrap. The example already documents the defaults shown above.

If you are running the backend alongside the observability stack, point to the collector service inside the Compose network:

OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_SERVICE_NAME=my-api
OTEL_RESOURCE_ATTRIBUTES=environment=dev

When the backend runs outside of the compose stack (e.g. local host), point at the exposed port:

OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

Usage

  1. Import first

    import '@rumbl/otel-bootstrap';
    import './server';

    This is the simplest workflow when you can control the entrypoint. The OpenTelemetry instrumentations (e.g. dataloader, Express, @grpc/grpc-js, ioredis, socket.io) must be initialized before their targets are required—if you see warnings like Module express has been loaded before @opentelemetry/instrumentation-express, move the bootstrap import to the very top of your entrypoint or preload the bootstrap via NODE_OPTIONS before the problematic modules load.

  2. Preload via Node options (useful in Docker):

    ENV NODE_OPTIONS="--require ./node_modules/@rumbl/otel-bootstrap/dist/otel.cjs"
    CMD ["node", "dist/server.js"]

    When Node starts, it will require dist/otel.cjs, which triggers the same initialization path.

  3. Optional logger helper

    import { createLogger } from '@rumbl/otel-bootstrap';
    
    const logger = createLogger('server');
    logger.info('Server ready', { port: process.env.PORT });
The helper emits structured log records and automatically adds `trace_id`/`span_id` when a span is active.

### Typed telemetry models

The bootstrap now exports `ApplicationLogAttributes`, `RequestLogAttributes`, `CacheLogAttributes`, `CacheTraceAttributes`,
`ScheduleLogAttributes`, `PresetAttributes`, `PresetOperationAttributes`, `SocketEventAttributes`, and a `TelemetryLogger<T>`
so you can align your log payloads with the Prisma-backed schemas we store.

```ts
import { createLogger, ApplicationLogAttributes } from '@rumbl/otel-bootstrap';

const logger = createLogger<ApplicationLogAttributes>('server');
logger.info('Startup completed', {
name: 'startup.complete',
tags: ['bootstrap']
});

ApplicationLogAttributes mirrors the ApplicationLog model and supports fields like name, groupId, tags, level, and meta. Use RequestLogAttributes when emitting HTTP logs, CacheLogAttributes/CacheTraceAttributes for cache operations, and ScheduleLogAttributes/SocketEventAttributes for background jobs and realtime traffic.

If you prefer one logger that switches between log types, use the discriminated union:

import { CacheOperation, DiscUnionAttributes, createLogger } from '@rumbl/otel-bootstrap';

const logger = createLogger<DiscUnionAttributes>('server');

logger.info('Cache read', {
  logType: 'cache_trace',
  key: 'user:1234',
  operation: CacheOperation.hit,
  durationMs: 2
});

We also export helpers that are typed for the common log types:

import {
  CacheOperation,
  HttpMethod,
  createApplicationLogger,
  createRequestLogger,
  createCacheLogger,
  createCacheTraceLogger
} from '@rumbl/otel-bootstrap';

const appLogger = createApplicationLogger('server');
const requestLogger = createRequestLogger('http');
const cacheLogger = createCacheLogger('redis');
const cacheTraceLogger = createCacheTraceLogger('redis');

appLogger.info('Startup complete', { name: 'startup.complete', tags: ['bootstrap'] });
requestLogger.info('Request handled', {
  name: 'GET /health',
  method: HttpMethod.get,
  path: '/health',
  status: 200,
  durationMs: 12
});
cacheLogger.info('Cache entry refreshed', {
  name: 'user:1234',
  ttlMs: 60000
});
cacheTraceLogger.info('Cache lookup', {
  key: 'user:1234',
  operation: CacheOperation.hit,
  durationMs: 2
});

Service shutdown (tests / scripts)

If you need to tear down instrumentation (tests, graceful shutdown), call:

import { shutdownTelemetry } from '@rumbl/otel-bootstrap';

await shutdownTelemetry();

Code examples

Entry-point bootstrap

Importing @rumbl/otel-bootstrap before anything else guarantees the SDK, exporters, and console patching are ready when your service starts emitting traces or logs. Combine that with the helper logger for structured data:

import '@rumbl/otel-bootstrap';
import http from 'node:http';
import { HttpMethod, createLogger } from '@rumbl/otel-bootstrap';

const logger = createLogger('server');

const server = http.createServer((req, res) => {
  logger.info('Request received', {
    name: `${req.method ?? 'GET'} ${req.url ?? '/'}`,
    method: (req.method ?? 'GET').toLowerCase() as HttpMethod,
    path: req.url ?? '/'
  });
  res.end('Telemetry service is ready');
});

server.listen(process.env.PORT ?? 3000, () => {
  logger.info('Server listening', { port: 3000 });
});

The helper logger automatically enriches every record with trace_id/span_id when a span is active and your console.* calls still emit OTLP logs.

Manual control (tests or scripts)

When you need to gate telemetry initialization—such as in a test harness or a script that must finish flushing before exiting—await initTelemetry and later call shutdownTelemetry:

import { initTelemetry, shutdownTelemetry } from '@rumbl/otel-bootstrap';

beforeAll(async () => {
  await initTelemetry();
});

afterAll(async () => {
  await shutdownTelemetry();
});

Wrap the startup/shutdown pair in try/finally blocks when your script should keep running so exporters flush before the process exits.

Troubleshooting

  • Telemetry does not appear: ensure OTEL_EXPORTER_OTLP_ENDPOINT is reachable from your process and the collector is running (obs-stack urls).
  • Collector rejects logs/traces: confirm OTEL_EXPORTER_OTLP_PROTOCOL matches the protocol the collector listens on (http/protobuf for port 4318, grpc for 4317).
  • Env vars not loaded: make sure .env or Docker Compose passes the variables before importing the bootstrap.
  • Console logs missing: the package patches console.* once telemetry initializes; ensure initialization runs before you log.
  • Module already loaded warnings: messages such as Module dataloader has been loaded before @opentelemetry/instrumentation-dataloader (also reported for Express, @grpc/grpc-js, ioredis, socket.io, etc.) mean those modules were required before telemetry initialized. Re-order your imports so @rumbl/otel-bootstrap runs first, or preload it via NODE_OPTIONS="--require ./node_modules/@rumbl/otel-bootstrap/dist/otel.cjs" to guarantee the instrumentations are registered before the instrumented libraries load.