-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Finalize monitoring page with websockets streaming system info
- Loading branch information
1 parent
576cba7
commit 8c2871c
Showing
9 changed files
with
185 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ pub mod network; | |
pub mod processor; | ||
pub mod disks; | ||
pub mod system; | ||
pub mod stream; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
use std::collections::HashMap; | ||
use sysinfo::{CpuExt, System, SystemExt}; | ||
|
||
|
||
use serde_json; | ||
use std::process::{Command, Stdio}; | ||
|
||
fn get_docker_stats() -> Result<Vec<serde_json::Value>, Box<dyn std::error::Error>> { | ||
let process = Command::new("docker") | ||
.args(&["stats", "--no-stream", "--format", "{{json .}}"]) | ||
.stdout(Stdio::piped()) | ||
.stderr(Stdio::piped()) | ||
.spawn()?; | ||
let output = process.wait_with_output().unwrap(); | ||
if !output.status.success() { | ||
let stderr = String::from_utf8_lossy(&output.stderr); | ||
eprintln!("Error: {}", stderr); | ||
return Ok(vec![]); | ||
} | ||
let stdout = String::from_utf8_lossy(&output.stdout); | ||
let stats: Vec<serde_json::Value> = stdout | ||
.lines() | ||
.filter_map(|line| serde_json::from_str(line).ok()) | ||
.collect(); | ||
Ok(stats) | ||
} | ||
|
||
fn get_cpu_percent() -> Vec<String> { | ||
let mut system = System::new_all(); | ||
system.refresh_all(); | ||
let mut cpu_usage = Vec::new(); | ||
for core in system.cpus() { | ||
cpu_usage.push(format!("{:.2}", core.cpu_usage())); | ||
} | ||
cpu_usage | ||
} | ||
|
||
fn get_system_metrics() -> HashMap<String, serde_json::Value> { | ||
let mut system = System::new_all(); | ||
system.refresh_all(); | ||
|
||
let load_avg = system.load_average(); | ||
|
||
let mut hash_vec = vec![ | ||
( | ||
"memory_info".to_string(), | ||
serde_json::json!({ | ||
"total": system.total_memory(), | ||
"used": system.used_memory(), // todo: wildly inaccurate (always 99%) on macOS | ||
}), | ||
), | ||
( | ||
"load_averages".to_string(), | ||
serde_json::json!({ | ||
"m1": load_avg.one, | ||
"m5": load_avg.five, | ||
"m15": load_avg.fifteen, | ||
}), | ||
), | ||
]; | ||
|
||
let total_swap = system.total_swap(); | ||
if total_swap != 0 { | ||
hash_vec.push(( | ||
"swap_info".to_string(), | ||
serde_json::json!({ | ||
"total": total_swap, | ||
"used": system.used_swap(), | ||
}), | ||
)); | ||
} | ||
let info = HashMap::from_iter(hash_vec); | ||
info | ||
} | ||
|
||
|
||
pub fn system_resources() -> HashMap<String, serde_json::Value> { | ||
let mut system_metrics = get_system_metrics(); | ||
let cpu_percent = get_cpu_percent(); | ||
let docker_stats = get_docker_stats().unwrap(); | ||
system_metrics.insert("cpu_usage".to_string(), serde_json::json!(cpu_percent)); | ||
system_metrics.insert("docker_stats".to_string(), serde_json::json!(docker_stats)); | ||
system_metrics | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
use crate::{constant, resources, routes, squire}; | ||
use actix_web::rt::time::sleep; | ||
use actix_web::{rt, web, Error, HttpRequest, HttpResponse}; | ||
use actix_ws::AggregatedMessage; | ||
use fernet::Fernet; | ||
use std::sync::Arc; | ||
use std::time::Duration; | ||
use futures::future; | ||
use futures::stream::StreamExt; | ||
|
||
|
||
async fn send_system_resources(mut session: actix_ws::Session) { | ||
loop { | ||
let system_resources = resources::stream::system_resources(); | ||
let strigified = serde_json::to_string(&system_resources).unwrap(); | ||
session.text(strigified).await.unwrap(); | ||
sleep(Duration::from_secs(1)).await; | ||
} | ||
} | ||
|
||
async fn receive_messages( | ||
mut session: actix_ws::Session, | ||
mut stream: impl futures::Stream<Item=Result<AggregatedMessage, actix_ws::ProtocolError>> + Unpin | ||
) { | ||
while let Some(msg) = stream.next().await { | ||
match msg { | ||
Ok(AggregatedMessage::Text(text)) => { | ||
println!("Text: {:?}", &text); | ||
session.text(text).await.unwrap(); | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
|
||
|
||
#[route("/ws/system", method = "GET")] | ||
async fn echo( | ||
request: HttpRequest, | ||
fernet: web::Data<Arc<Fernet>>, | ||
session_info: web::Data<Arc<constant::Session>>, | ||
config: web::Data<Arc<squire::settings::Config>>, | ||
stream: web::Payload, | ||
) -> Result<HttpResponse, Error> { | ||
let auth_response = squire::authenticator::verify_token(&request, &config, &fernet, &session_info); | ||
if !auth_response.ok { | ||
return Ok(routes::auth::failed_auth(auth_response)); | ||
} | ||
let (response, session, stream) = actix_ws::handle(&request, stream)?; | ||
// todo: implement a session timeout here | ||
let stream = stream | ||
.aggregate_continuations() | ||
// aggregate continuation frames up to 1MiB | ||
// todo: check and remove limit if necessary | ||
.max_continuation_size(2_usize.pow(20)); | ||
rt::spawn(async move { | ||
let send_task = send_system_resources(session.clone()); | ||
let receive_task = receive_messages(session, stream); | ||
future::join(send_task, receive_task).await; | ||
}); | ||
// respond immediately with response connected to WS session | ||
Ok(response) | ||
} |
Oops, something went wrong.