Skip to content

feat: upgrade to OpenTelemetry 2.x and capture exception source automatically - #31

Open
bhogayatakb wants to merge 1 commit into
masterfrom
auto-exception-code-capturing
Open

feat: upgrade to OpenTelemetry 2.x and capture exception source automatically#31
bhogayatakb wants to merge 1 commit into
masterfrom
auto-exception-code-capturing

Conversation

@bhogayatakb

Copy link
Copy Markdown
Member

…atically

Express users currently have to register an error handler by hand to get exception code capture, and even then only Express is covered. This moves the capture into the SDK so it works for every instrumentation, and lifts the OTel dependencies to 2.x to make that possible.

Why the upgrade is required

instrumentation-express 0.42 (pinned by auto-instrumentations 0.50) ends a route handler's layer span before invoking the handler, so its own recordException lands on an ended span and is dropped. Nothing records a route-handler throw, which is why registerErrorHandler exists. Upstream fixed this in instrumentation-express 0.48, which depends on OTel 2.x core and so cannot be taken on its own.

Exception source capture

NodeSDK's traceExporter is replaced by an explicit spanProcessors array so @middleware.io/otel-extensions can enrich exception events with exception.stack_details before export. NodeSDK wrapped traceExporter in exactly this BatchSpanProcessor, so batching and OTEL_BSP_* are unchanged.

errorhandler.ts drops its hand-rolled stack parsing (~60 lines) for a plain span.recordException; the processor produces a superset of the same keys, plus source-map resolution, whole-function capture instead of a fixed +/-10 line window, correct 1-based start_line/end_line, and node_modules frames trimmed to location only. The handler and its docs step are kept for now -- removal is a public API change and a separate decision.

Dependency and API changes

17 OTel packages moved to 2.x (sdk-node 0.53 -> 0.222, sdk-trace-* / resources / core 1.26 -> 2.11, auto-instrumentations 0.50 -> 0.80):

  • Detector/DetectorSync -> ResourceDetector; *DetectorSync lost the suffix
  • new Resource(attrs) -> resourceFromAttributes(attrs)
  • LoggerProvider.addLogRecordProcessor removed; processors are constructor-only, and BatchLogRecordProcessor now takes { exporter }
  • ResourceAttributes type removed -> Attributes from @opentelemetry/api

engines is set to OTel 2.x's own range, ^18.19.0 || >=20.6.0. Node 14 and 16 users should move to @middleware.io/node-apm-legacy.

Instrumentation coverage

auto-instrumentations 0.80 no longer bundles instrumentation-fastify, so it is carried as a direct dependency and registered explicitly, honouring the existing "fastify" disable key. The package is deprecated upstream in favour of @fastify/otel; migrating is follow-up work.

instrumentation-redis-4 merged into instrumentation-redis; the "redis-client" disable key now points there and keeps working.

Express 5 moved routing into the standalone router package, which has its own instrumentation in the bundle. With both active every layer is traced twice and every exception recorded on each copy -- measured at 22 spans and 3 exception events over 3 requests, against 11 and 1 with router off, with identical routes, middleware, http.route and enriched exception. Router instrumentation is now disabled when express is resolvable; apps using router directly still get it, and "router" is a recognised disable key.

Verified

Express 5 route-handler throw with no error handler registered now yields exception.stack_details with 8 frames, 3 carrying source. Express 4 behaves identically. Logs, metrics (including opentelemetry-node-metrics against sdk-metrics 2.x) and vcs.* resource attributes all confirmed working. Build clean, 24 tests pass.

…atically

Express users currently have to register an error handler by hand to get
exception code capture, and even then only Express is covered. This moves
the capture into the SDK so it works for every instrumentation, and lifts
the OTel dependencies to 2.x to make that possible.

Why the upgrade is required
---------------------------
instrumentation-express 0.42 (pinned by auto-instrumentations 0.50) ends a
route handler's layer span *before* invoking the handler, so its own
recordException lands on an ended span and is dropped. Nothing records a
route-handler throw, which is why registerErrorHandler exists. Upstream
fixed this in instrumentation-express 0.48, which depends on OTel 2.x core
and so cannot be taken on its own.

Exception source capture
------------------------
NodeSDK's traceExporter is replaced by an explicit spanProcessors array so
@middleware.io/otel-extensions can enrich exception events with
exception.stack_details before export. NodeSDK wrapped traceExporter in
exactly this BatchSpanProcessor, so batching and OTEL_BSP_* are unchanged.

errorhandler.ts drops its hand-rolled stack parsing (~60 lines) for a plain
span.recordException; the processor produces a superset of the same keys,
plus source-map resolution, whole-function capture instead of a fixed +/-10
line window, correct 1-based start_line/end_line, and node_modules frames
trimmed to location only. The handler and its docs step are kept for now --
removal is a public API change and a separate decision.

Dependency and API changes
--------------------------
17 OTel packages moved to 2.x (sdk-node 0.53 -> 0.222, sdk-trace-* /
resources / core 1.26 -> 2.11, auto-instrumentations 0.50 -> 0.80):

  - Detector/DetectorSync -> ResourceDetector; *DetectorSync lost the suffix
  - new Resource(attrs) -> resourceFromAttributes(attrs)
  - LoggerProvider.addLogRecordProcessor removed; processors are
    constructor-only, and BatchLogRecordProcessor now takes { exporter }
  - ResourceAttributes type removed -> Attributes from @opentelemetry/api

engines is set to OTel 2.x's own range, ^18.19.0 || >=20.6.0. Node 14 and 16
users should move to @middleware.io/node-apm-legacy.

Instrumentation coverage
------------------------
auto-instrumentations 0.80 no longer bundles instrumentation-fastify, so it
is carried as a direct dependency and registered explicitly, honouring the
existing "fastify" disable key. The package is deprecated upstream in favour
of @fastify/otel; migrating is follow-up work.

instrumentation-redis-4 merged into instrumentation-redis; the "redis-client"
disable key now points there and keeps working.

Express 5 moved routing into the standalone `router` package, which has its
own instrumentation in the bundle. With both active every layer is traced
twice and every exception recorded on each copy -- measured at 22 spans and
3 exception events over 3 requests, against 11 and 1 with router off, with
identical routes, middleware, http.route and enriched exception. Router
instrumentation is now disabled when express is resolvable; apps using
`router` directly still get it, and "router" is a recognised disable key.

Verified
--------
Express 5 route-handler throw with no error handler registered now yields
exception.stack_details with 8 frames, 3 carrying source. Express 4 behaves
identically. Logs, metrics (including opentelemetry-node-metrics against
sdk-metrics 2.x) and vcs.* resource attributes all confirmed working. Build
clean, 24 tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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