mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 10:04:12 +02:00
add option to show parse errors
This commit is contained in:
parent
d04da3b11d
commit
d061e7b606
6 changed files with 97 additions and 19 deletions
|
|
@ -16,6 +16,7 @@ pub struct App {
|
|||
pub all: LogMatch,
|
||||
pub unmatched: LogMatch,
|
||||
pub log_file: LogFile,
|
||||
pub error_lines: Vec<(String, serde_json::Error)>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
|
|
|||
52
src/main.rs
52
src/main.rs
|
|
@ -72,35 +72,48 @@ fn main() -> MainResult {
|
|||
let mut results: Vec<_> = lines
|
||||
.enumerate()
|
||||
.par_bridge()
|
||||
.flat_map(|(index, line)| {
|
||||
let mut parsed = parse_line(line).ok()?;
|
||||
parsed.index = index;
|
||||
Some(parsed)
|
||||
.map(|(index, line)| {
|
||||
let mut parsed = parse_line(line);
|
||||
if let Ok(parsed) = parsed.as_mut() {
|
||||
parsed.index = index;
|
||||
};
|
||||
parsed.map_err(|err| (index, line, err))
|
||||
})
|
||||
.map(|parsed| {
|
||||
let log_match = matcher.match_log(&parsed);
|
||||
(parsed, log_match)
|
||||
parsed.map(|parsed| {
|
||||
let log_match = matcher.match_log(&parsed);
|
||||
(parsed, log_match)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
results.sort_by_key(|(line, _)| line.index);
|
||||
results.sort_by_key(|res| match res {
|
||||
Ok((line, _)) => line.index,
|
||||
Err((index, _, _)) => *index,
|
||||
});
|
||||
|
||||
let mut error_lines = Vec::with_capacity(32);
|
||||
let mut parsed_lines = Vec::with_capacity(1024);
|
||||
let mut unmatched_lines = Vec::with_capacity(256);
|
||||
|
||||
for (parsed_index, result) in results.into_iter().enumerate() {
|
||||
let parsed = match result {
|
||||
(parsed, Some(match_result)) => {
|
||||
counts.entry(match_result).or_default().push(parsed_index);
|
||||
parsed
|
||||
}
|
||||
(parsed, None) => {
|
||||
unmatched_lines.push(parsed_index);
|
||||
parsed
|
||||
}
|
||||
};
|
||||
let mut parsed_index = 0;
|
||||
|
||||
parsed_lines.push(parsed);
|
||||
for result in results.into_iter() {
|
||||
match result {
|
||||
Ok((parsed, Some(match_result))) => {
|
||||
counts.entry(match_result).or_default().push(parsed_index);
|
||||
parsed_lines.push(parsed);
|
||||
parsed_index += 1;
|
||||
}
|
||||
Ok((parsed, None)) => {
|
||||
unmatched_lines.push(parsed_index);
|
||||
parsed_lines.push(parsed);
|
||||
parsed_index += 1;
|
||||
}
|
||||
Err((_index, line, e)) => {
|
||||
error_lines.push((line.to_string(), e));
|
||||
}
|
||||
}
|
||||
}
|
||||
let error_count = log_file.iter().count() - parsed_lines.len();
|
||||
|
||||
|
|
@ -125,6 +138,7 @@ fn main() -> MainResult {
|
|||
last_date: parsed_lines.last().unwrap().time,
|
||||
lines: parsed_lines,
|
||||
log_statements: statements,
|
||||
error_lines,
|
||||
matches,
|
||||
unmatched,
|
||||
all,
|
||||
|
|
|
|||
22
src/ui/error_list.rs
Normal file
22
src/ui/error_list.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use crate::app::App;
|
||||
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 error_list(app: &App) -> ScrollbarTable {
|
||||
let header = [Text::from("Error"), Text::from("Line")]
|
||||
.into_iter()
|
||||
.map(Cell::from)
|
||||
.collect::<Row>()
|
||||
.style(TABLE_HEADER_STYLE)
|
||||
.height(1);
|
||||
|
||||
let widths = [Constraint::Percentage(50), Constraint::Percentage(50)];
|
||||
ScrollbarTable::new(app.error_lines.iter().map(error_row), widths).header(header)
|
||||
}
|
||||
|
||||
fn error_row((line, err): &(String, serde_json::Error)) -> Row {
|
||||
Row::new([Text::from(format!("{err}")), Text::from(line.as_str())])
|
||||
}
|
||||
|
|
@ -29,9 +29,10 @@ pub fn footer(app: &App, page: UiPage) -> Table {
|
|||
|
||||
fn help(page: UiPage) -> &'static str {
|
||||
match page {
|
||||
UiPage::MatchList => "«Q» Exit - «Enter» Select",
|
||||
UiPage::MatchList => "«Q» Exit - «Enter» Select - «E» Show parse errors",
|
||||
UiPage::Match => "«Q» Exit - «Enter» Select - «Esc» Back",
|
||||
UiPage::Logs => "«Q» Exit - «Esc» Back - «C» Copy log line",
|
||||
UiPage::Log => "«Q» Exit - «Esc» Back - «R» Toggle raw - «C» Copy log line",
|
||||
UiPage::Errors => "«Q» Exit - «Esc» Back - «C» Copy log line",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
use crate::app::App;
|
||||
use crate::error::UiError;
|
||||
use crate::ui::error_list::error_list;
|
||||
use crate::ui::footer::footer;
|
||||
use crate::ui::histogram::UiHistogram;
|
||||
use crate::ui::match_list::match_list;
|
||||
use crate::ui::raw_logs::raw_logs;
|
||||
use crate::ui::single_log::single_log;
|
||||
use crate::ui::single_match::grouped_lines;
|
||||
use crate::ui::state::{LogState, LogsState, MatchListState, MatchState, UiEvent, UiPage, UiState};
|
||||
use crate::ui::state::{
|
||||
ErrorState, LogState, LogsState, MatchListState, MatchState, UiEvent, UiPage, UiState,
|
||||
};
|
||||
use ratatui::crossterm::event::{Event, KeyCode, KeyModifiers};
|
||||
use ratatui::crossterm::terminal::{
|
||||
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
|
||||
|
|
@ -17,6 +20,7 @@ use ratatui::Terminal;
|
|||
use std::io;
|
||||
use std::io::stdout;
|
||||
|
||||
mod error_list;
|
||||
mod footer;
|
||||
mod histogram;
|
||||
mod match_list;
|
||||
|
|
@ -61,6 +65,7 @@ fn handle_events(page: UiPage) -> io::Result<Option<UiEvent>> {
|
|||
}
|
||||
KeyCode::Char('q') => Some(UiEvent::Quit),
|
||||
KeyCode::Esc => Some(UiEvent::Back),
|
||||
KeyCode::Char('e') if page == UiPage::MatchList => Some(UiEvent::Errors),
|
||||
KeyCode::Left if page != UiPage::MatchList => Some(UiEvent::Back),
|
||||
KeyCode::Down => Some(UiEvent::Down(1)),
|
||||
KeyCode::Up => Some(UiEvent::Up(1)),
|
||||
|
|
@ -137,5 +142,9 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
|
|||
);
|
||||
frame.render_widget(footer(app, page), layout[2]);
|
||||
}
|
||||
UiState::Errors(ErrorState { table_state, .. }) => {
|
||||
frame.render_stateful_widget(error_list(app), layout[0].union(layout[1]), table_state);
|
||||
frame.render_widget(footer(app, page), layout[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub enum UiState<'a> {
|
|||
Match(MatchState<'a>),
|
||||
Logs(LogsState<'a>),
|
||||
Log(LogState<'a>),
|
||||
Errors(ErrorState<'a>),
|
||||
Quit,
|
||||
}
|
||||
|
||||
|
|
@ -45,6 +46,12 @@ pub struct LogsState<'a> {
|
|||
pub previous: Box<UiState<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ErrorState<'a> {
|
||||
pub table_state: ScrollbarTableState,
|
||||
pub previous: Box<UiState<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> LogsState<'a> {
|
||||
fn selected(&self) -> usize {
|
||||
self.table_state.selected()
|
||||
|
|
@ -75,6 +82,7 @@ impl<'a> UiState<'a> {
|
|||
UiState::Match(_) => UiPage::Match,
|
||||
UiState::Logs(_) => UiPage::Logs,
|
||||
UiState::Log(_) => UiPage::Log,
|
||||
UiState::Errors(_) => UiPage::Errors,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +92,7 @@ impl<'a> UiState<'a> {
|
|||
UiState::Match(state) => Some(&mut state.table_state),
|
||||
UiState::Logs(state) => Some(&mut state.table_state),
|
||||
UiState::Log(state) => Some(&mut state.table_state),
|
||||
UiState::Errors(state) => Some(&mut state.table_state),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -125,6 +134,16 @@ impl<'a> UiState<'a> {
|
|||
}),
|
||||
)
|
||||
}
|
||||
(UiState::MatchList(state), UiEvent::Errors) => {
|
||||
let table_state = ScrollbarTableState::new(app.error_lines.len());
|
||||
(
|
||||
true,
|
||||
UiState::Errors(ErrorState {
|
||||
table_state,
|
||||
previous: Box::new(state.into()),
|
||||
}),
|
||||
)
|
||||
}
|
||||
(UiState::Match(state), UiEvent::Select) => {
|
||||
let selected = state.selected();
|
||||
let mut table_state = TableState::default();
|
||||
|
|
@ -181,10 +200,20 @@ impl<'a> UiState<'a> {
|
|||
copy_osc(raw);
|
||||
(false, UiState::Log(state))
|
||||
}
|
||||
(UiState::Errors(state), UiEvent::Copy) => {
|
||||
let raw = app
|
||||
.error_lines
|
||||
.get(state.table_state.selected())
|
||||
.map(|(line, _)| line.as_str())
|
||||
.unwrap_or_default();
|
||||
copy_osc(raw);
|
||||
(false, UiState::Errors(state))
|
||||
}
|
||||
(
|
||||
UiState::Match(MatchState { previous, .. })
|
||||
| UiState::Logs(LogsState { previous, .. })
|
||||
| UiState::Log(LogState { previous, .. }),
|
||||
| UiState::Log(LogState { previous, .. })
|
||||
| UiState::Errors(ErrorState { previous, .. }),
|
||||
UiEvent::Back,
|
||||
) => (true, *previous),
|
||||
(state, _) => (false, state),
|
||||
|
|
@ -197,6 +226,7 @@ pub enum UiEvent {
|
|||
Back,
|
||||
Up(usize),
|
||||
Down(usize),
|
||||
Errors,
|
||||
Select,
|
||||
Copy,
|
||||
}
|
||||
|
|
@ -207,4 +237,5 @@ pub enum UiPage {
|
|||
Match,
|
||||
Logs,
|
||||
Log,
|
||||
Errors,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue