kcli top: auto add all histograms

This commit is contained in:
Wez Furlong
2025-04-04 07:49:50 -07:00
parent cb1c87ab15
commit 04ea7e5804
4 changed files with 69 additions and 17 deletions
+37 -1
View File
@@ -1,5 +1,5 @@
use crate::top::accumulator::*;
use crate::top::{SeriesChartOptions, SeriesFactory, TimeSeries};
use crate::top::{Histogram, HistogramFactory, SeriesChartOptions, SeriesFactory, TimeSeries};
use kumo_prometheus::parser::Metric;
pub struct ThreadPoolFactory {}
@@ -121,3 +121,39 @@ impl SeriesFactory for HistogramEventAvgFactory {
series
}
}
pub struct HistogramHistoFactory {}
impl HistogramFactory for HistogramHistoFactory {
fn matches(&self, metric: &Metric) -> Option<String> {
if metric.is_histogram() {
let h = metric.as_histogram();
match h.labels.values().next() {
Some(l) => {
let label = l.as_str();
if label == "init" || label == "pre_init" {
return None;
}
Some(format!("{} - {label}", h.name.as_str()))
}
None => Some(h.name.as_str().to_string()),
}
} else {
None
}
}
fn factory(&self, _series_name: &str, metric: &Metric) -> Histogram {
let h = metric.as_histogram();
match h.labels.iter().next() {
Some((key, value)) => Histogram::new_with_label_match(
metric.name().to_string(),
key.to_string(),
value.to_string(),
"s",
),
None => Histogram::new(metric.name().to_string(), "s"),
}
}
}
+7
View File
@@ -72,3 +72,10 @@ impl Histogram {
}
}
}
pub trait HistogramFactory {
/// Returns the name that should be created for this metric
fn matches(&self, metric: &Metric) -> Option<String>;
/// Constructs the appropriate histogram for this metric
fn factory(&self, series_name: &str, metric: &Metric) -> Histogram;
}
+2 -15
View File
@@ -50,6 +50,8 @@ impl TopCommand {
state.add_factory(HistogramEventFreqFactory {});
state.add_factory(HistogramEventAvgFactory {});
state.add_histogram_factory(HistogramHistoFactory {});
state.add_series(
"message_count",
TimeSeries::new(DirectAccumulator::new("message_count")),
@@ -144,21 +146,6 @@ impl TopCommand {
)),
);
state.add_histogram(
"Inbound SMTP Transaction Duration",
Histogram::new("smtpsrv_transaction_duration", "s"),
);
state.add_histogram(
"Inbound SMTP Data Receive Latency",
Histogram::new("smtpsrv_read_data_duration", "s"),
);
state.add_histogram(
"Inbound SMTP Data Process Latency",
Histogram::new("smtpsrv_process_data_duration", "s"),
);
let mut ticker = tokio::time::interval(Duration::from_secs(self.update_interval));
ticker.set_missed_tick_behavior(MissedTickBehavior::Skip);
+23 -1
View File
@@ -84,6 +84,7 @@ pub struct State {
time_series: HashMap<String, TimeSeries>,
histograms: HashMap<String, Histogram>,
factories: Vec<Box<dyn SeriesFactory + 'static>>,
histo_factories: Vec<Box<dyn HistogramFactory + 'static>>,
error: String,
vert_scroll: ScrollbarState,
vert_scroll_position: usize,
@@ -96,6 +97,10 @@ impl State {
self.factories.push(Box::new(f));
}
pub fn add_histogram_factory(&mut self, f: impl HistogramFactory + 'static) {
self.histo_factories.push(Box::new(f));
}
fn accumulate_series(&mut self, metric: &Metric) {
let mut new_series = vec![];
for factory in &self.factories {
@@ -114,6 +119,19 @@ impl State {
series.accumulate(metric);
}
let mut new_histo = vec![];
for factory in &self.histo_factories {
if let Some(name) = factory.matches(metric) {
if !self.histograms.contains_key(&name) {
let histogram = factory.factory(&name, metric);
new_histo.push((name, histogram));
}
}
}
for (name, histo) in new_histo {
self.add_histogram(name, histo);
}
for histo in self.histograms.values_mut() {
histo.accumulate(metric);
}
@@ -413,8 +431,12 @@ impl State {
.vert_scroll_position
.min(content_length.saturating_sub(1));
let mut names: Vec<_> = self.histograms.keys().map(|s| s.to_string()).collect();
names.sort();
let mut y = area.top();
for (caption, histo) in self.histograms.iter().skip(vert_scroll_position) {
for caption in names.iter().skip(vert_scroll_position) {
let histo = self.histograms.get(caption).expect("caption to be valid");
let heatmap = HeatMap::new(histo, caption).block(Block::bordered());
let height = heatmap.height() + 2 /* borders */;