update: measuring CPU usage every minute

main
_ 2020-12-20 17:17:31 -06:00
parent 1e5aa528c9
commit f335644b03
8 changed files with 78 additions and 66 deletions

1
Cargo.lock generated
View File

@ -1653,6 +1653,7 @@ dependencies = [
"tokio", "tokio",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"uom",
] ]
[[package]] [[package]]

View File

@ -18,6 +18,7 @@ structopt = "0.3.20"
tokio = { version = "0.2.22", features = ["full"] } tokio = { version = "0.2.22", features = ["full"] }
tracing = "0.1.21" tracing = "0.1.21"
tracing-subscriber = "0.2.15" tracing-subscriber = "0.2.15"
uom = "0.30.0"
ptth_core = { path = "../ptth_core" } ptth_core = { path = "../ptth_core" }
ptth_server = { path = "../ptth_server" } ptth_server = { path = "../ptth_server" }

View File

@ -97,24 +97,46 @@ async fn main () -> Result <(), anyhow::Error> {
config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ()) config_file.name.unwrap_or_else (|| "PTTH File Server".to_string ())
); );
let metrics_gauges = Arc::new (ArcSwap::default ()); let metrics_interval = Arc::new (ArcSwap::default ());
let gauge_writer = Arc::clone (&metrics_gauges); let interval_writer = Arc::clone (&metrics_interval);
tokio::spawn (async move { tokio::spawn (async move {
let mut interval = tokio::time::interval (std::time::Duration::from_secs (2)); use std::time::Duration;
use uom::si::ratio::percent;
let mut interval = tokio::time::interval (Duration::from_secs (60));
let mut counter = 0_u64;
let mut next_10_time = counter;
let mut metrics_at_last_10: Arc <Option <metrics::Interval>> = Arc::new (None);
loop { loop {
interval.tick ().await; interval.tick ().await;
let new_gauges = match file_server::metrics::Gauges::new ().await { let new_interval_metrics = match file_server::metrics::Interval::new ().await {
Err (e) => { Err (e) => {
error! ("Failed to update gauge metrics: {:?}", e); error! ("Failed to update interval metrics: {:?}", e);
continue; continue;
}, },
Ok (x) => x, Ok (x) => x,
}; };
let new_gauges = Arc::new (Some (new_gauges)); let new_interval_metrics = Arc::new (Some (new_interval_metrics));
gauge_writer.store (new_gauges);
if counter >= next_10_time {
if let (Some (old), Some (new)) = (&*metrics_at_last_10, &*new_interval_metrics) {
let diff = new.cpu_usage.clone () - old.cpu_usage.clone ();
trace! ("CPU usage: {}%", diff.get::<percent> ());
}
next_10_time += 1;
metrics_at_last_10 = new_interval_metrics.clone ();
}
interval_writer.store (new_interval_metrics);
counter += 1;
//trace! ("interval metrics 1");
} }
}); });
@ -124,7 +146,7 @@ async fn main () -> Result <(), anyhow::Error> {
}, },
handlebars, handlebars,
metrics_startup, metrics_startup,
metrics_gauges, metrics_interval,
hidden_path: Some (path), hidden_path: Some (path),
}); });

View File

@ -52,12 +52,12 @@ pub async fn serve_root (
#[derive (Serialize)] #[derive (Serialize)]
struct RootHtml <'a> { struct RootHtml <'a> {
metrics_startup: &'a metrics::Startup, metrics_startup: &'a metrics::Startup,
metrics_gauges: &'a Option <metrics::Gauges>, metrics_interval: &'a Option <metrics::Interval>,
} }
let params = RootHtml { let params = RootHtml {
metrics_startup: &state.metrics_startup, metrics_startup: &state.metrics_startup,
metrics_gauges: &**state.metrics_gauges.load (), metrics_interval: &**state.metrics_interval.load (),
}; };
let s = state.handlebars.render ("file_server_root", &params)?; let s = state.handlebars.render ("file_server_root", &params)?;

View File

