Some work towards more configurable graphs
This commit is contained in:
parent
a3529772cd
commit
59a38aa847
|
@ -1,13 +1,31 @@
|
||||||
use bare_metrics_core::structures::MetricKind;
|
use bare_metrics_core::structures::MetricKind;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Clone)]
|
#[derive(Deserialize, Default, Clone)]
|
||||||
pub struct DashboardConfig {
|
pub struct DashboardConfig {
|
||||||
pub graphs: Vec<GraphConfig>,
|
pub graphs: Vec<GraphConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
pub enum MetricTransform {
|
||||||
|
Rate {
|
||||||
|
// Divisor in seconds. Would usually expect to see 1 (/sec), 60 (/min) or 3600 (/hour).
|
||||||
|
time_unit: f32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
pub struct GraphConfig {
|
pub struct GraphConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub kind: MetricKind,
|
pub kind: MetricKind,
|
||||||
|
#[serde(default)]
|
||||||
|
pub transform: Option<MetricTransform>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash)]
|
||||||
|
pub struct GraphRequest {
|
||||||
|
pub metric_name: String,
|
||||||
|
pub metric_labels: BTreeMap<String, String>,
|
||||||
|
pub derivation: Option<MetricTransform>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
|
use crate::config::MetricTransform;
|
||||||
use anyhow::{anyhow, bail};
|
use anyhow::{anyhow, bail};
|
||||||
use bare_metrics_core::structures::{
|
use bare_metrics_core::structures::{
|
||||||
Frame, MetricDescriptor, MetricId, MetricKind, UnixTimestampMilliseconds,
|
Frame, MetricDescriptor, MetricId, MetricKind, UnixTimestampMilliseconds,
|
||||||
};
|
};
|
||||||
use bare_metrics_reader::{MetricsLogReader, SeekToken};
|
use bare_metrics_reader::{MetricsLogReader, SeekToken};
|
||||||
use eframe::egui::{
|
use eframe::egui::{
|
||||||
Color32, Frame as EguiFrame, Galley, PointerButton, Pos2, Rect, Sense, Stroke, TextStyle, Ui,
|
Color32, Frame as EguiFrame, PointerButton, Pos2, Rect, Sense, Stroke, TextStyle, Ui, Vec2,
|
||||||
Vec2,
|
|
||||||
};
|
};
|
||||||
use hdrhistogram::Histogram;
|
use hdrhistogram::Histogram;
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
use std::ops::{Mul, RangeInclusive};
|
use std::ops::{DerefMut, Mul, RangeInclusive};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
/// Make a checkpoint every 10 minutes?
|
/// Make a checkpoint every 10 minutes?
|
||||||
/// This should probably be tunable since it will likely vary per-source ...
|
/// This should probably be tunable since it will likely vary per-source ...
|
||||||
pub const CHECKPOINT_EVERY_MILLISECONDS: u64 = 600_000_000;
|
pub const CHECKPOINT_EVERY_MILLISECONDS: u64 = 600_000_000;
|
||||||
|
|
||||||
|
pub type StateCallbackHook = Arc<Mutex<Option<Box<dyn FnOnce() + Send + 'static>>>>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MetricsWindow {
|
pub struct MetricsWindow {
|
||||||
pub time_range: RangeInclusive<f64>,
|
pub time_range: RangeInclusive<f64>,
|
||||||
|
@ -157,6 +158,7 @@ pub enum MetricsLogReaderMessage {
|
||||||
impl MetricsLogReadingRequester {
|
impl MetricsLogReadingRequester {
|
||||||
pub fn new_manager<R: Read + Seek + Send + 'static>(
|
pub fn new_manager<R: Read + Seek + Send + 'static>(
|
||||||
reader: MetricsLogReader<R>,
|
reader: MetricsLogReader<R>,
|
||||||
|
on_initial_scan_done: StateCallbackHook,
|
||||||
) -> MetricsLogReadingRequester {
|
) -> MetricsLogReadingRequester {
|
||||||
let shared = Arc::new(MetricsLogReadingShared {
|
let shared = Arc::new(MetricsLogReadingShared {
|
||||||
current_window: RwLock::new(MetricsWindow {
|
current_window: RwLock::new(MetricsWindow {
|
||||||
|
@ -177,9 +179,12 @@ impl MetricsLogReadingRequester {
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("metricslogreader".to_string())
|
.name("metricslogreader".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
if let Err(err) =
|
if let Err(err) = MetricsLogReaderManager::new_and_run(
|
||||||
MetricsLogReaderManager::new_and_run(manager_shared_ref, reader, rx)
|
manager_shared_ref,
|
||||||
{
|
reader,
|
||||||
|
rx,
|
||||||
|
on_initial_scan_done,
|
||||||
|
) {
|
||||||
error!("Error in background log reader: {:?}", err);
|
error!("Error in background log reader: {:?}", err);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -554,11 +559,19 @@ impl<R: Read + Seek> MetricsLogReaderManager<R> {
|
||||||
Ok(metrics_window)
|
Ok(metrics_window)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&mut self) -> anyhow::Result<()> {
|
fn run(&mut self, on_initial_scan_done: StateCallbackHook) -> anyhow::Result<()> {
|
||||||
info!("Starting manager");
|
info!("Starting manager");
|
||||||
self.initial_scan()?;
|
self.initial_scan()?;
|
||||||
self.update_metric_descriptors();
|
self.update_metric_descriptors();
|
||||||
info!("Initial scan done.");
|
info!("Initial scan done.");
|
||||||
|
let mut the_func = None;
|
||||||
|
let mut callback_guard = on_initial_scan_done
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| anyhow!("Can't lock"))?;
|
||||||
|
std::mem::swap(&mut the_func, callback_guard.deref_mut());
|
||||||
|
if let Some(on_initial_scan_done) = the_func {
|
||||||
|
on_initial_scan_done();
|
||||||
|
}
|
||||||
|
|
||||||
while let Ok(msg) = self.rx.recv() {
|
while let Ok(msg) = self.rx.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
|
@ -637,6 +650,7 @@ impl<R: Read + Seek> MetricsLogReaderManager<R> {
|
||||||
shared_ref: Arc<MetricsLogReadingShared>,
|
shared_ref: Arc<MetricsLogReadingShared>,
|
||||||
reader: MetricsLogReader<R>,
|
reader: MetricsLogReader<R>,
|
||||||
rx: Receiver<MetricsLogReaderMessage>,
|
rx: Receiver<MetricsLogReaderMessage>,
|
||||||
|
on_initial_scan_done: StateCallbackHook,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut manager = MetricsLogReaderManager {
|
let mut manager = MetricsLogReaderManager {
|
||||||
shared_ref,
|
shared_ref,
|
||||||
|
@ -648,7 +662,7 @@ impl<R: Read + Seek> MetricsLogReaderManager<R> {
|
||||||
checkpoints: Default::default(),
|
checkpoints: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
manager.run()
|
manager.run(on_initial_scan_done)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,9 @@ fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let reader = MetricsLogReader::new(file).unwrap();
|
let reader = MetricsLogReader::new(file).unwrap();
|
||||||
let log_app_name = reader.header.application_name.clone();
|
let log_app_name = reader.header.application_name.clone();
|
||||||
let requester = MetricsLogReadingRequester::new_manager(reader);
|
// TODO we can attach a callback to this hook.
|
||||||
|
let init_hook_callback = Default::default();
|
||||||
|
let requester = MetricsLogReadingRequester::new_manager(reader, init_hook_callback);
|
||||||
|
|
||||||
let dashboard_dir = appdirs::user_data_dir(Some("baremetrics"), Some("rei"), true)
|
let dashboard_dir = appdirs::user_data_dir(Some("baremetrics"), Some("rei"), true)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
Loading…
Reference in New Issue