91 lines
3.5 KiB
Rust
91 lines
3.5 KiB
Rust
fn live_chart_system_payload(state: &App) -> Value {
|
|
let view = state.diagnostics.view();
|
|
json!({
|
|
"sampled_at_ms": view.sampled_at_ms,
|
|
"cpu_percent": view.cpu_percent,
|
|
"process_cpu_percent": view.process_cpu_percent,
|
|
"process_rss_bytes": view.process_rss_bytes,
|
|
"network_rx_bytes_per_second": view.network_rx_bytes_per_second,
|
|
"network_tx_bytes_per_second": view.network_tx_bytes_per_second,
|
|
"network_interfaces": view.network_interfaces
|
|
})
|
|
}
|
|
|
|
fn web_server_metrics_payload(snapshot: &crate::config::Snapshot) -> Value {
|
|
let mut services = serde_json::Map::new();
|
|
for service in &snapshot.envelope.config.web_services {
|
|
let Some(compiled) = snapshot.web_php_services.get(&service.id) else {
|
|
continue;
|
|
};
|
|
let php = compiled.php.as_ref().map(|handler| {
|
|
let available = handler.permits.available_permits();
|
|
json!({"metrics": handler.metrics.view(), "capacity_limit": handler.max_concurrent,
|
|
"capacity_available": available, "capacity_used": handler.max_concurrent.saturating_sub(available)})
|
|
});
|
|
services.insert(
|
|
service.id.clone(),
|
|
json!({"web": compiled.web_metrics.view(), "php": php}),
|
|
);
|
|
}
|
|
Value::Object(services)
|
|
}
|
|
|
|
fn live_status_payload(state: &App) -> Value {
|
|
let snapshot = state.config.load_full();
|
|
let stream_metrics = state
|
|
.active_streams
|
|
.iter()
|
|
.filter_map(|stream| {
|
|
state
|
|
.stream_metrics
|
|
.get(&stream.id)
|
|
.map(|metrics| (stream.id.clone(), metrics.view()))
|
|
})
|
|
.collect::<std::collections::BTreeMap<_, _>>();
|
|
json!({
|
|
"version": env!("CARGO_PKG_VERSION"),
|
|
"uptime_seconds": state.started.elapsed().as_secs(),
|
|
"revision": snapshot.envelope.revision,
|
|
"listeners": {
|
|
"active_endpoints": state.active_listeners,
|
|
"desired_endpoints": snapshot.listeners,
|
|
"restart_required": crate::http3::listeners_require_restart(&state.active_listeners, &snapshot.listeners)
|
|
},
|
|
"metrics": state.metrics.view(),
|
|
"web_server_metrics": web_server_metrics_payload(&snapshot),
|
|
"live_system": live_chart_system_payload(state),
|
|
"cache": state.cache.view(),
|
|
"transform_metrics": state.transform_metrics.total(),
|
|
"logs_dropped": state.logs.dropped.load(Ordering::Relaxed),
|
|
"backends": snapshot.envelope.config.vhosts.iter().map(|v| v.backends.len()).sum::<usize>(),
|
|
"backend_pools": snapshot.pools.iter().map(|p| p.view()).collect::<Vec<_>>(),
|
|
"vhost_metrics": snapshot.vhost_metrics.iter().map(|(id, metrics)| (id.clone(), metrics.view())).collect::<std::collections::BTreeMap<_, _>>(),
|
|
"streams": {"metrics": stream_metrics},
|
|
"logging": {"sinks": state.logs.stats(), "error_file": crate::logging::error_log_stats()}
|
|
})
|
|
}
|
|
|
|
#[derive(Default, Deserialize)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
struct StatusQuery {
|
|
view: Option<String>,
|
|
}
|
|
|
|
async fn status(
|
|
State(state): State<Arc<App>>,
|
|
Query(query): Query<StatusQuery>,
|
|
) -> Result<Json<Value>, ApiError> {
|
|
match query.view.as_deref() {
|
|
None => Ok(Json(status_payload(&state))),
|
|
Some("live") => Ok(Json(live_status_payload(&state))),
|
|
_ => Err(ApiError(
|
|
StatusCode::BAD_REQUEST,
|
|
"invalid status view".into(),
|
|
)),
|
|
}
|
|
}
|
|
|
|
async fn system_info(State(state): State<Arc<App>>) -> Json<Value> {
|
|
Json(system_info_payload(&state))
|
|
}
|