Observability: Prometheus metrics, log panel, runbook
- GET /api/metrics renders Prometheus text (equity, P&L, per-strategy equity/pnl/allocation/halted, info) with no client library. - In-memory ring log handler (app/logs.py) exposed at GET /api/logs and a dashboard "Server logs" panel; Runtime mirrors bot events into the logger. - docs/runbook.md covers deploys, the kill switch, resetting paper state and going live. Adds tests for metrics rendering and the log ring.
This commit is contained in:
1 parent
c605a0f316
commit
ac92dd5ac4
12 files changed
+462
-1
No files matched your search
@@ -4,10 +4,20 @@ import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, WebSocket, WebSocketDisconnect
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
Depends,
|
||||
HTTPException,
|
||||
Request,
|
||||
Response,
|
||||
WebSocket,
|
||||
WebSocketDisconnect,
|
||||
)
|
||||
|
||||
from app.config import Settings
|
||||
from app.engine.strategies import get_strategy, list_strategies, strategy_spec
|
||||
from app.logs import get_log_handler
|
||||
from app.metrics import render_metrics
|
||||
from app.models import OrderSide, Position, PositionStatus
|
||||
from app.runtime import Runtime
|
||||
from app.schemas import (
|
||||
@@ -65,6 +75,21 @@ def health() -> dict[str, str]:
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@router.get("/metrics")
|
||||
def metrics(runtime: GuardedRuntimeDep) -> Response:
|
||||
"""Prometheus text exposition, unauthenticated so a scraper can reach it."""
|
||||
status = runtime.multi_status()
|
||||
body = render_metrics(status, runtime.settings.mode, runtime.settings.exchange)
|
||||
return Response(content=body, media_type="text/plain; version=0.0.4")
|
||||
|
||||
|
||||
@router.get("/logs")
|
||||
def logs(runtime: GuardedRuntimeDep, limit: int = 100) -> dict:
|
||||
handler = get_log_handler()
|
||||
entries = handler.snapshot(limit) if handler is not None else []
|
||||
return {"entries": entries}
|
||||
|
||||
|
||||
@router.get("/version")
|
||||
def version(request: Request) -> dict[str, str]:
|
||||
"""Build version of the running backend, used by the client to self-heal
|
||||
|
||||
Reference in new issue
Block a user