mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 10:04:12 +02:00
store logline references instead of indirecting trough logindex
This commit is contained in:
parent
c5af0ac37a
commit
dc4b5d2853
7 changed files with 80 additions and 86 deletions
82
src/app.rs
82
src/app.rs
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::logfile::{LogFile, LogLine, LogLineNumber};
|
use crate::logfile::{LogFile, LogLine, LogLineNumber};
|
||||||
use crate::logs::{LogIndex, ParsedLogs};
|
use crate::logs::ParsedLogs;
|
||||||
use crate::matcher::MatchResult;
|
use crate::matcher::MatchResult;
|
||||||
use crate::timegraph::TimeGraph;
|
use crate::timegraph::TimeGraph;
|
||||||
use logsmash_data::{LoggingStatementWithPathPrefix, StatementList};
|
use logsmash_data::{LoggingStatementWithPathPrefix, StatementList};
|
||||||
|
|
@ -8,39 +8,36 @@ use serde_json::Error as JsonError;
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
pub struct App<'a> {
|
pub struct App<'logs> {
|
||||||
pub lines: ParsedLogs<'a>,
|
pub lines: &'logs ParsedLogs<'logs>,
|
||||||
pub log_statements: StatementList,
|
pub log_statements: StatementList,
|
||||||
pub matches: Vec<LogMatch>,
|
pub matches: Vec<LogMatch<'logs>>,
|
||||||
pub all: LogMatch,
|
pub all: LogMatch<'logs>,
|
||||||
pub unmatched: LogMatch,
|
pub unmatched: LogMatch<'logs>,
|
||||||
pub log_file: &'a LogFile,
|
pub log_file: &'logs LogFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl<'logs> App<'logs> {
|
||||||
pub fn match_lines(&self) -> usize {
|
pub fn match_lines(&self) -> usize {
|
||||||
let unmatched_line_count = if self.unmatched.count == 0 { 0 } else { 1 };
|
let unmatched_line_count = if self.unmatched.count == 0 { 0 } else { 1 };
|
||||||
self.matches.len() + 1 + unmatched_line_count
|
self.matches.len() + 1 + unmatched_line_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_source_line(&self, index: LogLineNumber) -> Option<&'a str> {
|
pub fn get_source_line(&self, index: LogLineNumber) -> Option<&'logs str> {
|
||||||
self.log_file.nth(index)
|
self.log_file.nth(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_line(&self, index: LogIndex) -> &LogLine<'a> {
|
pub fn lines_by_request<'a: 'logs>(
|
||||||
&self.lines[index]
|
&'a self,
|
||||||
}
|
request_id: &'a str,
|
||||||
|
) -> impl Iterator<Item = &'logs LogLine<'logs>> + use<'a, 'logs> {
|
||||||
pub fn line_indices_by_request<'b>(
|
|
||||||
&'b self,
|
|
||||||
request_id: &'b str,
|
|
||||||
) -> impl Iterator<Item = LogIndex> + 'b {
|
|
||||||
self.lines
|
self.lines
|
||||||
.find_indices(move |line| line.request_id == request_id)
|
.find_lines(move |line| line.request_id == request_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error_lines(&self) -> impl Iterator<Item = (&'a str, &JsonError)> {
|
pub fn error_lines(&self) -> impl Iterator<Item = (&'logs str, &JsonError)> {
|
||||||
self.lines.errors().iter().map(|(line_number, error)| {
|
self.lines.errors().iter().map(|(line_number, error)| {
|
||||||
(self.log_file.nth(*line_number).unwrap_or_default(), error)
|
(self.log_file.nth(*line_number).unwrap_or_default(), error)
|
||||||
})
|
})
|
||||||
|
|
@ -49,21 +46,25 @@ impl<'a> App<'a> {
|
||||||
pub fn error_count(&self) -> usize {
|
pub fn error_count(&self) -> usize {
|
||||||
self.lines.errors().len()
|
self.lines.errors().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn time_range(&self) -> (OffsetDateTime, OffsetDateTime) {
|
||||||
|
(self.lines.first().time, self.lines.last().time)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LogMatch {
|
pub struct LogMatch<'logs> {
|
||||||
pub result: Option<MatchResult>,
|
pub result: Option<MatchResult>,
|
||||||
pub count: usize,
|
pub count: usize,
|
||||||
pub histogram: OnceCell<TimeGraph>,
|
pub histogram: OnceCell<TimeGraph>,
|
||||||
pub sparkline: OnceCell<String>,
|
pub sparkline: OnceCell<String>,
|
||||||
pub all: LineSet,
|
pub all: LineSet<'logs>,
|
||||||
pub grouped: Vec<LineSet>,
|
pub grouped: Vec<LineSet<'logs>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogMatch {
|
impl<'logs> LogMatch<'logs> {
|
||||||
pub fn new(result: Option<MatchResult>, lines: Vec<LogIndex>, all_lines: &ParsedLogs) -> Self {
|
pub fn new(result: Option<MatchResult>, lines: Vec<&'logs LogLine<'logs>>) -> Self {
|
||||||
let count = lines.len();
|
let count = lines.len();
|
||||||
let grouped = group_lines(all_lines, lines.iter().copied());
|
let grouped = group_lines(lines.iter().copied());
|
||||||
let all = LineSet::new(lines);
|
let all = LineSet::new(lines);
|
||||||
|
|
||||||
LogMatch {
|
LogMatch {
|
||||||
|
|
@ -87,7 +88,7 @@ impl LogMatch {
|
||||||
let min_time = app.lines.first().time;
|
let min_time = app.lines.first().time;
|
||||||
let max_time = app.lines.last().time;
|
let max_time = app.lines.last().time;
|
||||||
let mut histogram = TimeGraph::new(min_time, max_time);
|
let mut histogram = TimeGraph::new(min_time, max_time);
|
||||||
for line in self.all.lines.iter().map(|line| app.get_line(*line)) {
|
for line in &self.all.lines {
|
||||||
histogram.add(line.time);
|
histogram.add(line.time);
|
||||||
}
|
}
|
||||||
histogram
|
histogram
|
||||||
|
|
@ -128,19 +129,19 @@ impl LogMatch {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl LogMatch {
|
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
self.count
|
self.count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_lines<I: Iterator<Item = LogIndex>>(all_lines: &ParsedLogs, indices: I) -> Vec<LineSet> {
|
fn group_lines<'logs, I: Iterator<Item = &'logs LogLine<'logs>>>(
|
||||||
let mut map: BTreeMap<u64, Vec<LogIndex>> = BTreeMap::new();
|
indices: I,
|
||||||
|
) -> Vec<LineSet<'logs>> {
|
||||||
|
let mut map: BTreeMap<u64, Vec<&'logs LogLine<'logs>>> = BTreeMap::new();
|
||||||
|
|
||||||
for (i, line) in indices.map(|i| (i, &all_lines[i])) {
|
for line in indices {
|
||||||
map.entry(line.identity()).or_default().push(i);
|
map.entry(line.identity()).or_default().push(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut list: Vec<_> = map.into_values().map(LineSet::new).collect();
|
let mut list: Vec<_> = map.into_values().map(LineSet::new).collect();
|
||||||
|
|
@ -149,14 +150,14 @@ fn group_lines<I: Iterator<Item = LogIndex>>(all_lines: &ParsedLogs, indices: I)
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LineSet {
|
pub struct LineSet<'logs> {
|
||||||
pub lines: Vec<LogIndex>,
|
pub lines: Vec<&'logs LogLine<'logs>>,
|
||||||
pub histogram: OnceCell<TimeGraph>,
|
pub histogram: OnceCell<TimeGraph>,
|
||||||
pub sparkline: OnceCell<String>,
|
pub sparkline: OnceCell<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LineSet {
|
impl<'logs> LineSet<'logs> {
|
||||||
pub fn new(lines: Vec<LogIndex>) -> Self {
|
pub fn new(lines: Vec<&'logs LogLine<'logs>>) -> Self {
|
||||||
LineSet {
|
LineSet {
|
||||||
lines,
|
lines,
|
||||||
histogram: OnceCell::new(),
|
histogram: OnceCell::new(),
|
||||||
|
|
@ -172,10 +173,9 @@ impl LineSet {
|
||||||
|
|
||||||
pub fn histogram(&self, app: &App) -> &TimeGraph {
|
pub fn histogram(&self, app: &App) -> &TimeGraph {
|
||||||
self.histogram.get_or_init(|| {
|
self.histogram.get_or_init(|| {
|
||||||
let min_time = app.lines.first().time;
|
let (min_time, max_time) = app.time_range();
|
||||||
let max_time = app.lines.last().time;
|
|
||||||
let mut histogram = TimeGraph::new(min_time, max_time);
|
let mut histogram = TimeGraph::new(min_time, max_time);
|
||||||
for line in self.lines.iter().map(|line| &app.lines[*line]) {
|
for line in self.lines.iter() {
|
||||||
histogram.add(line.time);
|
histogram.add(line.time);
|
||||||
}
|
}
|
||||||
histogram
|
histogram
|
||||||
|
|
@ -186,11 +186,11 @@ impl LineSet {
|
||||||
self.lines.len()
|
self.lines.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches(&self, app: &App, filter: &Filter) -> bool {
|
pub fn matches(&self, filter: &Filter) -> bool {
|
||||||
if filter.is_empty() {
|
if filter.is_empty() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let line = &app.lines[self.lines[0]];
|
let line = self.lines[0];
|
||||||
if line.request_id == filter.filter {
|
if line.request_id == filter.filter {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,12 @@ pub struct LogLine<'a> {
|
||||||
pub time: OffsetDateTime,
|
pub time: OffsetDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq for LogLine<'a> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.index == other.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum LogUser {
|
pub enum LogUser {
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
10
src/logs.rs
10
src/logs.rs
|
|
@ -32,15 +32,11 @@ impl<'logfile> ParsedLogs<'logfile> {
|
||||||
&self.error_lines
|
&self.error_lines
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_indices<'a, F: Fn(&'a LogLine<'a>) -> bool>(
|
pub fn find_lines<'a: 'logfile, F: Fn(&'logfile LogLine<'logfile>) -> bool + 'logfile>(
|
||||||
&'a self,
|
&'a self,
|
||||||
filter: F,
|
filter: F,
|
||||||
) -> impl Iterator<Item = LogIndex> + use<'a, F> {
|
) -> impl Iterator<Item = &'logfile LogLine<'logfile>> + use<'a, 'logfile, F> {
|
||||||
self.parsed
|
self.parsed.iter().filter(move |line| filter(line))
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(move |(_, line)| filter(line))
|
|
||||||
.map(|(i, _)| LogIndex(i))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn first(&self) -> &LogLine<'logfile> {
|
pub fn first(&self) -> &LogLine<'logfile> {
|
||||||
|
|
|
||||||
24
src/main.rs
24
src/main.rs
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::app::{App, LogMatch};
|
use crate::app::{App, LogMatch};
|
||||||
use crate::error::LogError;
|
use crate::error::LogError;
|
||||||
use crate::logfile::{LogFile, LogLineNumber};
|
use crate::logfile::{LogFile, LogLineNumber};
|
||||||
|
use crate::logs::ParsedLogs;
|
||||||
use crate::matcher::{MatchResult, Matcher};
|
use crate::matcher::{MatchResult, Matcher};
|
||||||
use crate::ui::run_ui;
|
use crate::ui::run_ui;
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
|
|
@ -27,7 +28,6 @@ mod matcher;
|
||||||
mod timegraph;
|
mod timegraph;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use crate::logs::{LogIndex, ParsedLogs};
|
|
||||||
#[cfg(target_env = "musl")]
|
#[cfg(target_env = "musl")]
|
||||||
use tikv_jemallocator::Jemalloc;
|
use tikv_jemallocator::Jemalloc;
|
||||||
use time::format_description::{parse_owned, parse_strftime_owned};
|
use time::format_description::{parse_owned, parse_strftime_owned};
|
||||||
|
|
@ -78,7 +78,6 @@ fn main() -> MainResult {
|
||||||
.collect();
|
.collect();
|
||||||
let line_count = lines.len();
|
let line_count = lines.len();
|
||||||
|
|
||||||
let mut counts: HashMap<MatchResult, Vec<LogIndex>> = HashMap::new();
|
|
||||||
let Some(first_parsed) = lines.iter().find_map(|(_, line)| parse_line(line).ok()) else {
|
let Some(first_parsed) = lines.iter().find_map(|(_, line)| parse_line(line).ok()) else {
|
||||||
eprintln!("Failed to find at least one log line that parses successfully");
|
eprintln!("Failed to find at least one log line that parses successfully");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -123,10 +122,11 @@ fn main() -> MainResult {
|
||||||
let parsed_log: ParsedLogs = results.into_iter().collect();
|
let parsed_log: ParsedLogs = results.into_iter().collect();
|
||||||
progress.reset();
|
progress.reset();
|
||||||
|
|
||||||
|
let mut counts: HashMap<MatchResult, Vec<&LogLine>> = HashMap::new();
|
||||||
let line_matches: Vec<_> = parsed_log
|
let line_matches: Vec<_> = parsed_log
|
||||||
.all()
|
.all()
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|line| (line.index, matcher.match_log(line)))
|
.map(|line| (line, matcher.match_log(line)))
|
||||||
.inspect(|_| {
|
.inspect(|_| {
|
||||||
progress.icr();
|
progress.icr();
|
||||||
})
|
})
|
||||||
|
|
@ -135,13 +135,13 @@ fn main() -> MainResult {
|
||||||
|
|
||||||
let mut unmatched_lines = Vec::with_capacity(256);
|
let mut unmatched_lines = Vec::with_capacity(256);
|
||||||
|
|
||||||
for (index, result) in line_matches.into_iter() {
|
for (line, result) in line_matches.into_iter() {
|
||||||
match result {
|
match result {
|
||||||
Some(match_result) => {
|
Some(match_result) => {
|
||||||
counts.entry(match_result).or_default().push(index);
|
counts.entry(match_result).or_default().push(line);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
unmatched_lines.push(index);
|
unmatched_lines.push(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -150,20 +150,16 @@ fn main() -> MainResult {
|
||||||
matched_lines.sort_by_key(|(_, lines)| lines.len());
|
matched_lines.sort_by_key(|(_, lines)| lines.len());
|
||||||
matched_lines.reverse();
|
matched_lines.reverse();
|
||||||
|
|
||||||
let all = LogMatch::new(
|
let all = LogMatch::new(None, parsed_log.find_lines(|_| true).collect());
|
||||||
None,
|
let unmatched = LogMatch::new(None, unmatched_lines);
|
||||||
parsed_log.find_indices(|_| true).collect(),
|
|
||||||
&parsed_log,
|
|
||||||
);
|
|
||||||
let unmatched = LogMatch::new(None, unmatched_lines, &parsed_log);
|
|
||||||
|
|
||||||
let matches = matched_lines
|
let matches = matched_lines
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|(result, lines)| LogMatch::new(Some(result), lines, &parsed_log))
|
.map(|(result, lines)| LogMatch::new(Some(result), lines))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let app = App {
|
let app = App {
|
||||||
lines: parsed_log,
|
lines: &parsed_log,
|
||||||
log_statements: statements,
|
log_statements: statements,
|
||||||
matches,
|
matches,
|
||||||
unmatched,
|
unmatched,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::app::{App, Filter};
|
use crate::app::{App, Filter};
|
||||||
use crate::logfile::logline::{format_time, LogLine};
|
use crate::logfile::logline::{format_time, LogLine};
|
||||||
use crate::logs::LogIndex;
|
|
||||||
use crate::ui::state::GroupedLogGrouping;
|
use crate::ui::state::GroupedLogGrouping;
|
||||||
use crate::ui::style::TABLE_HEADER_STYLE;
|
use crate::ui::style::TABLE_HEADER_STYLE;
|
||||||
use crate::ui::table::{ScrollbarTable, ScrollbarTableState};
|
use crate::ui::table::{ScrollbarTable, ScrollbarTableState};
|
||||||
|
|
@ -12,7 +11,7 @@ use ratatui::text::Text;
|
||||||
use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
|
use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
|
||||||
|
|
||||||
pub struct GroupedLogs<'a> {
|
pub struct GroupedLogs<'a> {
|
||||||
lines: &'a [LogIndex],
|
lines: &'a [&'a LogLine<'a>],
|
||||||
app: &'a App<'a>,
|
app: &'a App<'a>,
|
||||||
filter: &'a Filter,
|
filter: &'a Filter,
|
||||||
grouping: GroupedLogGrouping,
|
grouping: GroupedLogGrouping,
|
||||||
|
|
@ -20,7 +19,7 @@ pub struct GroupedLogs<'a> {
|
||||||
|
|
||||||
pub fn grouped_logs<'a>(
|
pub fn grouped_logs<'a>(
|
||||||
app: &'a App<'a>,
|
app: &'a App<'a>,
|
||||||
lines: &'a [LogIndex],
|
lines: &'a [&'a LogLine<'a>],
|
||||||
filter: &'a Filter,
|
filter: &'a Filter,
|
||||||
grouping: GroupedLogGrouping,
|
grouping: GroupedLogGrouping,
|
||||||
) -> GroupedLogs<'a> {
|
) -> GroupedLogs<'a> {
|
||||||
|
|
@ -39,12 +38,11 @@ impl StatefulWidget for GroupedLogs<'_> {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let lines = self.lines.iter().copied().map(|i| self.app.get_line(i));
|
let lines = self.lines.iter().copied();
|
||||||
let line = self
|
let line = self
|
||||||
.lines
|
.lines
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.map(|i| &self.app.lines[i])
|
|
||||||
.filter(|line| line.matches(self.filter))
|
.filter(|line| line.matches(self.filter))
|
||||||
.nth(state.selected())
|
.nth(state.selected())
|
||||||
.unwrap_or(self.app.lines.first());
|
.unwrap_or(self.app.lines.first());
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pub fn grouped_lines<'a>(
|
||||||
|
|
||||||
pub struct SingleMatchTable<'a> {
|
pub struct SingleMatchTable<'a> {
|
||||||
app: &'a App<'a>,
|
app: &'a App<'a>,
|
||||||
log_match: &'a LogMatch,
|
log_match: &'a LogMatch<'a>,
|
||||||
filter: &'a Filter,
|
filter: &'a Filter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ impl StatefulWidget for SingleMatchTable<'_> {
|
||||||
.chain(
|
.chain(
|
||||||
grouped
|
grouped
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|group| group.matches(self.app, self.filter))
|
.filter(|group| group.matches(self.filter))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, group)| {
|
.map(|(i, group)| {
|
||||||
group_row(self.app, group, i.abs_diff(state.selected()) < 100)
|
group_row(self.app, group, i.abs_diff(state.selected()) < 100)
|
||||||
|
|
@ -80,7 +80,7 @@ impl StatefulWidget for SingleMatchTable<'_> {
|
||||||
|
|
||||||
fn group_row<'a>(app: &'a App, group: &'a LineSet, is_in_view: bool) -> Row<'a> {
|
fn group_row<'a>(app: &'a App, group: &'a LineSet, is_in_view: bool) -> Row<'a> {
|
||||||
if is_in_view {
|
if is_in_view {
|
||||||
let line = &app.lines[group.lines[0]];
|
let line = group.lines[0];
|
||||||
|
|
||||||
Row::new([
|
Row::new([
|
||||||
Text::from(line.level.as_str()),
|
Text::from(line.level.as_str()),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::app::{App, Filter, LogMatch, EMPTY_FILTER};
|
use crate::app::{App, Filter, LogMatch, EMPTY_FILTER};
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::logfile::logline::{FullLogLine, LogLine};
|
use crate::logfile::logline::{FullLogLine, LogLine};
|
||||||
use crate::logs::LogIndex;
|
|
||||||
use crate::ui::footer::FooterParams;
|
use crate::ui::footer::FooterParams;
|
||||||
use crate::ui::input::{PopMode, UiEvent};
|
use crate::ui::input::{PopMode, UiEvent};
|
||||||
use crate::ui::table::ScrollbarTableState;
|
use crate::ui::table::ScrollbarTableState;
|
||||||
|
|
@ -78,7 +77,7 @@ impl PartialEq for MatchListState<'_> {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MatchState<'a> {
|
pub struct MatchState<'a> {
|
||||||
pub result: &'a LogMatch,
|
pub result: &'a LogMatch<'a>,
|
||||||
pub table_state: ScrollbarTableState,
|
pub table_state: ScrollbarTableState,
|
||||||
pub previous: Box<UiState<'a>>,
|
pub previous: Box<UiState<'a>>,
|
||||||
pub filter: Filter,
|
pub filter: Filter,
|
||||||
|
|
@ -90,7 +89,7 @@ impl<'a> MatchState<'a> {
|
||||||
self.table_state.selected()
|
self.table_state.selected()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter(self, selected: usize, app: &'a App) -> UiState<'a> {
|
fn enter(self, selected: usize) -> UiState<'a> {
|
||||||
let mut table_state = TableState::default();
|
let mut table_state = TableState::default();
|
||||||
table_state.select(Some(0));
|
table_state.select(Some(0));
|
||||||
|
|
||||||
|
|
@ -102,7 +101,7 @@ impl<'a> MatchState<'a> {
|
||||||
self.result
|
self.result
|
||||||
.grouped
|
.grouped
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|grouped| grouped.matches(app, &self.filter))
|
.filter(|grouped| grouped.matches(&self.filter))
|
||||||
.nth(selected - 1)
|
.nth(selected - 1)
|
||||||
.expect("filtered select out of bounds")
|
.expect("filtered select out of bounds")
|
||||||
};
|
};
|
||||||
|
|
@ -133,7 +132,7 @@ pub enum GroupedLogGrouping {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GroupedLogsState<'a> {
|
pub struct GroupedLogsState<'a> {
|
||||||
pub lines: Cow<'a, [LogIndex]>,
|
pub lines: Cow<'a, [&'a LogLine<'a>]>,
|
||||||
pub table_state: ScrollbarTableState,
|
pub table_state: ScrollbarTableState,
|
||||||
pub previous: Box<UiState<'a>>,
|
pub previous: Box<UiState<'a>>,
|
||||||
pub filter: Filter,
|
pub filter: Filter,
|
||||||
|
|
@ -146,14 +145,13 @@ impl<'a> GroupedLogsState<'a> {
|
||||||
self.table_state.selected()
|
self.table_state.selected()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_selected<'b>(&self, selected: usize, app: &'b App<'b>) -> &'b LogLine<'b> {
|
fn get_selected(&self, selected: usize) -> &'a LogLine<'a> {
|
||||||
if self.filter.is_empty() {
|
if self.filter.is_empty() {
|
||||||
let line = self.lines[selected];
|
self.lines[selected]
|
||||||
&app.lines[line]
|
|
||||||
} else {
|
} else {
|
||||||
self.lines
|
self.lines
|
||||||
.iter()
|
.iter()
|
||||||
.map(|index| &app.lines[*index])
|
.copied()
|
||||||
.filter(|line| line.matches(&self.filter))
|
.filter(|line| line.matches(&self.filter))
|
||||||
.nth(selected)
|
.nth(selected)
|
||||||
.expect("filtered select out of bounds")
|
.expect("filtered select out of bounds")
|
||||||
|
|
@ -161,7 +159,7 @@ impl<'a> GroupedLogsState<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter(self, selected: usize, app: &'a App<'a>) -> UiState<'a> {
|
fn enter(self, selected: usize, app: &'a App<'a>) -> UiState<'a> {
|
||||||
let log = self.get_selected(selected, app);
|
let log = self.get_selected(selected);
|
||||||
let raw_line = app.get_source_line(log.line_number).unwrap();
|
let raw_line = app.get_source_line(log.line_number).unwrap();
|
||||||
let full_line = match parse_line_full(raw_line) {
|
let full_line = match parse_line_full(raw_line) {
|
||||||
Ok(line) => line,
|
Ok(line) => line,
|
||||||
|
|
@ -191,8 +189,8 @@ impl<'a> GroupedLogsState<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn by_request(self, selected: usize, app: &'a App<'a>) -> UiState<'a> {
|
fn by_request(self, selected: usize, app: &'a App<'a>) -> UiState<'a> {
|
||||||
let log = self.get_selected(selected, app);
|
let log = self.get_selected(selected);
|
||||||
let lines: Vec<_> = app.line_indices_by_request(&log.request_id).collect();
|
let lines: Vec<_> = app.lines_by_request(&log.request_id).collect();
|
||||||
|
|
||||||
let table_state = ScrollbarTableState::new(lines.len());
|
let table_state = ScrollbarTableState::new(lines.len());
|
||||||
UiState::GroupedLogs(GroupedLogsState {
|
UiState::GroupedLogs(GroupedLogsState {
|
||||||
|
|
@ -234,7 +232,7 @@ pub struct LogState<'a> {
|
||||||
|
|
||||||
impl<'a> LogState<'a> {
|
impl<'a> LogState<'a> {
|
||||||
fn by_request(self, app: &'a App<'a>) -> UiState<'a> {
|
fn by_request(self, app: &'a App<'a>) -> UiState<'a> {
|
||||||
let lines: Vec<_> = app.line_indices_by_request(&self.log.request_id).collect();
|
let lines: Vec<_> = app.lines_by_request(&self.log.request_id).collect();
|
||||||
|
|
||||||
let table_state = ScrollbarTableState::new(lines.len());
|
let table_state = ScrollbarTableState::new(lines.len());
|
||||||
UiState::GroupedLogs(GroupedLogsState {
|
UiState::GroupedLogs(GroupedLogsState {
|
||||||
|
|
@ -447,9 +445,9 @@ impl<'a> UiState<'a> {
|
||||||
}
|
}
|
||||||
(UiState::Match(state), UiEvent::Select) => {
|
(UiState::Match(state), UiEvent::Select) => {
|
||||||
let selected = state.selected();
|
let selected = state.selected();
|
||||||
(true, state.enter(selected, app))
|
(true, state.enter(selected))
|
||||||
}
|
}
|
||||||
(UiState::Match(state), UiEvent::Enter(selected)) => (true, state.enter(selected, app)),
|
(UiState::Match(state), UiEvent::Enter(selected)) => (true, state.enter(selected)),
|
||||||
(UiState::GroupedLogs(state), UiEvent::Select) => {
|
(UiState::GroupedLogs(state), UiEvent::Select) => {
|
||||||
let selected = state.selected();
|
let selected = state.selected();
|
||||||
(true, state.enter(selected, app))
|
(true, state.enter(selected, app))
|
||||||
|
|
@ -462,7 +460,7 @@ impl<'a> UiState<'a> {
|
||||||
let mut table_state = TableState::default();
|
let mut table_state = TableState::default();
|
||||||
table_state.select(Some(0));
|
table_state.select(Some(0));
|
||||||
|
|
||||||
let line = &app.lines[state.lines[selected]];
|
let line = state.lines[selected];
|
||||||
let raw = app.get_source_line(line.line_number).unwrap_or_default();
|
let raw = app.get_source_line(line.line_number).unwrap_or_default();
|
||||||
copy_osc(raw);
|
copy_osc(raw);
|
||||||
(false, UiState::GroupedLogs(state))
|
(false, UiState::GroupedLogs(state))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue