Prometheus exporter for routerai.ru API spend
  • Go 92.6%
  • Go Template 3.8%
  • Dockerfile 2.6%
  • Makefile 1%
Find a file
hermes-bot b7e25c5cc5
All checks were successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/chart-edge Pipeline was successful
ci/woodpecker/push/docker-edge Pipeline was successful
fix(chart): un-ignore chart yaml — .gitignore '*.yaml' silently excluded the whole chart
Chart.yaml/values.yaml/templates never reached git, so helm package
failed with 'Chart.yaml file is missing' and chart-* releases were
impossible. Whitelist chart/**/*.yaml.
2026-10-01 00:17:12 +00:00
.woodpecker ci: edge tagging — <branch> + <branch>-<shortsha> for image and chart 2026-10-01 00:08:18 +00:00
chart/routerai-exporter fix(chart): un-ignore chart yaml — .gitignore '*.yaml' silently excluded the whole chart 2026-10-01 00:17:12 +00:00
cmd/routerai-exporter fix: resolve golangci-lint v2.14 findings 2026-09-29 22:38:02 +00:00
examples routerai-exporter: Prometheus exporter for routerai.ru API spend 2026-09-27 17:16:14 +00:00
internal fix: resolve golangci-lint v2.14 findings 2026-09-29 22:38:02 +00:00
.gitignore fix(chart): un-ignore chart yaml — .gitignore '*.yaml' silently excluded the whole chart 2026-10-01 00:17:12 +00:00
.golangci.yml routerai-exporter: Prometheus exporter for routerai.ru API spend 2026-09-27 17:16:14 +00:00
Dockerfile routerai-exporter: Prometheus exporter for routerai.ru API spend 2026-09-27 17:16:14 +00:00
go.mod routerai-exporter: Prometheus exporter for routerai.ru API spend 2026-09-27 17:16:14 +00:00
go.sum routerai-exporter: Prometheus exporter for routerai.ru API spend 2026-09-27 17:16:14 +00:00
LICENSE routerai-exporter: Prometheus exporter for routerai.ru API spend 2026-09-27 17:16:14 +00:00
Makefile routerai-exporter: Prometheus exporter for routerai.ru API spend 2026-09-27 17:16:14 +00:00
README.md ci+chart: branch-scoped build cache, chart-* tags, monitoring resources 2026-09-29 23:36:02 +00:00

routerai-exporter

Warning

This is a vibecoded project. Built end-to-end by an AI agent (Hermes, Nous Research) from a conversational spec, with human review limited to architecture decisions and API contracts. It works — CI is green and the live gateway verifies the numbers — but treat it as unaudited: read the relay/proxy code before pointing production credentials at it, and don't trust the defaults blindly.

Prometheus exporter for routerai.ru API spend — money per API key, money and tokens per model, account balance.

Sibling of keen-exporter (same structure, config conventions and CI).

What it does

Two independent data paths:

  1. Passive scraping (always on). Polls the gateway account API on every scrape:

    • /v1/credits — account balance;
    • /v1/keys — spend, monthly spend and limits of every named API key (needs the account master key; with only a regular key it falls back to /v1/key, the self view).
  2. Relay mode (opt-in, relay: true). A transparent OpenAI-compatible proxy mounted at /relay/<account>/v1/...: point your OpenAI/Anthropic SDKs at it instead of https://routerai.ru/api/v1 and the exporter reads the exact cost the gateway itself reports (usage.cost in the response body, including the final SSE chunk), aggregating per model and provider. No scraping, no guessing from price lists — every sum comes from the gateway.

    Authorization passes through: clients may use their own routerai key (per-key attribution on the routerai side keeps working); when none is sent, the account default key is applied.

Metrics

All money metrics are in credits (the gateway's billing unit; a credit is billed in roubles today) and carry a currency="rub" label. Token/latency/meta metrics have no currency label.

Scrape & exporter meta

Metric Labels Meaning
routerai_up account 1 if the account API fetch succeeded
routerai_scrape_error account, reason 1 on failure; timeout|auth_failed|connection|http_5xx
routerai_scrape_duration_seconds account fetch duration
routerai_exporter_build_info version, commit, go_version build info

Balance & per-key spend (passive)

Metric Labels Meaning
routerai_account_credits account, currency account balance
routerai_key_usage_credits_total account, currency, key lifetime spend of a key (counter)
routerai_key_usage_monthly_credits_total account, currency, key current-month spend of a key
routerai_key_limit_credits account, currency, key monthly limit; 0 = unlimited
routerai_key_limit_remaining_credits account, currency, key remaining limit; absent for unlimited keys (the gateway reports garbage there)
routerai_key_disabled account, key 1 if the key is disabled
routerai_key_info account, key, limit_reset, created_at key identity

Per-model spend (relay mode only; appears with data)

Metric Labels Meaning
routerai_model_cost_credits_total account, currency, model, provider exact spend as reported by the gateway (counter)
routerai_model_requests_total account, model, provider completed requests
routerai_model_prompt_tokens_total account, model, provider prompt tokens (incl. cached)
routerai_model_completion_tokens_total account, model, provider completion tokens (incl. reasoning)
routerai_model_prompt_cached_tokens_total account, model, provider cached prompt tokens
routerai_model_reasoning_tokens_total account, model, provider reasoning tokens
routerai_model_request_duration_seconds_{bucket,sum,count} account, model, provider[, le] request latency histogram
routerai_relay_requests_total account, outcome passthrough attempts: ok, error_upstream, error_relay
routerai_relay_accounted_credits_total account, currency total money accounted by the relay since start

Relay counters are exporter-lifetime: they reset on restart (standard Prometheus counter handling) and do not persist.

Configuration

See examples/config.yaml. Secrets interpolate from the environment: ${VAR}, ${VAR:-fallback}, literal $ as $$; unknown keys are a hard error.

server:
  listen_address: ":9913"
  metrics_path: /metrics

log:
  level: info
  format: logfmt

routerai:
  base_url: https://routerai.ru/api
  timeout: 4s

relay:
  prefix: /relay
  max_idle_stream_timeout: 10m

accounts:
  - name: main
    key: ${ROUTERAI_API_KEY}          # regular key: balance + self metrics + relay default
    master_key: ${ROUTERAI_MASTER_KEY} # optional: per-key spend for all keys
    relay: true

Auth matrix (verified live against the gateway):

Credential /v1/credits /v1/key /v1/keys /v1/chat/completions
regular key ✅ ✅ ❌ 401 ✅
master key ❌ 401 ❌ 401 ✅ ❌

A master-only account works: balance is absent, per-key spend is present.

Usage

routerai-exporter serve --config routerai-exporter.yaml
routerai-exporter validate-config --config routerai-exporter.yaml
routerai-exporter probe --account main --config routerai-exporter.yaml  # one collect to stdout

Scrape /metrics, and — with relay enabled — point clients at http://<host>:9913/relay/<account>/v1 (OpenAI base URL) instead of https://routerai.ru/api/v1.

CI

Woodpecker (Forgejo webhooks, k8s backend), .woodpecker/:

Workflow Trigger What it does
test.yml push to main, tags golangci-lint v2.14 (go1.27 support), go test -race, govulncheck
docker-edge.yml push to main multi-arch image → cr.ppvn.ru/wailorman/routerai-exporter/app (edge + sha tags)
docker-release.yml tag v* multi-arch image → same repo (vX.Y.Z + latest)
chart.yml tag chart-* Helm chart → oci://cr.ppvn.ru/charts/routerai-exporter

Versioning: app releases are vX.Y.Z tags (docker-release); chart releases are independent — chart-X.Y.Z tags (chart.yml derives the chart version from the tag, appVersion is maintained in Chart.yaml and may lag/lead the app).

Build cache: per-branch tags in cr.ppvn.ru/wailorman/routerai-exporter/build-cache — cache_from lists the branch's entry with a fallback to main's (BuildKit ignores misses), cache_images writes the current branch's entry.

Registry auth via global Woodpecker secrets LOCAL_REGISTRY_USERNAME / LOCAL_REGISTRY_PASSWORD; buildx runs privileged via server-wide WOODPECKER_PLUGINS_PRIVILEGED.

Helm chart

chart/routerai-exporter — generic chart (no environment values baked in; the deployment side supplies tag, host and credentials).

Monitoring resources — all disabled by default, under one monitoring.enabled switch plus per-flavor toggles:

  • monitoring.serviceMonitor.enabled — prometheus-operator ServiceMonitor CRD;
  • monitoring.vmServiceScrape.enabled — VictoriaMetrics operator VMServiceScrape CRD;
  • monitoring.grafanaDashboard.enabled — Grafana sidecar dashboard (ConfigMap with the grafana_dashboard: "1" label) with a default spend dashboard: balance, per-key monthly spend, limit utilization, per-model spend rate, tokens, latency, relay errors.

Development

make all        # lint + test + build
make test       # go test ./... -race
make image      # local multi-arch image build

License

MIT — see LICENSE.