@@ -11,6 +11,9 @@ use serde_json::json;
1111use std:: collections:: HashMap ;
1212use std:: fs;
1313use std:: path:: Path as StdPath ;
14+ use std:: sync:: { Arc , Mutex } ;
15+ use std:: time:: { Duration , Instant } ;
16+ use sysinfo:: System ;
1417use tracing:: error;
1518
1619#[ derive( Serialize , Deserialize ) ]
@@ -184,6 +187,7 @@ pub fn workbench_routes() -> Router<ApiState> {
184187 . route ( "/api/workbench/endpoints" , get ( get_endpoints) )
185188 . route ( "/api/workbench/types/{type_name}" , get ( get_type_schema) )
186189 . route ( "/api/workbench/events/{name}/trigger" , post ( trigger_event) )
190+ . route ( "/api/workbench/system-metrics" , get ( get_system_metrics) )
187191}
188192
189193async fn get_snapshot ( State ( state) : State < ApiState > ) -> Result < Response , WorkbenchError > {
@@ -1111,6 +1115,69 @@ async fn trigger_event(
11111115 . into_response ( ) )
11121116}
11131117
1118+ #[ derive( Serialize , Deserialize ) ]
1119+ pub struct SystemMetrics {
1120+ pub cpu : f32 ,
1121+ pub ram : RamMetrics ,
1122+ }
1123+
1124+ #[ derive( Serialize , Deserialize ) ]
1125+ pub struct RamMetrics {
1126+ pub used_mb : u64 ,
1127+ pub total_mb : u64 ,
1128+ pub percentage : f32 ,
1129+ }
1130+
1131+ static SYSTEM : std:: sync:: OnceLock < Arc < Mutex < System > > > = std:: sync:: OnceLock :: new ( ) ;
1132+ static LAST_UPDATE : std:: sync:: OnceLock < Arc < Mutex < Instant > > > = std:: sync:: OnceLock :: new ( ) ;
1133+
1134+ fn get_system ( ) -> Arc < Mutex < System > > {
1135+ SYSTEM . get_or_init ( || Arc :: new ( Mutex :: new ( System :: new_all ( ) ) ) ) . clone ( )
1136+ }
1137+
1138+ fn get_last_update ( ) -> Arc < Mutex < Instant > > {
1139+ LAST_UPDATE . get_or_init ( || Arc :: new ( Mutex :: new ( Instant :: now ( ) ) ) ) . clone ( )
1140+ }
1141+
1142+ async fn get_system_metrics ( ) -> Result < Response , WorkbenchError > {
1143+ let system = get_system ( ) ;
1144+ let mut system_guard = system. lock ( ) . map_err ( |e| {
1145+ WorkbenchError :: Internal ( format ! ( "Failed to acquire system lock: {}" , e) )
1146+ } ) ?;
1147+
1148+ let last_update = get_last_update ( ) ;
1149+ let mut last_update_guard = last_update. lock ( ) . map_err ( |e| {
1150+ WorkbenchError :: Internal ( format ! ( "Failed to acquire update lock: {}" , e) )
1151+ } ) ?;
1152+
1153+ if last_update_guard. elapsed ( ) > Duration :: from_secs ( 1 ) {
1154+ system_guard. refresh_all ( ) ;
1155+ * last_update_guard = Instant :: now ( ) ;
1156+ }
1157+ let cpu_usage = system_guard. global_cpu_usage ( ) ;
1158+
1159+ let total_memory = system_guard. total_memory ( ) ;
1160+ let used_memory = system_guard. used_memory ( ) ;
1161+ let total_memory_mb = total_memory / ( 1024 * 1024 ) ;
1162+ let used_memory_mb = used_memory / ( 1024 * 1024 ) ;
1163+ let memory_percentage = if total_memory > 0 {
1164+ ( used_memory as f32 / total_memory as f32 ) * 100.0
1165+ } else {
1166+ 0.0
1167+ } ;
1168+
1169+ let metrics = SystemMetrics {
1170+ cpu : cpu_usage,
1171+ ram : RamMetrics {
1172+ used_mb : used_memory_mb,
1173+ total_mb : total_memory_mb,
1174+ percentage : memory_percentage,
1175+ } ,
1176+ } ;
1177+
1178+ Ok ( Json ( metrics) . into_response ( ) )
1179+ }
1180+
11141181#[ derive( Debug ) ]
11151182pub enum WorkbenchError {
11161183 NotFound ( String ) ,
0 commit comments