@ -2,15 +2,10 @@ use chrono::{DateTime, Utc};
use tracing::debug; use tracing::debug;
use ulid::Ulid; use ulid::Ulid;
fn serialize_ulid <S: serde::Serializer> (t: &Ulid, s: S) // Metrics are named for when they're updated:
-> Result <S::Ok, S::Error> // - Startup (Once, when the server state is initialized)
{ // - Interval (About once per minute)
let t = t.to_string (); // - Events (When a request is processed)
s.serialize_str (&t)
}
// Instance metrics are captured when the ptth_server process starts.
// They don't change after that.
#[derive (Debug, serde::Serialize)] #[derive (Debug, serde::Serialize)]
pub struct Startup { pub struct Startup {
@ -33,23 +28,45 @@ pub struct Startup {
pub startup_utc: DateTime <Utc>, pub startup_utc: DateTime <Utc>,
} }
// Gauges are things we instananeously measure on a fixed interval.
// They are not read back and accumulated like counters.
#[derive (Debug, serde::Serialize)] #[derive (Debug, serde::Serialize)]
pub struct Gauges { pub struct Interval {
pub utc: DateTime <Utc>, pub utc: DateTime <Utc>,
pub rss_mib: u64, pub rss_mib: u64,
// What's the difference?
pub cpu_time_user: f64,
pub cpu_time_system: f64,
#[serde (skip)] #[serde (skip)]
pub cpu_usage: heim::process::CpuUsage, pub cpu_usage: heim::process::CpuUsage,
} }
impl Gauges { pub struct Events {
}
impl Startup {
#[must_use]
pub fn new (server_name: String) -> Self
{
let x = Self {
machine_id: get_machine_id (),
git_version: None,
server_name,
instance_id: ulid::Ulid::new (),
startup_utc: Utc::now (),
};
debug! ("metrics at startup: {:?}", x);
x
}
}
fn serialize_ulid <S: serde::Serializer> (t: &Ulid, s: S)
-> Result <S::Ok, S::Error>
{
let t = t.to_string ();
s.serialize_str (&t)
}
impl Interval {
pub async fn new () -> Result <Self, super::FileServerError> { pub async fn new () -> Result <Self, super::FileServerError> {
use tokio::join; use tokio::join;
use heim::process; use heim::process;
@ -61,33 +78,22 @@ impl Gauges {
let our_process = process::current ().await?; let our_process = process::current ().await?;
let cpu_time = our_process.cpu_time ();
let cpu_usage = our_process.cpu_usage (); let cpu_usage = our_process.cpu_usage ();
let (cpu_time, cpu_usage) = join! ( let (cpu_usage, mem) = join! {
cpu_time,
cpu_usage, cpu_usage,
); our_process.memory ()
};
let cpu_time = cpu_time?;
let cpu_time_user = cpu_time.user ().get::<second> ();
let cpu_time_system = cpu_time.system ().get::<second> ();
let cpu_usage = cpu_usage?; let cpu_usage = cpu_usage?;
let mem = mem?;
let mem = our_process.memory ().await?;
let rss_mib = mem.rss ().get::<mebibyte> (); let rss_mib = mem.rss ().get::<mebibyte> ();
let x = Gauges { let x = Self {
utc: Utc::now (), utc: Utc::now (),
rss_mib, rss_mib,
cpu_time_user,
cpu_time_system,
cpu_usage, cpu_usage,
}; };
debug! ("metric gauges: {:?}", x);
Ok (x) Ok (x)
} }
} }
@ -110,24 +116,6 @@ fn get_machine_id () -> Option <String> {
Some (s) Some (s)
} }
impl Startup {
#[must_use]
pub fn new (server_name: String) -> Self
{
let x = Self {
machine_id: get_machine_id (),
git_version: None,
server_name,
instance_id: ulid::Ulid::new (),
startup_utc: Utc::now (),
};
debug! ("metrics at startup: {:?}", x);
x
}
}
#[cfg (test)] #[cfg (test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -59,7 +59,7 @@ pub struct State {
pub config: Config, pub config: Config,
pub handlebars: handlebars::Handlebars <'static>, pub handlebars: handlebars::Handlebars <'static>,
pub metrics_startup: metrics::Startup, pub metrics_startup: metrics::Startup,
pub metrics_gauges: Arc <ArcSwap <Option <metrics::Gauges>>>, pub metrics_interval: Arc <ArcSwap <Option <metrics::Interval>>>,
pub hidden_path: Option <PathBuf>, pub hidden_path: Option <PathBuf>,
} }

View File

@ -201,7 +201,7 @@ pub async fn run_server (
let handlebars = file_server::load_templates (&asset_root)?; let handlebars = file_server::load_templates (&asset_root)?;
let metrics_startup = file_server::metrics::Startup::new (config_file.name); let metrics_startup = file_server::metrics::Startup::new (config_file.name);
let metrics_gauges = Arc::new (ArcSwap::default ()); let metrics_interval = Arc::new (ArcSwap::default ());
let state = Arc::new (State { let state = Arc::new (State {
file_server: file_server::State { file_server: file_server::State {
@ -210,7 +210,7 @@ pub async fn run_server (
}, },
handlebars, handlebars,
metrics_startup, metrics_startup,
metrics_gauges, metrics_interval,
hidden_path, hidden_path,
}, },
config: Config { config: Config {

View File

@ -24,7 +24,7 @@
<h2>Gauges</h2> <h2>Gauges</h2>
<p>RSS MiB: {{metrics_gauges.rss_mib}}</p> <p>RSS MiB: {{metrics_interval.rss_mib}}</p>
<div class="entry_list"> <div class="entry_list">