feat: implement api endpoints to know usage per ip/s #143
No reviewers
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_aibroker!143
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "develop_usage_api"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The
request_logstable already had anipcolumn (indexed) and capturedmodel / tokens / cost per request — but every row was written with an empty
ip(ip: String::new()at all billing sites), and there was no endpointto query usage per IP. So we could see total and per-model spend, but not
which caller spent how much.
This wires up the missing piece: attribute each request to its source IP (the
Mycelium IPv6 when reached over the overlay) and expose it as a queryable,
admin-gated API.
What changed
main.rs): the peeraddress (previously discarded as
let (stream, _)) is stamped into requestextensions via a new
ClientIptype / extractor (middleware/client_ip.rs).The UDS accept loop is unchanged — same-host calls have no peer address and
fall back to
"unknown".CallContext.client_ip,populated in the 5 REST handlers (
chat,embedding,tts,stt,rerank), and written intorequest_logs.ipat every persist site(streaming + non-streaming + error paths).
middleware/request_log.rs):usage_by_ip(since, until)and
usage_for_ip(ip, since, until)(GROUP BYaggregations), plusIpUsage/ModelUsageresult types. Enabled WAL so the read-heavyusage queries don't block request logging.
api_openrpc/mod.rs), gated by the existingadmin_authmiddleware (same gate as admin/rpc; open in dev-mode whenno
ADMIN_TOKEN/HERO_SECRETis set):GET /billing/usageGET /billing/usage/{ip}Both accept optional
?since=&until=(unix-epoch-second bounds onstarted_at).Example
Testing
cargo clippy -p hero_aibroker_server -- -D warnings— clean.cargo test— 94 passing, incl. 3 new aggregation tests(
usage_by_ip_aggregates_and_ranks_by_spend,usage_by_ip_respects_time_bounds,usage_for_ip_breaks_down_by_model).GET /billing/usagereturns the caller IP with correct cost, and verifiedthe raw row (
request_logs.ip = 127.0.0.1).Out of scope / notes
X-Forwarded-Forresolution. Source IP = TCP peer, which is correctfor the direct-Mycelium deployment. Fronting with a reverse proxy (e.g.
hero_proxy) would need an XFF path gated ontrusted_proxy_ips.request_logs.db).