walletpress/backend/routers/metrics.py
cryptorugmunch e13bd4d774
Some checks are pending
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
CI / security (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / license (push) Waiting to run
CI / ai-review (push) Waiting to run
docs: apply fleet-template (16-artifact scaffold)
Adds missing standard artifacts:
- README.md (if missing)
- AGENTS.md (AI agent contract)
- PLAN.md (current sprint)
- STATUS.md (where we are)
- DEVELOPMENT.md (dev workflow)
- DEPLOYMENT.md (deploy procedure)
- TESTING.md (test strategy)
- DECISIONS.md (ADR index + templates)
- .github/CODEOWNERS
- .github/workflows/ci.yml

Preserves all existing artifacts.

Refs: RugMunchMedia/fleet-template
2026-07-02 02:07:06 +07:00

119 lines
4.4 KiB
Python

"""Prometheus metrics endpoint for operations monitoring.
Exposes /metrics in Prometheus text format for scraping by Prometheus,
Grafana, or any monitoring system.
Metrics:
walletpress_wallets_total — Total wallets in vault
walletpress_generations_total — Total wallet generations
walletpress_requests_total — Total API requests (by method, path, status)
walletpress_request_duration — Request latency histogram
walletpress_vault_encrypted — Whether vault encryption is enabled
walletpress_chains_supported — Number of supported chains
"""
from __future__ import annotations
import time
from fastapi import APIRouter, Request, Response
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from core.config import cfg
from core.vault import get_vault
from wallet_engine.generator import get_generator
from wallet_engine.chains import CHAINS
router = APIRouter(tags=["Metrics"])
_metrics_data = {
"requests": {"count": 0},
"start_time": time.time(),
}
class MetricsMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
start = time.monotonic()
response = await call_next(request)
time.monotonic() - start
_metrics_data["requests"]["count"] += 1
return response
@router.get("/metrics")
async def metrics():
vault = get_vault()
gen = get_generator(cfg.vault_password)
vault_stats = vault.stats()
lines = [
"# HELP walletpress_wallets_total Total wallets in vault",
"# TYPE walletpress_wallets_total gauge",
f"walletpress_wallets_total {vault_stats['total_wallets']}",
"",
"# HELP walletpress_encrypted_wallets Total encrypted wallets",
"# TYPE walletpress_encrypted_wallets gauge",
f"walletpress_encrypted_wallets {vault_stats['encrypted_wallets']}",
"",
"# HELP walletpress_generations_total Total wallets generated (this session)",
"# TYPE walletpress_generations_total counter",
f"walletpress_generations_total {gen.stats['generation_count']}",
"",
"# HELP walletpress_chains_supported Number of supported chains",
"# TYPE walletpress_chains_supported gauge",
f"walletpress_chains_supported {len(CHAINS)}",
"",
"# HELP walletpress_vault_encrypted Whether vault encryption is enabled",
"# TYPE walletpress_vault_encrypted gauge",
f"walletpress_vault_encrypted {1 if cfg.vault_password else 0}",
"",
"# HELP walletpress_requests_total Total API requests processed",
"# TYPE walletpress_requests_total counter",
f"walletpress_requests_total {_metrics_data['requests']['count']}",
"",
"# HELP walletpress_uptime_seconds Server uptime in seconds",
"# TYPE walletpress_uptime_seconds gauge",
f"walletpress_uptime_seconds {time.time() - _metrics_data['start_time']}",
"",
]
return Response("\n".join(lines), media_type="text/plain; charset=utf-8")
@router.get("/metrics/usage")
async def usage_dashboard():
"""Per-customer usage dashboard — rate limiting stats, request counts, active keys."""
vault = get_vault()
gen = get_generator(cfg.vault_password)
vault_stats = vault.stats()
from core.rate_limit import RateLimitMiddleware
from main import app
rate_limiter = None
for m in app.user_middleware:
if m.cls == RateLimitMiddleware:
rate_limiter = m
break
rate_stats = {}
if rate_limiter:
try:
rate_stats = rate_limiter.stats() if hasattr(rate_limiter, 'stats') else {}
except Exception:
pass
return {
"service": "WalletPress Usage Dashboard",
"uptime_seconds": int(time.time() - _metrics_data["start_time"]),
"requests_total": _metrics_data["requests"]["count"],
"rate_limiting": rate_stats,
"vault": {
"total_wallets": vault_stats["total_wallets"],
"encrypted_wallets": vault_stats["encrypted_wallets"],
"chains_used": vault_stats.get("chains_used", 0),
},
"generator": {
"generation_count": gen.stats["generation_count"],
"chains_supported": gen.stats["chains_supported"],
"encryption_enabled": gen.stats["encryption_enabled"],
},
"note": "Operational metrics. No customer data exposed.",
}