feat(core): OTLP trace exporter#7
Merged
Merged
Conversation
Adds a regression test asserting that createModule + Eden Treaty preserves per-route body/query schemas. Catches both failure modes observed pre-1.0.2 against @getvision/server@1.0.1: - "stomp" (every depth-1 POST resolves to one shared body shape) — caught via cross-route distinctness assertion. - intersection-merge (each route body becomes BodyA & BodyB & ...) — caught via per-route Equal<> probe. The contract is enforced at type level — `bun run typecheck:test` fails to compile if the prefix generic on createModule is ever removed. Verified by temporarily reverting <const Prefix extends string> and observing 8 type errors, then restoring. Test infra wiring: - new test/test:watch/typecheck:test scripts in @getvision/server - separate tsconfig.test.json so production build still excludes tests - @elysia/eden added as devDependency for the regression assertions No source changes — fix already shipped in 1.0.2 (commit 002b468). This is purely defensive scaffolding to keep the contract from regressing.
Add a generic exporter mechanism that fans completed traces out to OTLP/HTTP backends (BetterStack, Honeycomb, Grafana Tempo, an OTel Collector, …). The destination is purely endpoint + headers, so one exporter targets any OTLP-compatible backend. - core: `TraceExporter` interface + `VisionServerOptions.exporters`; fan-out in `completeTrace` (isolated per exporter) and flush on `stop()` - core: `OtlpTraceExporter` (OTLP/JSON over HTTP) with batching, random spec-compliant ids via Web Crypto, and Trace→OTLP transform (synthetic root SERVER span + nested INTERNAL spans, logs as span events) - server: forward `vision.exporters` into VisionCore; re-export OtlpTraceExporter - docs: README + docs-site config/section; mark OpenTelemetry export shipped
Address review feedback on the new OTLP exporter: - `maxQueueSize` (default 2048) is now a true hard cap — excess traces are dropped and reported via `onError` so the queue can't grow without bound when the backend is slow or down. Flush threshold is split out as `maxExportBatchSize` (default 512), matching the OTel SDK shape. - Failed batches are re-buffered for the next flush (respecting the cap) instead of silently dropped on a single 5xx/network error. - A `flushing` guard serializes concurrent flush() calls so the interval + threshold triggers can't stack N in-flight POSTs against the same endpoint. - Headers merge case-insensitively, so a user-supplied `Content-Type` actually overrides the default rather than producing both keys. - `onError` defaults to `console.warn` (was a silent no-op) and `VisionCore.exportTrace` warns on thrown exporters, so silent failures don't make local debugging impossible. - Public surface narrowed: the exporters barrel exports only `TraceExporter`, `OtlpTraceExporter`, and `OtlpExporterOptions`. - Tightened `transform.ts`: comment on the `error === true` contract with `createSpanHelper`; dropped the dead `?? newSpanId()` fallback. Adds behavioral tests covering overflow drop, eager flush, re-buffer on 5xx, serialized flush, and case-insensitive header merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@getvision/core: aTraceExporterinterface plusVisionServerOptions.exporters. Completed traces fan out incompleteTrace(each exporter isolated — a failing sink never affects request handling) and are flushed onstop().OtlpTraceExporter— OTLP/JSON over HTTP with batching. Works with any OTLP-compatible backend (BetterStack, Honeycomb, Grafana Tempo, Datadog, an OTel Collector); the destination is purelyendpoint+headers.SERVERspan,c.span(...)calls become nestedINTERNALspans, trace logs become span events. Span/trace ids are random and spec-compliant via Web Crypto (nonode:import, no hashing — cross-runtime).@getvision/server: forwardsvision.exportersintoVisionCoreand re-exportsOtlpTraceExporter.Usage
Test plan
@getvision/coreunit tests for theTrace → OTLPtransform (id format, span reparenting, status mapping, logs-as-events, payload shape) — 11/11 pass@getvision/serverAPI-contract test (exporter reachable + config acceptsTraceExporter[])bun test/bun run typecheck:testin CI (server tests can't run in the dev sandbox — deps not installed)endpointat a real OTLP backend and confirm traces arrive