OpenTelemetry

OpenTelemetry

If your app already emits OpenTelemetry traces, Metrx can read its LLM spans directly: point an OTLP/HTTP exporter at the Metrx receiver.

Value
Endpointhttps://gateway.metrxbot.com/v1/traces
ProtocolOTLP/HTTP, JSON encoding only
Auth headerAuthorization: Bearer <METRX_API_KEY> (keys start with sk_live_)
Spans per requestAt most 100 LLM spans; extra spans are reported back as rejectedSpans, so set the batch size to 100
Body sizeAt most 1MB per request
⚠️

Direct protobuf is not supported yet. A request with a protobuf body is refused with 415 OTLP_PROTOBUF_UNSUPPORTED, and gRPC is not accepted. Exporters that can only send protobuf (Python’s, among others) go through an OpenTelemetry Collector, below.

Node.js: environment variables only

Node’s OTLP/HTTP exporter can send JSON, so environment variables are enough. In an OTel header value the space after Bearer is percent-encoded as %20:

export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://gateway.metrxbot.com/v1/traces"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/json"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer%20${METRX_API_KEY}"
export OTEL_RESOURCE_ATTRIBUTES="service.name=refund-triage"
export OTEL_BSP_MAX_EXPORT_BATCH_SIZE="100"

Then install the auto-instrumentations and load them when the app starts:

npm install @opentelemetry/api@1.9.1 @opentelemetry/auto-instrumentations-node@0.81.2 openai@6.49.0
node --require @opentelemetry/auto-instrumentations-node/register app.js

The OpenAI instrumentation records spans for openai 4.19 to 6.x only. With openai 7 it records nothing and reports no error, so the install pins openai@6.49.0.

Calls are recorded under the agent key in the span or resource attribute metrx.agent_key when present, else under service.name. Each trace is one task unless a span carries metrxbot.task_id.

Python and other protobuf exporters: through a Collector

Python’s OTLP/HTTP exporter has no JSON encoding: asking it for http/json fails with Unsupported OTLP protocol 'http/json'. Run an OpenTelemetry Collector next to the app. It receives protobuf or gRPC from the app and re-encodes the traces to JSON for Metrx:

# otel-collector.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
 
processors:
  batch:
    send_batch_size: 100
    send_batch_max_size: 100
 
exporters:
  otlphttp/metrx:
    traces_endpoint: https://gateway.metrxbot.com/v1/traces
    encoding: json
    compression: none
    headers:
      Authorization: "Bearer ${env:METRX_API_KEY}"
 
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/metrx]

Start the Collector with METRX_API_KEY in its environment, then point the app at it:

export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_SERVICE_NAME="refund-triage"

The batch processor keeps each request to Metrx at or under the 100-span cap. The same Collector works for any SDK that only speaks protobuf or gRPC.

Errors

The receiver answers with the gateway’s error body, { error, code, hint, docs }. The codes you will see here are MISSING_API_KEY, UNAUTHORIZED, OTLP_PROTOBUF_UNSUPPORTED, PAYLOAD_TOO_LARGE and INVALID_JSON; Errors says what to do about each.