Some work towards more configurable graphs

This commit is contained in:
Olivier 'reivilibre' 2022-01-08 14:19:17 +00:00 committed by Olivier
parent a3529772cd
commit 59a38aa847
3 changed files with 45 additions and 11 deletions

View File

@ -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>,
} }

View File

@ -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)
} }
} }

View File

@ -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()