Skip to content

SMOODEV-1067c: @smooai/observability-otel — OpenTelemetry foundation (Phase 1) - #4

Merged
brentrager merged 1 commit into
mainfrom
smoodev-1067c-otel-foundation
May 18, 2026
Merged

SMOODEV-1067c: @smooai/observability-otel — OpenTelemetry foundation (Phase 1)#4
brentrager merged 1 commit into
mainfrom
smoodev-1067c-otel-foundation

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Summary

First step of the full OTel migration. New package @smooai/observability-otel wraps the OTel NodeSDK + auto-instrumentations + OTLP/HTTP trace exporter, and bridges the core Client so every captureException records on the active OTel span.

Why this matters for users who don't have @smooai/logger

The bridge depends on @opentelemetry/api, not the Smoo logger. Any consumer using winston / pino / bunyan / console can pipe readOtelCorrelation() into their format and get the same trace-id flowing through logs, traces, and Smoo error groups. OTel is the universal interop — this package speaks it natively.

Public surface

  • setupOtelSdk({ serviceName, otlpEndpoint, environment, release, ... }) — idempotent Lambda / Node bootstrap. Returns { sdk, flush, shutdown }.
  • bridgeClientToOtel() — wraps Client.captureException / setUser / setTag to update OTel span attributes + status. Idempotent.
  • readOtelCorrelation() — read the active span's traceId / spanId / sampled flag.

Bridge behavior

Every captureException becomes a recorded exception on the active span with SpanStatusCode.ERROR. If no span is active at capture time (background job, raw process listener), a synthetic span observability.captureException is minted so the error still surfaces in the trace.

Where this sits in the larger migration

Phase Status
1. OTel foundation (this PR)
2. Backend ingest accepts OTLP/HTTP alongside Smoo-native not started
3. Rebuild @smooai/observability metrics SDK on OTel meters not started
4. @smooai/logger writes CONTEXT into OTel baggage not started
5. Auto-instrumentations rollout across backend Lambdas not started

Until Phase 2 lands, bridgeClientToOtel() is additive — Smoo's existing transport still ships events to the backend; OTel becomes a parallel output.

Test plan

  • pnpm --filter @smooai/observability-otel exec vitest run — 12/12 green (7 bridge + 5 setup).
  • pnpm --filter @smooai/observability-otel typecheck clean.
  • pnpm --filter @smooai/observability-otel build clean.

🤖 Generated with Claude Code

…(Phase 1)

First step of the OTel migration. New package wraps the OTel NodeSDK +
auto-instrumentations + OTLP/HTTP trace exporter, and bridges the core
Client so captureException also records on the active OTel span.

Why this matters for non-@smooai/logger users:
The bridge depends on @opentelemetry/api, not on the Smoo logger. Any
consumer with their own logger (winston, pino, bunyan, console) can pipe
readOtelCorrelation() into their format and get the same trace-id on
logs, traces, and Smoo error groups. OTel is the universal interop —
this package speaks it natively.

Public surface:
  - setupOtelSdk(options) — idempotent Lambda / Node bootstrap. Returns
    { sdk, flush, shutdown } so the host can wire flush into SIGTERM /
    beforeExit.
  - bridgeClientToOtel() — wraps Client.captureException / setUser /
    setTag to also update OTel span attributes + status. Idempotent.
  - readOtelCorrelation() — read the active span's traceId / spanId /
    sampled flag.

Bridge behavior: every captureException becomes a recorded exception
on the active span with SpanStatusCode.ERROR. If no span is active at
capture time (background job, raw process listener), a synthetic span
"observability.captureException" is minted so the error still surfaces
in the trace.

Tests: 12 green (7 bridge + 5 setup). Typecheck + build clean.

This is Phase 1 of the migration tracked under SMOODEV-1067c. Phase 2
swaps the ingest backend to accept OTLP/HTTP alongside the existing
Smoo-native wire format. Phase 3 rebuilds the metrics SDK on OTel
meters. Phase 4 turns @smooai/logger's context into OTel baggage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@brentrager
brentrager merged commit 2d2eed7 into main May 18, 2026
1 check passed
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