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

@crossdelta/telemetry

v0.13.1

Published

OpenTelemetry instrumentation for CrossDelta services

Readme

@crossdelta/telemetry

npm version License: MIT TypeScript OpenTelemetry

OpenTelemetry instrumentation for TypeScript services on Bun and Node.js.

Getting Started

1. Install

bun add @crossdelta/telemetry

2. Import (first line!)

import '@crossdelta/telemetry'

import { Hono } from 'hono'

The import must come before everything else to properly patch modules.

3. Set environment variables

OTEL_SERVICE_NAME=my-service
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://otlp-gateway.grafana.net/otlp/v1/traces
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://otlp-gateway.grafana.net/otlp/v1/logs
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://otlp-gateway.grafana.net/otlp/v1/metrics
OTEL_EXPORTER_OTLP_HEADERS=Authorization=Basic base64(instanceId:apiKey)

If no endpoint is configured, telemetry stays disabled with zero overhead.

Usage

Hono services (Bun)

Wire instrumentMiddleware() to get per-request spans, HTTP metrics, and log context. Every console.* call within a request automatically includes requestId, traceId, path, and method in Grafana.

import '@crossdelta/telemetry'
import { instrumentMiddleware } from '@crossdelta/telemetry/middleware'
import { Hono } from 'hono'

const app = new Hono()
app.use('*', instrumentMiddleware())

Per request this creates:

  • An OTEL server span (http.method, http.target, http.status_code)
  • An http.server.request.duration histogram entry
  • ALS context with requestId, traceId, spanId, path, method for log correlation

The W3C traceparent header is propagated automatically, so all downstream services share the same traceId. NATS CloudEvents carry trace context via @crossdelta/cloudevents.

On Node.js (NestJS/Express), HttpInstrumentation handles spans and metrics automatically. instrumentMiddleware() only sets up the ALS context there.

Logging

For most cases, plain console.* works. The OTEL patch captures everything and attaches trace context automatically.

console.info('[ORDER:CREATED]', orderId)
console.error('[PAYMENT:FAILED]', reason)

For queryable key-value attributes in Grafana:

import { logInfo, logError } from '@crossdelta/telemetry/logger'

await logInfo('Order created', { orderId, total, tenantId })
await logError('Payment failed', { orderId, reason, provider })

Qwik apps

import { initRequestContext } from '@crossdelta/telemetry/logger'

export const onRequest: RequestHandler = async (ev) => {
  const requestId = initRequestContext(ev)
  ev.headers.set('X-Request-Id', requestId)
}

Custom initialization

For non-default settings, use initTelemetry() instead of the side-effect import:

import { initTelemetry } from '@crossdelta/telemetry'

initTelemetry({
  metricsIntervalMs: 30_000,
  onShutdown: async () => {
    await database.close()
  },
})

Runtime Support

All signals (logs, metrics, traces) work on both runtimes. The difference is how HTTP spans and metrics are created:

| Feature | Node.js | Bun | |---------|---------|-----| | HTTP spans | auto (HttpInstrumentation) | instrumentMiddleware() | | HTTP metrics (http.server.request.duration) | auto (HttpInstrumentation) | instrumentMiddleware() | | Express/NestJS tracing | Yes | No |

Supported Backends

Grafana Cloud, Better Stack, Jaeger — any OTLP endpoint works.

API Reference

Essential

| Export | From | Description | |--------|------|-------------| | import '@crossdelta/telemetry' | . | Auto-initialize SDK (side-effect import) | | instrumentMiddleware() | ./middleware | Hono middleware: server span, HTTP metrics, ALS context, X-Request-Id header | | logInfo(msg, data?) | ./logger | Structured info log with ALS context | | logWarn(msg, data?) | ./logger | Structured warning log with ALS context | | logError(msg, data?) | ./logger | Structured error log with ALS context | | logDebug(msg, data?) | ./logger | Structured debug log with ALS context | | initRequestContext(event) | ./logger | Set up per-request ALS context. Returns requestId. | | logger | ./logger | Universal logger object (server: Pino+ALS, client: console) |

Advanced

| Export | From | Description | |--------|------|-------------| | initTelemetry(config?) | . | Manual SDK initialization with custom options | | shutdownTelemetry() | . | Flush pending data and shut down the SDK | | getSDK() | . | Get the current NodeSDK instance (or null) | | extractTraceparent(request) | ./traceparent | Parse W3C traceparent header from a Request | | parseTraceparent(header) | ./traceparent | Parse a W3C traceparent string | | buildTraceparent(context) | ./traceparent | Build a W3C traceparent header from trace context | | getCurrentTraceparent() | ./traceparent | Get current traceparent from ALS or OTEL active span | | runWithTraceparent(header, fn) | ./traceparent | Run a function inside a trace context derived from a traceparent header | | runWithLogContext(context, fn) | ./logger | Run a function inside a custom ALS context | | buildRequestLogContext(req, url) | ./logger | Build a LogContext Map from a Request | | getLogContext() | ./logger | Read current ALS context as a plain object | | withLogging(name, fn, opts?) | ./logger | Wrap async function with auto error + slow-call logging | | serializeError(error) | ./logger | Serialize Error to { err, errName, stack, cause } |

In production, set OTEL_* vars via your secrets manager or CI/CD.

License

MIT