use crate::chart::RollingLineChart;
use radiate_engines::{Metric, TagType};
use radiate_utils::SmallStr;
use std::collections::HashMap;
const MAX_CHART_POINTS: usize = 1000;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum MetricChartType {
Last,
Mean,
Stddev,
Variance,
BoxWhisker,
Distribution,
}
impl MetricChartType {
pub(crate) const SCALAR_VIEWS: &'static [MetricChartType] =
&[MetricChartType::Last, MetricChartType::Mean];
pub(crate) const DISTRIBUTION_VIEWS: &'static [MetricChartType] = &[
MetricChartType::BoxWhisker,
MetricChartType::Distribution,
MetricChartType::Mean,
MetricChartType::Stddev,
MetricChartType::Variance,
];
pub fn for_metric(metric: &Metric) -> &'static [MetricChartType] {
if metric.tags().has(TagType::Distribution) {
Self::DISTRIBUTION_VIEWS
} else {
Self::SCALAR_VIEWS
}
}
pub fn label(self) -> &'static str {
match self {
MetricChartType::Last => "Last",
MetricChartType::Mean => "Mean",
MetricChartType::Stddev => "Stddev",
MetricChartType::Variance => "Variance",
MetricChartType::BoxWhisker => "Box & Whisker",
MetricChartType::Distribution => "Dist.",
}
}
pub fn short_label(self) -> &'static str {
match self {
MetricChartType::Last => "last",
MetricChartType::Mean => "mean",
MetricChartType::Stddev => "stddev",
MetricChartType::Variance => "var",
MetricChartType::BoxWhisker => "box",
MetricChartType::Distribution => "dist",
}
}
}
pub struct ChartState {
value_charts: HashMap<SmallStr, RollingLineChart>,
mean_charts: HashMap<SmallStr, RollingLineChart>,
stddev_charts: HashMap<SmallStr, RollingLineChart>,
variance_charts: HashMap<SmallStr, RollingLineChart>,
}
impl ChartState {
pub fn new() -> Self {
Self {
value_charts: HashMap::new(),
mean_charts: HashMap::new(),
stddev_charts: HashMap::new(),
variance_charts: HashMap::new(),
}
}
pub fn get_line_chart(
&self,
key: &str,
chart_type: MetricChartType,
) -> Option<&RollingLineChart> {
match chart_type {
MetricChartType::Last => self.value_charts.get(key),
MetricChartType::Mean => self.mean_charts.get(key),
MetricChartType::Stddev => self.stddev_charts.get(key),
MetricChartType::Variance => self.variance_charts.get(key),
_ => None,
}
}
pub fn update_from_metric(&mut self, metric: &Metric) {
let stat = metric.statistic();
let key = metric.name();
if !metric.tags().has(TagType::Distribution) {
let value_chart = self.get_or_create_chart(key, MetricChartType::Last);
value_chart.push(stat.last_value() as f64);
}
let mean_chart = self.get_or_create_chart(key, MetricChartType::Mean);
mean_chart.push(stat.mean() as f64);
let stddev_chart = self.get_or_create_chart(key, MetricChartType::Stddev);
stddev_chart.push(stat.std_dev().unwrap_or(0.0) as f64);
let variance_chart = self.get_or_create_chart(key, MetricChartType::Variance);
variance_chart.push(stat.variance().unwrap_or(0.0) as f64);
}
fn get_or_create_chart(
&mut self,
key: &SmallStr,
chart_type: MetricChartType,
) -> &mut RollingLineChart {
match chart_type {
MetricChartType::Last => self.value_charts.entry(key.clone()).or_insert_with(|| {
RollingLineChart::with_capacity(MAX_CHART_POINTS)
.with_title(key.as_str())
.with_color(ratatui::style::Color::LightCyan)
}),
MetricChartType::Mean => self.mean_charts.entry(key.clone()).or_insert_with(|| {
RollingLineChart::with_capacity(MAX_CHART_POINTS)
.with_title(format!("{} μ (mean)", key))
.with_color(ratatui::style::Color::Yellow)
}),
MetricChartType::Stddev => self.stddev_charts.entry(key.clone()).or_insert_with(|| {
RollingLineChart::with_capacity(MAX_CHART_POINTS)
.with_title(format!("{} σ (stddev)", key))
.with_color(ratatui::style::Color::LightGreen)
}),
MetricChartType::Variance => {
self.variance_charts.entry(key.clone()).or_insert_with(|| {
RollingLineChart::with_capacity(MAX_CHART_POINTS)
.with_title(format!("{} σ² (variance)", key))
.with_color(ratatui::style::Color::LightBlue)
})
}
_ => panic!("Unsupported chart type for line chart"),
}
}
}