opentelemetry

OpenTelemetry tracing and HTTP metrics plugin for the Elysia web framework

Library
npm
v1.4.11
40stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
43/100Fair
Development Activity32
Maintenance44
Community28
Maturity48
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture74
Code Quality78
Innovation62
Learning Curve55

@elysiajs/opentelemetry wires distributed tracing and request metrics into an Elysia application with a single .use(opentelemetry()) call. It hooks into every stage of Elysia’s request lifecycle - parsing, transform, before/after handle, error, and response mapping - and turns each into a properly parented OpenTelemetry span under one root span per request, so a trace viewer shows exactly where time was spent inside the framework’s own pipeline, not just inside the route handler.

Beyond spans, it records an http.server.request.duration histogram with the standard OpenTelemetry HTTP semantic-convention buckets, and exposes helper functions (getTracer, startSpan, startActiveSpan, setAttributes, getCurrentSpan) so application code can add custom spans using the same tracer the plugin already configured. It boots a NodeSDK automatically only when no tracer provider is already registered, so teams that preload their own OpenTelemetry SDK configuration are not overridden.

Privacy is a first-class concern rather than an afterthought: query strings and URLs are redacted for a fixed set of sensitive keys (tokens, passwords, API keys, credentials) by default, credentials embedded in URLs are stripped, and request/response body or header capture is opt-in and disabled unless explicitly configured. This makes it usable in production HTTP services without manually auditing every span for leaked secrets.

What You Get

  • Automatic per-request root span plus child spans for every Elysia lifecycle hook (onRequest, onParse, onTransform, onBeforeHandle, onHandle, onAfterHandle, onError, onAfterResponse, onMapResponse)
  • An http.server.request.duration histogram metric recorded with OpenTelemetry HTTP semantic-convention bucket boundaries and attributes
  • Automatic bootstrap of a NodeSDK when no tracer provider is registered yet, or transparent pass-through when the host app already preloads its own OpenTelemetry SDK
  • Manual instrumentation helpers - getTracer, startSpan, startActiveSpan, setAttributes, getCurrentSpan - for adding custom spans and attributes from application code
  • Default redaction of sensitive query-string parameters (tokens, passwords, API keys, credentials) and stripped userinfo in captured URLs
  • Opt-in capture of request/response bodies and specific request/response headers via recordBody and headersToSpanAttributes, with a wildcard "*" option for debugging
  • A checkIfShouldTrace predicate to skip tracing for specific requests (e.g. health checks)

Common Use Cases

  • Production observability for an Elysia API - export traces and HTTP duration metrics to an OTLP collector (Jaeger, Grafana Tempo, Honeycomb, etc.) without hand-writing span instrumentation for every route.
  • Debugging slow requests - inspect per-hook child spans (parse, transform, handle) to see exactly which stage of the request pipeline is adding latency.
  • Compliance-conscious logging - rely on default query/URL redaction so access tokens and credentials in request URLs never end up in trace backends.
  • Custom span enrichment - use startActiveSpan/setAttributes inside route handlers or other plugins to attach domain-specific spans and attributes to the same trace the plugin already started.
  • GraphQL or RPC services built on Elysia - combine with @envelop/opentelemetry or Eden clients (as shown in the repo’s example app) to trace GraphQL resolvers alongside HTTP-level spans.

Under The Hood

Architecture The entire plugin lives in a single src/index.ts module that exports one factory function, opentelemetry(), plus a handful of standalone tracer helpers (getTracer, startSpan, startActiveSpan, setAttributes, getCurrentSpan). The factory registers an Elysia .wrap() handler that extracts propagated trace context from incoming request headers and opens a SpanKind.SERVER root span named Root for the whole request, then registers a global .trace({ as: 'global' }, ...) hook that taps every one of Elysia’s internal lifecycle events (onRequest, onParse, onTransform, onBeforeHandle, onHandle, onAfterHandle, onError, onAfterResponse, onMapResponse) and turns each into a correctly parented child span via a hand-rolled setParent/createContext bridge, because Elysia’s own trace-hook API does not carry an OpenTelemetry Context object natively. Ending of the root span, duration recording, and span-parent bookkeeping are all guarded against already-ended spans to tolerate early aborts (the module also listens for the request’s AbortSignal).

Tech Stack Written in TypeScript, depending directly on @opentelemetry/api, @opentelemetry/instrumentation, and @opentelemetry/sdk-node, with elysia >= 1.4.0 as a peer dependency. The package builds dual CJS/ESM output plus type declarations via a custom build.ts script driving tsup, and is tested with bun test against an extensive devDependencies list of OpenTelemetry exporters (Jaeger, OTLP proto/http, metrics) used only in test/example scenarios, alongside @elysiajs/eden and @elysiajs/graphql-yoga for testing RPC/GraphQL interop.

Code Quality The test suite is unusually extensive for a plugin of this size - ten dedicated test files (core, metrics, span-privacy, span-headers, abort, integration, advanced, single-hook-span) totaling over 2,200 lines, covering NodeSDK bootstrap detection, span parenting, redaction behavior, abort handling, and header/body capture opt-ins. A test-setup.ts provides shared span-capture utilities and lifecycle hooks (beforeEach/afterEach) to reset state between tests. Beyond the Bun test run, npm run test:node additionally installs and runs separate CJS and ESM smoke-test projects under test/node/, verifying the published package resolves correctly under both module systems - a level of interop testing not common in similarly sized plugins. CI runs build and test on every push and PR via GitHub Actions.

What Makes It Unique Most OpenTelemetry HTTP instrumentation packages either wrap a generic server framework generically or require the application to manually create spans per route. This plugin instead taps Elysia’s fine-grained internal lifecycle hooks directly, giving span-level visibility into parsing, validation/transform, and response-mapping phases specifically - not just “request in, response out” - while treating data privacy as a default-on concern (query redaction, no body/header capture unless opted in) rather than something the integrator must remember to configure separately.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search