feat: user identity + error name tracking in metrics
CI / CI (pull_request) Successful in 12m36s

- ERRORS_BY_USER: labeled counter {user_id, endpoint, error_name}
- REQUESTS_BY_USER: labeled counter {user_id, endpoint}
- extract_user_id(): decode JWT sub claim from Authorization header
- Error names: auth_failure, forbidden, rate_limited, bad_request, embedding_failure
- Ingest handler: tracks user_id from claims.sub
- Query handler: tracks user_id from JWT decode
- Context handler: tracks user_id from claims.sub
- render_labeled_counter(): generic Prometheus label renderer
- User identity from gateway JWT (claims.sub per API.md)
- 515 tests passing
This commit is contained in:
2026-09-13 22:02:56 +09:00
parent 49dcf2616c
commit 3e7344787e
4 changed files with 96 additions and 16 deletions
+12
View File
@@ -491,13 +491,19 @@ pub async fn ingest_handler(
Err(e) => {
INGEST_AUTH_FAILURES.inc();
INGEST_ERRORS_TOTAL.inc();
ERRORS_BY_USER.inc(&["unknown", "/memory/ingest", "auth_failure"]);
INGEST_IN_FLIGHT.dec();
return e;
}
};
let user_id = &claims.sub;
REQUESTS_BY_USER.inc(&[user_id, "/memory/ingest"]);
if !has_capability(&claims, "memory:write") {
INGEST_AUTH_FAILURES.inc();
INGEST_ERRORS_TOTAL.inc();
ERRORS_BY_USER.inc(&[user_id, "/memory/ingest", "forbidden"]);
INGEST_IN_FLIGHT.dec();
return HttpResponse::Forbidden().json(json!({
"error": "forbidden",
@@ -506,6 +512,7 @@ pub async fn ingest_handler(
}
if let Err(e) = check_rate_limit(&claims, &state, "/memory/ingest") {
INGEST_RATE_LIMITED.inc();
ERRORS_BY_USER.inc(&[user_id, "/memory/ingest", "rate_limited"]);
INGEST_IN_FLIGHT.dec();
return e;
}
@@ -1044,12 +1051,17 @@ pub async fn context_handler(
Ok(c) => c,
Err(e) => {
CONTEXT_ERRORS_TOTAL.inc();
ERRORS_BY_USER.inc(&["unknown", "/memory/context", "auth_failure"]);
return e;
}
};
let user_id = &claims.sub;
REQUESTS_BY_USER.inc(&[user_id, "/memory/context"]);
if !has_capability(&claims, "memory:read") {
CONTEXT_ERRORS_TOTAL.inc();
ERRORS_BY_USER.inc(&[user_id, "/memory/context", "forbidden"]);
return HttpResponse::Forbidden().json(json!({
"error": "forbidden",
"reason": "missing capability: memory:read"