Debugging: traces of the engine

Opt-in. Set CSSINTS_TRACE=otlp (or otlp:http://host:port; the default is http://localhost:4318) before vite dev or vite build, and the plugin sends one trace per Vite hook to an OpenTelemetry backend over OTLP/HTTP (JSON). Unset, nothing is loaded and nothing runs: the hooks use Effect's own runSync and runPromiseExit, no tracer, no exporter, no HTTP client. The variable is read once, when the plugin loads.

docker run -d --rm --name cssints-jaeger -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one:latest
CSSINTS_TRACE=otlp bun run build        # or: CSSINTS_TRACE=otlp bun run dev, then edit a file
open http://localhost:16686             # service "cssints"; docker stop cssints-jaeger when done

Jaeger takes traces only, which is all there is: a warning or an error is an event on the span of its hook, not a log. Another OTLP backend (Grafana Tempo, grafana/otel-lgtm, any collector) works the same way through CSSINTS_TRACE=otlp:<its OTLP/HTTP base URL>.

The process must end the exporter or Node stays alive: vite build and server.close() do it (the closeBundle hook flushes and stops it); a script that exits by itself calls closeTrace() from cssints/src/trace.ts first. A backend that is not there costs a retry of up to three seconds at the end and loses the trace, nothing else.

packages/cssints/test/trace.mjs (in bun run test) checks the spans, the file attribute and the error's trace id against an in-process collector. node packages/cssints/test/trace-live.mjs builds apps/sky and runs its HMR test traced, then reads both traces back through Jaeger's API (GET /api/traces?service=cssints) and prints span counts and the slowest hooks; it skips when no backend answers. Effect's DevTools (the VS Code extension, effect/devtools) is not wired: it needs the editor's extension listening, so neither a script nor an agent can read it.