full line parse error page

This commit is contained in:
Robin Appelman 2025-05-27 22:30:45 +02:00
commit eec9d1aa00
4 changed files with 55 additions and 8 deletions

View file

@ -30,3 +30,16 @@ pub enum ReadError {
#[error("log file contained non-utf8 characters: {0:#}")]
Utf8(#[from] FromUtf8Error),
}
#[derive(Debug, Error)]
#[error("Error while parsing log line '{line}': {err:#}")]
pub struct ParseError {
pub err: serde_json::Error,
pub line: String,
}
impl PartialEq for ParseError {
fn eq(&self, other: &Self) -> bool {
self.line == other.line
}
}

View file

@ -64,6 +64,7 @@ fn help(page: UiPage) -> &'static str {
"«Q» Exit - «Esc» Back - «R» Toggle raw - «C» Copy log line - «R» Show logs for request"
}
UiPage::Errors => "«Q» Exit - «Esc» Back - «C» Copy log line",
UiPage::Error => "«Q» Exit - «Esc» Back",
}
}

View file

@ -9,7 +9,7 @@ use crate::ui::match_list::match_list;
use crate::ui::single_log::single_log;
use crate::ui::single_match::grouped_lines;
use crate::ui::state::{
ErrorState, GroupedLogsState, LogState, MatchListState, MatchState, UiState,
ErrorLinesState, ErrorState, GroupedLogsState, LogState, MatchListState, MatchState, UiState,
};
use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use ratatui::crossterm::terminal::{
@ -17,7 +17,9 @@ use ratatui::crossterm::terminal::{
};
use ratatui::crossterm::ExecutableCommand;
use ratatui::prelude::*;
use ratatui::widgets::Paragraph;
use ratatui::Terminal;
use serde_json::Value;
use std::io;
use std::io::stdout;
use std::panic::{set_hook, take_hook};
@ -171,9 +173,17 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
);
frame.render_widget(footer(app, state.footer_params()), layout[2]);
}
UiState::Errors(ErrorState { table_state, .. }) => {
UiState::Errors(ErrorLinesState { table_state, .. }) => {
frame.render_stateful_widget(error_list(app), layout[0].union(layout[1]), table_state);
frame.render_widget(footer(app, state.footer_params()), layout[2]);
}
UiState::Error(ErrorState { error, .. }) => {
let pretty =
serde_json::to_string_pretty(&serde_json::from_str::<Value>(&error.line).unwrap())
.unwrap();
let par = Paragraph::new(format!("{:#}\n\n{pretty}", error.err));
frame.render_widget(par, layout[0].union(layout[1]))
}
}
}

View file

@ -1,4 +1,5 @@
use crate::app::{App, Filter, LogMatch, EMPTY_FILTER};
use crate::error::ParseError;
use crate::logfile::logline::{FullLogLine, LogLine};
use crate::ui::footer::FooterParams;
use crate::ui::input::{PopMode, UiEvent};
@ -9,6 +10,7 @@ use derive_more::From;
use ratatui::widgets::TableState;
use std::borrow::Cow;
use std::iter::once;
use std::sync::Arc;
#[derive(Clone, From, PartialEq)]
pub enum UiState<'a> {
@ -16,7 +18,8 @@ pub enum UiState<'a> {
Match(MatchState<'a>),
GroupedLogs(GroupedLogsState<'a>),
Log(LogState<'a>),
Errors(ErrorState<'a>),
Errors(ErrorLinesState<'a>),
Error(ErrorState<'a>),
Quit,
}
@ -159,7 +162,18 @@ impl<'a> GroupedLogsState<'a> {
fn enter(self, selected: usize, app: &'a App<'a>) -> UiState<'a> {
let log = self.get_selected(selected, app);
let raw_line = app.get_line(log.index).unwrap();
let full_line = parse_line_full(raw_line).unwrap();
let full_line = match parse_line_full(raw_line) {
Ok(line) => line,
Err(err) => {
return UiState::Error(ErrorState {
error: Arc::new(ParseError {
err,
line: raw_line.into(),
}),
previous: Box::new(self.into()),
});
}
};
let trace_len = if let Some(exception) = &full_line.exception {
exception.stack().map(|e| 1 + e.trace.len()).sum()
} else {
@ -198,12 +212,12 @@ impl PartialEq for GroupedLogsState<'_> {
}
#[derive(Clone)]
pub struct ErrorState<'a> {
pub struct ErrorLinesState<'a> {
pub table_state: ScrollbarTableState,
pub previous: Box<UiState<'a>>,
}
impl PartialEq for ErrorState<'_> {
impl PartialEq for ErrorLinesState<'_> {
fn eq(&self, _other: &Self) -> bool {
true
}
@ -258,6 +272,7 @@ impl<'a> UiState<'a> {
UiState::GroupedLogs(_) => UiPage::Logs,
UiState::Log(_) => UiPage::Log,
UiState::Errors(_) => UiPage::Errors,
UiState::Error(_) => UiPage::Error,
}
}
@ -373,6 +388,7 @@ impl<'a> UiState<'a> {
UiState::GroupedLogs(_) => UI_HEADER_SIZE + 1,
UiState::Log(_) => 0,
UiState::Errors(_) => 0,
UiState::Error(_) => 0,
UiState::Quit => 0,
}
}
@ -422,7 +438,7 @@ impl<'a> UiState<'a> {
let table_state = ScrollbarTableState::new(app.error_lines.len());
(
true,
UiState::Errors(ErrorState {
UiState::Errors(ErrorLinesState {
table_state,
previous: Box::new(state.into()),
}),
@ -513,7 +529,7 @@ impl<'a> UiState<'a> {
UiState::Match(MatchState { previous, .. })
| UiState::GroupedLogs(GroupedLogsState { previous, .. })
| UiState::Log(LogState { previous, .. })
| UiState::Errors(ErrorState { previous, .. }),
| UiState::Errors(ErrorLinesState { previous, .. }),
UiEvent::Back,
) => (true, *previous),
(state, _) => (false, state),
@ -538,4 +554,11 @@ pub enum UiPage {
Logs,
Log,
Errors,
Error,
}
#[derive(Clone, PartialEq)]
pub struct ErrorState<'a> {
pub error: Arc<ParseError>,
pub previous: Box<UiState<'a>>,
}