Skip to content

feat(server-utils): Add @opentelemetry/instrumentation-koa orchestrion integration#22146

Open
s1gr1d wants to merge 2 commits into
developfrom
sig/rewrite-koa-orchestrion
Open

feat(server-utils): Add @opentelemetry/instrumentation-koa orchestrion integration#22146
s1gr1d wants to merge 2 commits into
developfrom
sig/rewrite-koa-orchestrion

Conversation

@s1gr1d

@s1gr1d s1gr1d commented Jul 9, 2026

Copy link
Copy Markdown
Member

Adds koaChannelIntegration in @sentry/server-utils for injecting orchestrion channels into koa.

A subscriber wraps each registered layer in a span-creating proxy.
Span-helpers are ported from the vendored instrumentation, preserving span names (but adapting to new conventions - check todo comments).

One thing to know for review: we instrument koa-compose, not use from koa. koa's use lives in koa's main entry (lib/application.js), and transforming a package's main entry forces its top-level require chain through Node's require(esm) bridge, which throws on Node < 24.13.

  1. Orchestrion instruments by rewriting a module's source at load time (via the ESM load hook).
  2. use lives in koa's main entry (lib/application.js), so to instrument it we transform that file. But transforming a main entry pulls its whole top-level require chain into the loader's handling --> and that changes how those requires are loaded (through the ESM→CommonJS translator, not the normal sync require path).
  3. koa is CJS (but support ESM). When importing koa, it loads a shim that loads the CJS code: import 'koa'dist/koa.mjs (a ESM shim) → import '../lib/application.js' (CJS). That CJS entry has a top-level require('is-generator-function').
  4. is-generator-functionrequire('generator-function'), and generator-function points at an .mjs file, which in turn imports ./index.js.
    --> So the top-level require in koa's application.js (CJS) becomes require(esm) of an ESM file importing a CJS file.
  5. On Node < 24.13 (we pin 20.19.5), the loader can't pre-link this dual-package shape into the require(esm) cache, so it throws request for './index.js' is not in cache.

The failing chain:

koa/lib/application.js (CJS)
  └─ require('is-generator-function')        (CJS)
       └─ require('generator-function')      → require(esm) → require.mjs (ESM)
            └─ import './index.js'            (ESM importing CJS)

koa-compose is koa's zero-dependency dispatch engine, so it's safe to transform, and compose(app.middleware) sees the same layers use would. Since @koa/router also calls compose per request, the subscriber uses getActiveSpan() to only wrap at app startup (no active span) and skip the per-request router composition.

Closes #20758

Linear: https://linear.app/getsentry/issue/JS-2409/rewrite-opentelemetryinstrumentation-koa-to-orchestrion

@s1gr1d s1gr1d requested a review from a team as a code owner July 9, 2026 13:52
@s1gr1d s1gr1d requested review from JPeer264, andreiborza and mydea and removed request for a team July 9, 2026 13:52
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️ Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

Path Size % Change Change
@sentry/browser 27.59 kB - -
@sentry/browser - with treeshaking flags 26.03 kB - -
@sentry/browser (incl. Tracing) 46.34 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.13 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.12 kB - -
@sentry/browser (incl. Tracing, Replay) 85.62 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 75.26 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 90.32 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 102.97 kB - -
@sentry/browser (incl. Feedback) 44.76 kB - -
@sentry/browser (incl. sendFeedback) 32.38 kB - -
@sentry/browser (incl. FeedbackAsync) 37.51 kB - -
@sentry/browser (incl. Metrics) 28.67 kB - -
@sentry/browser (incl. Logs) 28.91 kB - -
@sentry/browser (incl. Metrics & Logs) 29.59 kB - -
@sentry/react 29.38 kB - -
@sentry/react (incl. Tracing) 48.61 kB - -
@sentry/vue 33.03 kB - -
@sentry/vue (incl. Tracing) 48.3 kB - -
@sentry/svelte 27.61 kB - -
CDN Bundle 30 kB - -
CDN Bundle (incl. Tracing) 48.32 kB - -
CDN Bundle (incl. Logs, Metrics) 31.57 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 49.64 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 70.81 kB - -
CDN Bundle (incl. Tracing, Replay) 85.84 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 87.14 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 91.64 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 92.92 kB - -
CDN Bundle - uncompressed 89.35 kB - -
CDN Bundle (incl. Tracing) - uncompressed 146.1 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 94.05 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 150.07 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 218.78 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 265.3 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 269.26 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 282.95 kB - -
@sentry/nextjs (client) 51.16 kB - -
@sentry/sveltekit (client) 46.78 kB - -
@sentry/core/server 78.42 kB - -
@sentry/core/browser 64.74 kB - -
@sentry/node-core 62.72 kB - -
@sentry/node 125.37 kB -0.01% -3 B 🔽
@sentry/node (incl. diagnostics channel injection) 139.06 kB +0.38% +516 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 69.95 kB - -
@sentry/node/light 50.72 kB - -
@sentry/node - without tracing 74.06 kB +0.01% +1 B 🔺
@sentry/aws-serverless 85.5 kB +0.01% +1 B 🔺
@sentry/cloudflare (withSentry) - minified 181.71 kB - -
@sentry/cloudflare (withSentry) 449.16 kB - -

View base workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-koa to orchestrion

1 participant