inference/research
verifiedhigh · 0.90updated 2026-10-05

Envoy AI Gateway token usage histogram (OTel gen_ai semconv)

envoy-ai-gateway · histogram

Fields

id
metric-exposures/w5e-envoy-ai-gateway-gen-ai-client-token-usage
Metric name
gen_ai.client.token.usage
Metric type
histogram
Unit
tokens
Exposure
prometheus
Endpoint
:8080/metrics (Prometheus reader always attached)
Histogram buckets
141664256102440961638465536262144104857641943041677721667108864
Labels
gen_ai.operation.namegen_ai.provider.namegen_ai.request.modelgen_ai.response.modelgen_ai.token.typegen_ai.backend
notes
WithDescription('Number of tokens processed.') and WithUnit('token'). Declared as a HISTOGRAM, not a counter - which is the OTel GenAI semconv choice so that input and output token distributions can be read separately, discriminated by the gen_ai.token.type attribute (values 'input' and 'output'). If you are porting a dashboard from an engine where token counts are monotonic counters, the rate() over this is not equivalent. 14 explicit bounds from 1 token to 67 million. Envoy AI Gateway main (envoyproxy/ai-gateway), read 2026-10-05. Metrics go through an OpenTelemetry MeterProvider (internal/metrics/metrics.go NewMeterFromEnv), not a bare prometheus_client registry: a Prometheus reader is ALWAYS attached, and a console or OTLP exporter is added additionally when OTEL_METRICS_EXPORTER is 'console', or when it is neither 'none' nor 'prometheus' and an OTLP endpoint env var is set. OTEL_SDK_DISABLED=true turns off the extra exporters but not the Prometheus reader. That means the metric names are dotted OTel names (gen_ai.server.*), which the Prometheus exporter renders with dots replaced by underscores and a unit suffix appended - so the scraped series is NOT the literal constant in genai.go. Names follow the OpenTelemetry GenAI semantic conventions, not any engine's private scheme.

Notes

WithDescription('Number of tokens processed.') and WithUnit('token'). Declared as a HISTOGRAM, not a counter - which is the OTel GenAI semconv choice so that input and output token distributions can be read separately, discriminated by the gen_ai.token.type attribute (values 'input' and 'output'). If you are porting a dashboard from an engine where token counts are monotonic counters, the rate() over this is not equivalent. 14 explicit bounds from 1 token to 67 million. Envoy AI Gateway main (envoyproxy/ai-gateway), read 2026-10-05. Metrics go through an OpenTelemetry MeterProvider (internal/metrics/metrics.go NewMeterFromEnv), not a bare prometheus_client registry: a Prometheus reader is ALWAYS attached, and a console or OTLP exporter is added additionally when OTEL_METRICS_EXPORTER is 'console', or when it is neither 'none' nor 'prometheus' and an OTLP endpoint env var is set. OTEL_SDK_DISABLED=true turns off the extra exporters but not the Prometheus reader. That means the metric names are dotted OTel names (gen_ai.server.*), which the Prometheus exporter renders with dots replaced by underscores and a unit suffix appended - so the scraped series is NOT the literal constant in genai.go. Names follow the OpenTelemetry GenAI semantic conventions, not any engine's private scheme.

Cross-references