Skip to content

feat(otel): OpenTelemetry integration across all framework levels - #3

Merged
vitalics merged 3 commits into
mainfrom
feat/otel-all-levels
Jul 20, 2026
Merged

feat(otel): OpenTelemetry integration across all framework levels#3
vitalics merged 3 commits into
mainfrom
feat/otel-all-levels

Conversation

@vitalics

Copy link
Copy Markdown
Owner

Summary

Real OpenTelemetry SDK (@opentelemetry/* 2.x, traces + metrics over OTLP/HTTP) on every framework level, built around a single shared core so level packages never import OTel directly.

New packages

  • @youneed/otel — core: startNodeOtel() / startWebOtel() (OTLP/HTTP traces+metrics, W3C+baggage propagators, flush on pagehide), env-aware config (OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SDK_DISABLED), injectHeaders/extractHeaders, instrumentedFetch() (plugs into @youneed/http-client), global metrics useGlobalCounter/useGlobalHistogram (same name = one process-wide instrument, lazily bound after SDK start), and createOtelApi() — the shared this.otel surface.
  • @youneed/server-plugin-otelotel() plugin + otelMiddleware(): SERVER span per request with remote-parent extraction, http.server.request.duration / http.server.active_requests metrics, ctx.state.span facade (logger correlation keeps working); otelProvider() — typed this.otel in controllers with per-request traceId/spanId (works for HTTP + WS JSON-RPC).
  • @youneed/cli-plugin-otelotelPlugin() + otelCommand(): span per command execution, cli.command.* metrics, flush+shutdown in afterCommand before exit.
  • @youneed/dom-provider-otelinitDomOtel() + otelProvider(): dom.render/effect/event spans in the browser via the Web SDK; Node SDK never enters the browser bundle (subpath exports).
  • @youneed/test-plugin-otelotel() TestPlugin: span per test with steps and failure status, test.* metrics, trace-id in metadata.otel; OtelFixture injects this.otel into test classes.
  • @youneed/logger-plugin-oteltrace_id/span_id/trace_flags of the active span stamped on every log record.
  • @youneed/ssr-plugin-otelotelModule(): ssr.render <url> spans + metrics for static page renders, nesting under server-plugin-otel.

Every contributed this.otel (server/dom/cli/test) exposes counter(name)/histogram(name) — the process-wide global metrics, so a metric like url_calls is shared by app code and all tests.

Also

  • server-middleware-metrics: useGlobalCounter/useGlobalHistogram for the Prometheus exposition, plus a fix for a pre-existing histogram-bucket double-counting bug (values were stored AND rendered cumulatively).
  • examples/otel end-to-end demo: stub OTLP receiver + server plugin + instrumentedFetch — client and server spans share one traceId (pnpm examples:otel).
  • Zero-dep server-middleware-trace + server-plugin-otlp remain untouched as the SDK-free alternative.

Verification

  • 62 tests green across the 8 touched packages; builds clean.
  • Root pnpm typecheck shows only the pre-existing server-plugin-devtools --jsx error (unrelated, exists on main).

Changesets

otel-all-levels, global-metrics-api, otel-providers — minor for all new/changed packages.

Real OTel SDK (@opentelemetry/* 2.x) on every level, traces + metrics over OTLP/HTTP:

- @youneed/otel: shared core — startNodeOtel/startWebOtel, W3C propagation,
  instrumentedFetch, useGlobalCounter/useGlobalHistogram (lazy-binding global
  metrics), createOtelApi (shared this.otel surface)
- @youneed/server-plugin-otel: otel() plugin + otelMiddleware() (SERVER spans,
  http.server.* metrics, ctx.state.span facade) + otelProvider() for controllers
- @youneed/cli-plugin-otel: otelPlugin() + otelCommand() (span per command,
  flushed before exit)
- @youneed/dom-provider-otel: initDomOtel() + otelProvider() (render/effect/event
  spans, flush on pagehide)
- @youneed/test-plugin-otel: otel() TestPlugin (span per test) + OtelFixture
- @youneed/logger-plugin-otel: trace_id/span_id/trace_flags on every record
- @youneed/ssr-plugin-otel: otelModule() (ssr.render spans for static pages)
- examples/otel end-to-end demo (client+server share one traceId)
- fix(server-middleware-metrics): histogram buckets double-counting + global
  useGlobalCounter/useGlobalHistogram for the Prometheus exposition

Changesets: otel-all-levels, global-metrics-api, otel-providers (all minor)
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
youneed Ready Ready Preview, Comment Jul 20, 2026 10:30am

vitalics added 2 commits July 20, 2026 13:16
…land

web.ts → ext.ts → flow.tsx (@xyflow/react) is esbuild-bundled at build time,
but the root tsc typecheck still resolves the import chain and needs a jsx
mode to parse it. Set "jsx": "react-jsx" in the typecheck-only root config
(noEmit; package builds extend tsconfig.base.json directly and are unaffected).
flow.tsx now gets real typecheck coverage as a side effect.
devtools-protocol/src/server.ts imports @youneed/server-plugin-jsonrpc
(+ /devtools) but the specifier was in neither tsconfig.base.json paths nor
the package deps — it only resolved locally via a stale node_modules symlink,
so CI (fresh install) failed with TS2307. Register both paths entries (the
repo-wide convention for cross-package imports) and fix the /devtools import
to be the side-effect import it always was (the module only registers
renderers; it has no default export).
@vitalics
vitalics merged commit d16e110 into main Jul 20, 2026
4 checks passed
@vitalics
vitalics deleted the feat/otel-all-levels branch July 20, 2026 10:47
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.

1 participant