The metrics catalogue
Every Prometheus metric TokenTriage registers, with its type, labels, when it is emitted, and which ones no code path increments yet.
On this page
Nineteen metric names are registered on the /metrics endpoint of the admin listener. Eighteen
are registered when the proxy starts; the nineteenth, tokentriage_otlp_dropped_total, is added
when span export is enabled.
They are grouped below by what they measure. Every name, type and label set here was read from the metric registry in the shipped build.
Two conventions apply to the whole catalogue. The model label always carries the model that was
served, after any rewrite, so it is bounded by your configuration rather than by what clients ask
for. And agent is not a label on anything, because agent names are unbounded; agent-level
questions are answered from the ledger instead.
Traffic
| Metric | Type | Labels | Emitted |
|---|---|---|---|
tokentriage_requests_total |
counter | dialect, path, mode, status |
once per inbound request, including refusals and passthroughs |
tokentriage_request_duration_seconds |
histogram | dialect, upstream, stream |
once per proxied request; end to end, upstream included |
tokentriage_decisions_total |
counter | mode, tier, rule, fail_safe |
no emitter in this build |
tokentriage_request_duration_seconds buckets run 0.05 s to 120 s, which is the range LLM calls
actually occupy. status is the HTTP status returned to the client, so a 429 from a governance
limit and a 200 are the same counter with different label values.
path on tokentriage_requests_total is the request path as the client sent it, which makes it
the one label in the catalogue whose value space your clients control. What a promoted dimension
costs has the
detail and the mitigation.
Cost and tokens
| Metric | Type | Labels | Emitted |
|---|---|---|---|
tokentriage_cost_usd_total |
counter | upstream, model, tier |
when a request resolves to a price above zero |
tokentriage_tokens_total |
counter | token_type, upstream, model |
once per token type with a count above zero |
tokentriage_pricing_miss_total |
counter | model |
when the price table has no entry for the served model |
token_type is a closed set of five values: input, output, cached_input,
cache_creation_input and reasoning. They adopt the GenAI convention’s vocabulary, so a
dashboard that sums by token_type reads the same way as one built over another producer.
An unpriced request adds nothing to tokentriage_cost_usd_total and adds one to
tokentriage_pricing_miss_total. It does not add a zero. A spend total that quietly counted
unpriced calls as free would understate the bill, and the miss counter is how you find out that
some rows are outside the total. tier is empty in ledger mode, where nothing is routed.
Latency of the proxy itself
| Metric | Type | Labels | Emitted |
|---|---|---|---|
tokentriage_proxy_overhead_seconds |
histogram | dialect |
once per request; pipeline time with the upstream excluded |
tokentriage_time_to_first_token_seconds |
histogram | dialect, upstream |
when a first response byte is timed |
Both are sub-millisecond-centric: overhead buckets run from 100 µs to 50 ms, and first-token
buckets from 25 ms to 16 s. tokentriage_time_to_first_token_seconds is observed on a narrower
population than tokentriage_requests_total, so its _count is legitimately lower. Measuring
your own overhead covers how to read them and what claims
the numbers do and do not support.
Routing
| Metric | Type | Labels | Emitted |
|---|---|---|---|
tokentriage_signal_duration_seconds |
histogram | provider |
once per signal provider per classified request |
tokentriage_upstream_cooldown |
gauge | upstream |
no emitter in this build |
tokentriage_oracle_requests_total |
counter | outcome |
no emitter in this build |
provider is a signal-provider name such as lexical or structural. Buckets run from 100 µs
to 25 ms, because signal evaluation is held to a sub-millisecond budget and a histogram scaled for
request latency would put every observation in one bucket.
Business dimensions
| Metric | Type | Labels | Emitted |
|---|---|---|---|
tokentriage_dim_requests_total |
counter | dim, value |
per request, per promoted dimension that has a value |
tokentriage_dims_dropped_total |
counter | reason |
when a tag or a promoted value is turned away |
Both are absent until ledger.dimensions.enabled is set, and tokentriage_dim_requests_total
stays absent until a dimension name is added to promote_to_metrics, which is empty by default.
reason has two values: max_tags for a tag beyond the per-request budget, and
promote_cardinality for a value beyond the fifty distinct values a promoted dimension admits.
What a promoted dimension costs is the page on both.
Governance
| Metric | Type | Labels | Emitted |
|---|---|---|---|
tokentriage_governance_refusals_total |
counter | type, limit_id |
no emitter in this build |
tokentriage_governance_limit_suspended |
gauge | limit_id |
no emitter in this build |
tokentriage_governance_gate_seconds |
histogram | stage |
no emitter in this build |
limit_id is always a limit definition id from your config rather than a per-scope instance, so
the label stays bounded however many tenants you have. The decision ledger records every refusal
with its full breach detail regardless; governance
refusals is where that data lives.
Drops
| Metric | Type | Labels | Emitted |
|---|---|---|---|
tokentriage_declog_dropped_total |
counter | none | when a ledger row is dropped on a full writer queue |
tokentriage_dash_stream_dropped_total |
counter | none | when a Live-feed event is dropped on a full client queue |
tokentriage_otlp_dropped_total |
counter | none | when a row is dropped on a full span-export queue |
These three are unlabelled counters, so they appear in every scrape at zero rather than being
absent until first use. tokentriage_otlp_dropped_total is the exception, added to the endpoint
only when span export is on. What a drop means explains what
each one costs you.
Metrics with no emitter in this build
Six of the nineteen are registered and never incremented, so they are absent from every scrape:
tokentriage_decisions_total
tokentriage_upstream_cooldown
tokentriage_oracle_requests_total
tokentriage_governance_refusals_total
tokentriage_governance_limit_suspended
tokentriage_governance_gate_seconds
That is a gap in the build rather than a property of your configuration, and it is stated here because a panel built on one of them is permanently empty and an alert written against one cannot fire. The underlying data exists: routing decisions, cooldowns, refusals and gate timings are all recorded on the ledger row, which is why the gap is a missing mirror rather than missing information.
How this list was verified
The names, types and label sets come from the metric registry the binary builds at start-up. The emitted-or-not column comes from two checks that agree: a search of the shipped source for a call site that increments each metric, and a live run.
The live run drove requests with identity headers, business dimensions, promoted labels, an
over-tagged request, sixty distinct tenant values, span export against a local collector, and a
governance deployment that authenticated a virtual key and rejected an anonymous request with a
401. Every metric with a call site appeared. None of the six appeared, including the governance
gate timing, which would have been observed on each admitted request had anything been recording
it.