➕ update: measuring CPU usage every minute
parent
1e5aa528c9
commit
f335644b03
|
@ -1653,6 +1653,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"uom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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", ¶ms)?;
|
let s = state.handlebars.render ("file_server_root", ¶ms)?;
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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">
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue