mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 18:14:11 +02:00
cache sparklines
This commit is contained in:
parent
5d4a17f289
commit
5b1ae14639
7 changed files with 46 additions and 41 deletions
11
src/app.rs
11
src/app.rs
|
|
@ -37,6 +37,7 @@ pub struct LogMatch {
|
|||
pub result: Option<MatchResult>,
|
||||
pub lines: Vec<usize>,
|
||||
pub histogram: TimeGraph,
|
||||
pub sparkline: String,
|
||||
pub grouped: Vec<GroupedLines>,
|
||||
}
|
||||
|
||||
|
|
@ -49,11 +50,13 @@ impl LogMatch {
|
|||
histogram.add(line.time);
|
||||
}
|
||||
let grouped = group_lines(all_lines, lines.iter().copied());
|
||||
let sparkline = histogram.sparkline::<10>();
|
||||
|
||||
LogMatch {
|
||||
result,
|
||||
lines,
|
||||
histogram,
|
||||
sparkline,
|
||||
grouped,
|
||||
}
|
||||
}
|
||||
|
|
@ -84,6 +87,7 @@ 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,
|
||||
}
|
||||
|
||||
impl GroupedLines {
|
||||
|
|
@ -94,7 +98,12 @@ impl GroupedLines {
|
|||
for line in lines.iter().map(|line| &all_lines[*line]) {
|
||||
histogram.add(line.time);
|
||||
}
|
||||
GroupedLines { lines, histogram }
|
||||
let sparkline = histogram.sparkline::<10>();
|
||||
GroupedLines {
|
||||
lines,
|
||||
histogram,
|
||||
sparkline,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
|
|
|||
|
|
@ -28,12 +28,30 @@ impl TimeGraph {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn counts(&self, buckets: usize) -> Vec<u64> {
|
||||
pub fn counts(&self, buckets: usize) -> impl Iterator<Item = u64> + '_ {
|
||||
let step = (self.end - self.start + 1) / buckets as u64;
|
||||
|
||||
self.histogram
|
||||
.iter_linear(step)
|
||||
.map(|val| val.count_since_last_iteration())
|
||||
}
|
||||
|
||||
pub fn sparkline<const N: usize>(&self) -> String {
|
||||
let mut values = [0; N];
|
||||
for (value, count) in values.iter_mut().zip(self.counts(N)) {
|
||||
*value = count;
|
||||
}
|
||||
let max = values.iter().copied().max().unwrap() as f64;
|
||||
let len = SPARKS.len() as f64 - 1.0;
|
||||
values
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|val| {
|
||||
let rel = val as f64 / max;
|
||||
SPARKS[(rel * len) as usize]
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
const SPARKS: &[char] = &[' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
|
||||
|
|
|
|||
|
|
@ -17,28 +17,8 @@ impl Widget for UiHistogram<'_> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let values = self.data.counts(area.width as usize);
|
||||
let values: Vec<_> = self.data.counts(area.width as usize).collect();
|
||||
let sparkline = Sparkline::default().data(&values);
|
||||
sparkline.render(area, buf)
|
||||
}
|
||||
}
|
||||
|
||||
const SPARKS: &[char] = &[' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
|
||||
|
||||
pub fn sparkline(values: &[u64]) -> String {
|
||||
let max = values.iter().copied().max().unwrap() as f64;
|
||||
let len = SPARKS.len() as f64 - 1.0;
|
||||
values
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|val| {
|
||||
let rel = val as f64 / max;
|
||||
SPARKS[(rel * len) as usize]
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sparkline() {
|
||||
assert_eq!(" ▇█", sparkline(&[0, 900, 1000]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::app::{App, LogMatch};
|
||||
use crate::ui::histogram::sparkline;
|
||||
use crate::ui::style::TABLE_HEADER_STYLE;
|
||||
use crate::ui::table::ScrollbarTable;
|
||||
use itertools::Either;
|
||||
|
|
@ -46,7 +45,7 @@ pub fn match_list(app: &App) -> ScrollbarTable {
|
|||
.header(header)
|
||||
}
|
||||
|
||||
fn log_row<'a>(result: &LogMatch, app: &'a App, name: &'static str) -> Row<'a> {
|
||||
fn log_row<'a>(result: &'a LogMatch, app: &'a App, name: &'static str) -> Row<'a> {
|
||||
if let Some(match_result) = &result.result {
|
||||
let mut message = String::new();
|
||||
let mut paths = String::new();
|
||||
|
|
@ -61,7 +60,7 @@ fn log_row<'a>(result: &LogMatch, app: &'a App, name: &'static str) -> Row<'a> {
|
|||
Text::from(message),
|
||||
Text::from(paths),
|
||||
Text::from(lines).alignment(Alignment::Right),
|
||||
Text::from(sparkline(&result.histogram.counts(10))),
|
||||
Text::from(result.sparkline.as_str()),
|
||||
Text::from(result.count().to_string()),
|
||||
])
|
||||
.height(match_result.len() as u16)
|
||||
|
|
@ -70,7 +69,7 @@ fn log_row<'a>(result: &LogMatch, app: &'a App, name: &'static str) -> Row<'a> {
|
|||
Text::from(name),
|
||||
Text::from(""),
|
||||
Text::from(""),
|
||||
Text::from(sparkline(&result.histogram.counts(10))),
|
||||
Text::from(result.sparkline.as_str()),
|
||||
Text::from(result.count().to_string()),
|
||||
])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use ratatui::text::Text;
|
|||
use ratatui::widgets::{Cell, Row};
|
||||
use time::format_description::well_known::Iso8601;
|
||||
|
||||
pub fn raw_logs(app: &App, lines: &[usize]) -> ScrollbarTable<'static> {
|
||||
pub fn raw_logs<'a>(app: &'a App, lines: &[usize]) -> ScrollbarTable<'a> {
|
||||
let lines = lines.iter().copied().map(|i| &app.lines[i]);
|
||||
let header = [
|
||||
Text::from("Level"),
|
||||
|
|
@ -30,10 +30,10 @@ pub fn raw_logs(app: &App, lines: &[usize]) -> ScrollbarTable<'static> {
|
|||
ScrollbarTable::new(lines.map(log_row), widths).header(header)
|
||||
}
|
||||
|
||||
fn log_row(line: &LogLine) -> Row<'static> {
|
||||
fn log_row(line: &LogLine) -> Row {
|
||||
Row::new([
|
||||
Text::from(line.level.as_str().to_string()),
|
||||
Text::from(line.app.to_string()),
|
||||
Text::from(line.level.as_str()),
|
||||
Text::from(line.app.as_str()),
|
||||
Text::from(line.display()),
|
||||
Text::from(line.time.format(&Iso8601::<TIME_FORMAT>).unwrap()).alignment(Alignment::Right),
|
||||
])
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ fn exception_trace(exception: &FullException) -> impl Iterator<Item = Row> + '_
|
|||
let exception_row = Row::new([
|
||||
Text::from(""),
|
||||
Text::from(exception.line.to_string()).alignment(Alignment::Right),
|
||||
Text::from(exception.file.clone()),
|
||||
Text::from(exception.file.as_str()),
|
||||
])
|
||||
.style(TABLE_HEADER_STYLE);
|
||||
let trace_rows = exception.trace.iter().map(trace_line);
|
||||
|
|
@ -83,7 +83,7 @@ fn exception_trace(exception: &FullException) -> impl Iterator<Item = Row> + '_
|
|||
|
||||
fn trace_line(trace: &Trace) -> Row {
|
||||
Row::new([
|
||||
Text::from(trace.file.clone()),
|
||||
Text::from(trace.file.as_str()),
|
||||
Text::from(if trace.line > 0 {
|
||||
trace.line.to_string()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::app::{App, GroupedLines, LogMatch};
|
||||
use crate::ui::histogram::sparkline;
|
||||
use crate::ui::style::TABLE_HEADER_STYLE;
|
||||
use crate::ui::table::ScrollbarTable;
|
||||
use ratatui::layout::Constraint;
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
|
||||
pub fn grouped_lines(app: &App, log_match: &LogMatch) -> ScrollbarTable<'static> {
|
||||
pub fn grouped_lines<'a>(app: &'a App, log_match: &'a LogMatch) -> ScrollbarTable<'a> {
|
||||
let grouped = &log_match.grouped;
|
||||
let header = [
|
||||
Text::from("Level"),
|
||||
|
|
@ -31,14 +30,14 @@ pub fn grouped_lines(app: &App, log_match: &LogMatch) -> ScrollbarTable<'static>
|
|||
ScrollbarTable::new(grouped.iter().map(|group| group_row(app, group)), widths).header(header)
|
||||
}
|
||||
|
||||
fn group_row(app: &App, group: &GroupedLines) -> Row<'static> {
|
||||
fn group_row<'a>(app: &'a App, group: &'a GroupedLines) -> Row<'a> {
|
||||
let line = &app.lines[group.lines[0]];
|
||||
|
||||
Row::new([
|
||||
line.level.as_str().to_string(),
|
||||
line.app.to_string(),
|
||||
line.display(),
|
||||
sparkline(&group.histogram.counts(10)),
|
||||
group.len().to_string(),
|
||||
Text::from(line.level.as_str()),
|
||||
Text::from(line.app.as_str()),
|
||||
Text::from(line.display()),
|
||||
Text::from(group.sparkline.as_str()),
|
||||
Text::from(group.len().to_string()),
|
||||
])
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue