Skip to main content
If you’re already instrumented with OpenTelemetry — via the OTel SDK, the Vercel AI SDK’s telemetry, OpenLLMetry, OpenInference, or a Collector — you don’t need @glassray/tracing. Point your exporter at the OTLP endpoint:
The key comes from adding an OpenTelemetry source under Settings → Sources — the same key the SDK uses. The full endpoint reference (formats, gzip, size limits, error codes) is on the OpenTelemetry ingestion page.

The delivery contract: whole trace per request

This is the one thing raw-OTel users must know. Glassray’s ingest replaces, not merges, per trace ID: within one request, spans are grouped by traceId into one document per trace (multiple traces per request are fine) — but across requests, the latest push of a trace ID overwrites the previous one. That interacts badly with the default OTel export strategies:
  • A vanilla BatchSpanProcessor flushes on size/time, splitting one run’s spans across several requests — every batch overwrites the last, silently losing the earlier spans of long runs.
  • A SimpleSpanProcessor sends one request per span — the trace degenerates to whichever span arrived last.

The fix: force-flush per run

Make each run’s spans ship together by forcing a flush when the run’s root span ends:
With a Collector in the path, the same logic applies to its batch processor — one run’s spans must leave in one export. If your runs are short-lived processes (a CLI, a job), flushing on process exit is enough.
This is exactly the contract @glassray/tracing automates: it buffers each run and POSTs once when the root settles. If you’re not already invested in OTel, the SDK is the path with no caveats. Server-side span merging (which would lift this contract for arbitrary collectors) is on the roadmap, not available today.

Attributes Glassray reads

Standard vocabularies light up automatically: gen_ai.* (operation, model, provider, token usage, gen_ai.input.messages / gen_ai.output.messages, plus the older indexed gen_ai.prompt.{i}.* / gen_ai.completion.{i}.* family) and OpenInference’s generic input.value / output.value. Support for other vendor-specific content attributes (Vercel AI SDK ai.*, OpenInference’s indexed llm.* messages, Traceloop) is still expanding — with those instrumentations, structure/model/tokens land today and content coverage depends on which of the attributes above they emit. Trace-level input/output is read from the root span’s content attributes, and session.id groups conversation turns. To carry Glassray’s metadata convention, set glassray.customer / glassray.agent / glassray.flow as resource attributes (root-span attributes override); add glassray.customer.name / glassray.customer.email beside the customer identifier (glassray.customer.id is accepted as its spelling too) and Glassray names the customer for you. The former glassray.environment / deployment.environment.name dimension is retired — the ingest key selects the project, so both attributes are ignored.

Usage and cost attributes

Glassray prices each LLM span from the token attributes it carries, so put them on the span that made the call. The one thing to get right is which cache spelling you use, because it tells Glassray how your provider counted: Use one convention per span: emit the Anthropic keys when your input_tokens excludes the cache, the OpenAI key when it includes it. If a span carries a cache write and no read, still emit the read key (as 0) in the spelling that matches your convention — that is what Glassray reads the convention from. The Vercel AI SDK’s ai.usage.* attributes are recognised too and treated as inclusive. Unknown models price to blank, never to $0; see Cost for how model ids are matched.