lazy histograms

This commit is contained in:
Robin Appelman 2025-03-26 18:13:07 +01:00
commit 8299a90578
4 changed files with 56 additions and 37 deletions

View file

@ -3,6 +3,7 @@ use crate::matcher::MatchResult;
use crate::timegraph::TimeGraph;
use logsmash_data::{LoggingStatementWithPathPrefix, StatementList};
use regex::{escape, Regex, RegexBuilder};
use std::cell::OnceCell;
use std::collections::BTreeMap;
use std::fmt::Display;
@ -42,39 +43,46 @@ impl<'a> App<'a> {
pub struct LogMatch {
pub result: Option<MatchResult>,
pub count: usize,
pub histogram: TimeGraph,
pub sparkline: String,
pub histogram: OnceCell<TimeGraph>,
pub sparkline: OnceCell<String>,
pub all: GroupedLines,
pub grouped: Vec<GroupedLines>,
}
impl LogMatch {
pub fn new(result: Option<MatchResult>, lines: Vec<usize>, all_lines: &[LogLine]) -> Self {
let min_time = all_lines[0].time;
let max_time = all_lines.last().unwrap().time;
let mut histogram = TimeGraph::new(min_time, max_time);
for line in lines.iter().map(|line| &all_lines[*line]) {
histogram.add(line.time);
}
let count = lines.len();
let grouped = group_lines(all_lines, lines.iter().copied());
let sparkline = histogram.sparkline::<10>();
let all = GroupedLines {
sparkline: sparkline.clone(),
histogram: histogram.clone(),
lines,
};
let all = GroupedLines::new(lines);
LogMatch {
result,
count,
histogram,
sparkline,
histogram: OnceCell::new(),
sparkline: OnceCell::new(),
grouped,
all,
}
}
pub fn sparkline(&self, app: &App) -> &str {
self.sparkline
.get_or_init(|| self.histogram(app).sparkline::<10>())
.as_str()
}
pub fn histogram(&self, app: &App) -> &TimeGraph {
self.histogram.get_or_init(|| {
let min_time = app.lines[0].time;
let max_time = app.lines.last().unwrap().time;
let mut histogram = TimeGraph::new(min_time, max_time);
for line in self.all.lines.iter().map(|line| &app.lines[*line]) {
histogram.add(line.time);
}
histogram
})
}
pub fn row_count(&self) -> usize {
self.result.as_ref().map(|res| res.len()).unwrap_or(1)
}
@ -126,7 +134,7 @@ fn group_lines<I: Iterator<Item = usize>>(all_lines: &[LogLine], indices: I) ->
let mut list: Vec<_> = map
.into_values()
.map(|lines| GroupedLines::new(lines, all_lines))
.map(|lines| GroupedLines::new(lines))
.collect();
list.sort_by_key(|list| list.len());
list.reverse();
@ -135,26 +143,37 @@ fn group_lines<I: Iterator<Item = usize>>(all_lines: &[LogLine], indices: I) ->
pub struct GroupedLines {
pub lines: Vec<usize>,
pub histogram: TimeGraph,
pub sparkline: String,
pub histogram: OnceCell<TimeGraph>,
pub sparkline: OnceCell<String>,
}
impl GroupedLines {
pub fn new(lines: Vec<usize>, all_lines: &[LogLine]) -> Self {
let min_time = all_lines[0].time;
let max_time = all_lines.last().unwrap().time;
let mut histogram = TimeGraph::new(min_time, max_time);
for line in lines.iter().map(|line| &all_lines[*line]) {
histogram.add(line.time);
}
let sparkline = histogram.sparkline::<10>();
pub fn new(lines: Vec<usize>) -> Self {
GroupedLines {
lines,
histogram,
sparkline,
histogram: OnceCell::new(),
sparkline: OnceCell::new(),
}
}
pub fn sparkline(&self, app: &App) -> &str {
self.sparkline
.get_or_init(|| self.histogram(app).sparkline::<10>())
.as_str()
}
pub fn histogram(&self, app: &App) -> &TimeGraph {
self.histogram.get_or_init(|| {
let min_time = app.lines[0].time;
let max_time = app.lines.last().unwrap().time;
let mut histogram = TimeGraph::new(min_time, max_time);
for line in self.lines.iter().map(|line| &app.lines[*line]) {
histogram.add(line.time);
}
histogram
})
}
pub fn len(&self) -> usize {
self.lines.len()
}

View file

@ -65,7 +65,7 @@ fn log_row<'a>(result: &'a LogMatch, app: &'a App, name: &'static str) -> Row<'a
Text::from(message),
Text::from(paths),
Text::from(lines).alignment(Alignment::Right),
Text::from(result.sparkline.as_str()),
Text::from(result.sparkline(app)),
Text::from(result.count().to_string()),
])
.height(match_result.len() as u16)
@ -74,7 +74,7 @@ fn log_row<'a>(result: &'a LogMatch, app: &'a App, name: &'static str) -> Row<'a
Text::from(name),
Text::from(""),
Text::from(""),
Text::from(result.sparkline.as_str()),
Text::from(result.sparkline(app)),
Text::from(result.count().to_string()),
])
}

View file

@ -112,12 +112,12 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
}) => {
let selected = table_state.selected();
let histogram = if selected == 0 {
&app.all.histogram
app.all.histogram(app)
} else if selected < app.matches.len() + 1 {
let log_match = &app.matches[selected - 1];
&log_match.histogram
log_match.histogram(app)
} else {
&app.unmatched.histogram
app.unmatched.histogram(app)
};
frame.render_widget(UiHistogram::new(histogram), layout[0]);
@ -137,7 +137,7 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
&result.grouped[selected - 1]
};
frame.render_widget(UiHistogram::new(&selected_group.histogram), layout[0]);
frame.render_widget(UiHistogram::new(&selected_group.histogram(app)), layout[0]);
frame.render_stateful_widget(
grouped_lines(app, result, filter),
layout[1],

View file

@ -37,7 +37,7 @@ pub fn grouped_lines<'a>(
Text::from("All lines"),
Text::from(""),
Text::from(""),
Text::from(log_match.sparkline.as_str()),
Text::from(log_match.sparkline(app)),
Text::from(log_match.count().to_string()),
]))
.chain(
@ -58,7 +58,7 @@ fn group_row<'a>(app: &'a App, group: &'a GroupedLines) -> Row<'a> {
Text::from(line.level.as_str()),
Text::from(line.app.as_ref()),
Text::from(line.display()),
Text::from(group.sparkline.as_str()),
Text::from(group.sparkline(app)),
Text::from(group.len().to_string()),
])
}