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",
"tracing",
"tracing-subscriber",
"uom",
]
[[package]]

View File

@ -18,6 +18,7 @@ structopt = "0.3.20"
tokio = { version = "0.2.22", features = ["full"] }
tracing = "0.1.21"
tracing-subscriber = "0.2.15"
uom = "0.30.0"
ptth_core = { path = "../ptth_core" }
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 ())
);
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 {
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 {
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) => {
error! ("Failed to update gauge metrics: {:?}", e);
error! ("Failed to update interval metrics: {:?}", e);
continue;
},
Ok (x) => x,
};
let new_gauges = Arc::new (Some (new_gauges));
gauge_writer.store (new_gauges);
let new_interval_metrics = Arc::new (Some (new_interval_metrics));
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,
metrics_startup,
metrics_gauges,
metrics_interval,
hidden_path: Some (path),
});

View File

@ -52,12 +52,12 @@ pub async fn serve_root (
#[derive (Serialize)]
struct RootHtml <'a> {
metrics_startup: &'a metrics::Startup,
metrics_gauges: &'a Option <metrics::Gauges>,
metrics_interval: &'a Option <metrics::Interval>,
}
let params = RootHtml {
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)?;

View File

@ -2,15 +2,10 @@ use chrono::{DateTime, Utc};
use tracing::debug;
use ulid::Ulid;
fn serialize_ulid <S: serde::Serializer> (t: &Ulid, s: S)
-> Result <S::Ok, S::Error>
{
let t = t.to_string ();
s.serialize_str (&t)
}
// Instance metrics are captured when the ptth_server process starts.
// They don't change after that.
// Metrics are named for when they're updated:
// - Startup (Once, when the server state is initialized)
// - Interval (About once per minute)
// - Events (When a request is processed)
#[derive (Debug, serde::Serialize)]
pub struct Startup {
@ -33,23 +28,45 @@ pub struct Startup {
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)]
pub struct Gauges {
pub struct Interval {
pub utc: DateTime <Utc>,
pub rss_mib: u64,
// What's the difference?
pub cpu_time_user: f64,
pub cpu_time_system: f64,
#[serde (skip)]
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> {
use tokio::join;
use heim::process;
@ -61,33 +78,22 @@ impl Gauges {
let our_process = process::current ().await?;
let cpu_time = our_process.cpu_time ();
let cpu_usage = our_process.cpu_usage ();
let (cpu_time, cpu_usage) = join! (
cpu_time,
let (cpu_usage, mem) = join! {
cpu_usage,
);
let cpu_time = cpu_time?;
let cpu_time_user = cpu_time.user ().get::<second> ();
let cpu_time_system = cpu_time.system ().get::<second> ();
our_process.memory ()
};
let cpu_usage = cpu_usage?;
let mem = our_process.memory ().await?;
let mem = mem?;
let rss_mib = mem.rss ().get::<mebibyte> ();
let x = Gauges {
let x = Self {
utc: Utc::now (),
rss_mib,
cpu_time_user,
cpu_time_system,
cpu_usage,
};
debug! ("metric gauges: {:?}", x);
Ok (x)
}
}
@ -110,24 +116,6 @@ fn get_machine_id () -> Option <String> {
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)]
mod tests {
use super::*;

View File

@ -59,7 +59,7 @@ pub struct State {
pub config: Config,
pub handlebars: handlebars::Handlebars <'static>,
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>,
}

View File

@ -201,7 +201,7 @@ pub async fn run_server (
let handlebars = file_server::load_templates (&asset_root)?;
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 {
file_server: file_server::State {
@ -210,7 +210,7 @@ pub async fn run_server (
},
handlebars,
metrics_startup,
metrics_gauges,
metrics_interval,
hidden_path,
},
config: Config {

View File

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