feat: add system metrics dashboard with resource monitoring
- Add system metrics endpoint (CPU load, memory, swap, network traffic) - Collect metrics from /proc and /sys (no subprocess required) - Overhaul dashboard to pull from per-subsystem models - Remove deprecated /status/all monolithic endpoint - Improve networkd import to handle optional priority prefix - Fix CSS duplicate .grid-4 rule and unused dashboard imports
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
"""System metrics handler.
|
||||
|
||||
Returns CPU load, memory usage, and per-interface network traffic stats.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from daemon.iface import GET_SYSTEM_METRICS
|
||||
from daemon.server import registry
|
||||
from lib.state import state as state_store
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@registry.register(GET_SYSTEM_METRICS)
|
||||
def system_metrics(_request: Any, _body: Any) -> dict[str, Any]:
|
||||
"""Return system-wide metrics.
|
||||
|
||||
Reads from pre-collected state (CPU load, memory, network traffic).
|
||||
|
||||
Returns:
|
||||
Dict with load, memory, swap, and traffic data.
|
||||
"""
|
||||
sys_state = state_store.get("system")
|
||||
if sys_state is None:
|
||||
return {
|
||||
"load": {"load1": 0.0, "load5": 0.0, "load15": 0.0},
|
||||
"memory": {"total": 0, "available": 0, "used": 0, "used_pct": 0},
|
||||
"swap": {"total": 0, "used": 0, "used_pct": 0},
|
||||
"traffic": {},
|
||||
}
|
||||
return sys_state
|
||||
+1
-1
@@ -155,12 +155,12 @@ GET_LOGS_APP: Endpoint = _ep("GET", "/logs/app")
|
||||
|
||||
# ---- Server infra (not going through client) ----
|
||||
GET_HEALTH: Endpoint = _ep("GET", "/health")
|
||||
GET_STATUS_ALL: Endpoint = _ep("GET", "/status/all")
|
||||
POST_STATUS_REFRESH: Endpoint = _ep("POST", "/status/refresh")
|
||||
GET_WS: Endpoint = _ep("GET", "/ws")
|
||||
POST_BATCH: Endpoint = _ep("POST", "/batch")
|
||||
GET_STATUS_PENDING: Endpoint = _ep("GET", "/status/pending")
|
||||
POST_STATUS_APPLY_ALL: Endpoint = _ep("POST", "/status/apply-all")
|
||||
GET_SYSTEM_METRICS: Endpoint = _ep("GET", "/system/metrics")
|
||||
|
||||
# Collect all endpoint module-level constants for __all__ verification
|
||||
_all_endpoints = [
|
||||
|
||||
+1
-10
@@ -350,7 +350,6 @@ def create_app() -> web.Application:
|
||||
"""
|
||||
app = web.Application()
|
||||
app.router.add_route("GET", "/health", _health)
|
||||
app.router.add_route("GET", "/status/all", get_status_all)
|
||||
app.router.add_route("POST", "/status/refresh", refresh_status)
|
||||
app.router.add_route("POST", "/batch", _handle_batch)
|
||||
app.router.add_route("GET", "/ws", _handle_ws)
|
||||
@@ -462,15 +461,6 @@ async def _health(_request: web.Request) -> web.Response:
|
||||
return ok({"pid": os.getpid(), "socket": str(SOCKET_PATH)})
|
||||
|
||||
|
||||
async def get_status_all(_request: web.Request) -> web.Response:
|
||||
"""Return the entire state snapshot in one call.
|
||||
|
||||
Returns:
|
||||
JSON response containing state data for all subsystems.
|
||||
"""
|
||||
return ok({name: state_store.get(name) for name in state_store.SUBSYSTEMS})
|
||||
|
||||
|
||||
async def refresh_status(_request: web.Request) -> web.Response:
|
||||
"""Re-collect all state from system.
|
||||
|
||||
@@ -517,6 +507,7 @@ def _register_routes() -> None:
|
||||
network, # noqa: F401
|
||||
nginx, # noqa: F401
|
||||
status, # noqa: F401
|
||||
system, # noqa: F401
|
||||
wireguard, # noqa: F401
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user