Fixing JavaScript observability, one library at a time

awad_dev1 pts0 comments

Fixing JavaScript observability, one library at a time | Sentry Blog

Skip to main content

← Back to Blog Home<br>Contents<br>Share

Over the past few weeks, we have been driving a cross-ecosystem effort to replace the “monkey-patching” that powers all JavaScript APM tools today with something built into the runtime. Here is why, how, and where it stands.

This applies to server-side JavaScript only (Node.js, Bun, Deno, Cloudflare Workers). Browsers do not have diagnostics_channel and lack the async context propagation primitives needed to polyfill it.

Monkey-patching does not scale

My teammate Sigrid wrote a detailed breakdown of why monkey-patching is failing and how TracingChannel solves it.

The short version: every JavaScript APM tool, including Sentry’s, instruments libraries by intercepting require() and import calls at runtime using import-in-the-middle (IITM) and require-in-the-middle (RITM). This breaks with ECMAScript Modules (ESM), does not work in non-Node runtimes, conflicts with bundlers, and couples us to internal implementation details we do not control. The SDK also must load before the library it instruments, or instrumentation silently does nothing.

This is not a Sentry-specific problem. Every APM vendor maintaining JavaScript instrumentation deals with the same fragility. The ecosystem is stuck.

Most library maintainers do not think about observability. They do not know what they would need to expose, and adopting something like OpenTelemetry means taking on an implementation burden, not just adding a standard. APMs managed to patch their way around this for years, so nobody on the library side ever had to figure it out.

But there’s a better way.

TracingChannels - observability without patching

In late 2025, we were working with Pooya Parsa (creator of Nitro, h3, and the unjs ecosystem) on the best way to build a Sentry SDK for the Nitro framework. During that conversation, my teammate Sigrid suggested we look into TracingChannel, a built-in API from Node’s diagnostics_channel module. Sigrid’s blog post covers that API in depth, but the core idea is simple: if a library publishes structured events on a TracingChannel, any APM tool can subscribe to those events without patching anything. The library just says “a query started” and “a query ended,” and whoever is listening can create spans from that.

Click to Copy<br>// Library side (e.g. inside mysql2)<br>import { tracingChannel } from 'diagnostics_channel';

const queryChannel = tracingChannel('mysql2:query');

queryChannel.tracePromise(async () => {<br>return await connection.query(sql);<br>}, { query: sql, serverAddress: host, serverPort: port });

The cost of this added code is minimal, so this is an easy sell for library maintainers. From APM’s side, we just need to subscribe to that tracing channel and we get the events. No IITM, no RITM, no loader hooks, no initialization ordering. Zero overhead when nobody is listening. Works across Node, Bun, and Deno. Bundler safe. The API has been available since Node 18, and dc-polyfill covers runtimes that lack it, which already matches our support range.

Everyone agrees, nobody is pushing

After getting enough learnings about the tracing channel API and how to make it work with OpenTelemetry, I opened an issue on Otel JS in November 2025 to discuss TracingChannel support.

The response was positive. A while after, someone from the OTel team even created a draft API approach for integrating TracingChannel into the OTel SDK.

But there is no significant push to drive ecosystem adoption. The draft exists; the ecosystem work does not.

Everyone agrees that TracingChannel is the future of JavaScript observability, but nobody is doing the work of getting libraries to adopt it. We have many instrumentations across databases, web frameworks, message queues, and AI providers that need TracingChannel support. That is a mountain of upstream PRs, each requiring understanding the library’s internals, writing a proposal that maintainers will accept, implementing the changes, and iterating on review feedback.

So I thought “fine, why not just get the ball rolling?”

The first step was proving the pattern works. I had already built TracingChannel support by hand in h3, srvx, unstorage, db0, and Nitro as part of the earlier SDK work. The unjs ecosystem was receptive and moved fast, which gave us shipped examples to point to and an end-to-end mental model: how events should be shaped, how context propagation flows, how to make it work with OTel, and what semantic conventions to follow.

We also learned early that you can’t just say “hey you should use TracingChannel,” which is just begging to be shelved to collect dust. Instead, like we did with Nitro, we say “Hey, we will do it for you and help you own it.” Accepting code into a repository adds a burden of maintenance, so we offer to help own it and make it part of the library.

With that in mind, I reached out to pg, mysql2, and redis to gauge their interest,...

library tracingchannel javascript ecosystem work observability

Related Articles