mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 18:14:11 +02:00
log trace
This commit is contained in:
parent
04308e966b
commit
aff67c43dd
4 changed files with 229 additions and 11 deletions
|
|
@ -170,8 +170,14 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
|
|||
);
|
||||
frame.render_widget(footer(app, page), layout[2]);
|
||||
}
|
||||
UiState::Log(LogState { log, .. }) => {
|
||||
frame.render_widget(single_log(app, log), layout[0].union(layout[1]));
|
||||
UiState::Log(LogState {
|
||||
log, table_state, ..
|
||||
}) => {
|
||||
frame.render_stateful_widget(
|
||||
single_log(app, log),
|
||||
layout[0].union(layout[1]),
|
||||
table_state,
|
||||
);
|
||||
frame.render_widget(footer(app, page), layout[2]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,98 @@
|
|||
use crate::app::App;
|
||||
use crate::logline::LogLine;
|
||||
use ratatui::widgets::{Paragraph, Wrap};
|
||||
use crate::logline::{FullException, FullLogLine, LogLine, Trace};
|
||||
use crate::ui::style::{TABLE_HEADER_STYLE, TABLE_SELECTED_STYLE, TIME_FORMAT};
|
||||
use ratatui::prelude::*;
|
||||
use ratatui::widgets::{Cell, HighlightSpacing, Paragraph, Row, Table, TableState, Wrap};
|
||||
use std::iter::once;
|
||||
use time::format_description::well_known::Iso8601;
|
||||
|
||||
pub fn single_log<'a>(_app: &App, line: &'a LogLine) -> Paragraph<'a> {
|
||||
Paragraph::new(line.display()).wrap(Wrap::default())
|
||||
pub fn single_log(app: &App, line: &LogLine) -> SingleLog {
|
||||
let raw_line = app.get_line(line.index).unwrap();
|
||||
let line: FullLogLine = serde_json::from_str(raw_line).unwrap();
|
||||
SingleLog { line }
|
||||
}
|
||||
|
||||
pub struct SingleLog {
|
||||
line: FullLogLine,
|
||||
}
|
||||
|
||||
impl StatefulWidget for SingleLog {
|
||||
type State = TableState;
|
||||
|
||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let par = Paragraph::new(format!(
|
||||
"{}\n\n {} {}\n {}\n\n from {} by {} at {}",
|
||||
self.line.message,
|
||||
self.line.method,
|
||||
self.line.url,
|
||||
self.line.user_agent,
|
||||
self.line.remote_address,
|
||||
self.line.user,
|
||||
self.line.time.format(&Iso8601::<TIME_FORMAT>).unwrap()
|
||||
))
|
||||
.wrap(Wrap::default());
|
||||
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(vec![Constraint::Min(7), Constraint::Percentage(100)])
|
||||
.split(area);
|
||||
|
||||
par.render(layout[0], buf);
|
||||
|
||||
if let Some(exception) = &self.line.exception {
|
||||
StatefulWidget::render(render_exception(exception), layout[1], buf, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_exception(exception: &FullException) -> Table {
|
||||
let header = [
|
||||
Text::from("File"),
|
||||
Text::from("Line").alignment(Alignment::Right),
|
||||
Text::from("Function"),
|
||||
]
|
||||
.into_iter()
|
||||
.map(Cell::from)
|
||||
.collect::<Row>()
|
||||
.style(TABLE_HEADER_STYLE)
|
||||
.height(1);
|
||||
|
||||
let widths = [
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Min(10),
|
||||
Constraint::Percentage(60),
|
||||
];
|
||||
let rows = exception.stack().flat_map(exception_trace);
|
||||
let table = Table::new(rows, widths)
|
||||
.header(header)
|
||||
.highlight_style(TABLE_SELECTED_STYLE)
|
||||
.highlight_spacing(HighlightSpacing::Always);
|
||||
table
|
||||
}
|
||||
|
||||
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()),
|
||||
])
|
||||
.style(TABLE_HEADER_STYLE);
|
||||
let trace_rows = exception.trace.iter().map(trace_line);
|
||||
once(exception_row).chain(trace_rows)
|
||||
}
|
||||
|
||||
fn trace_line(trace: &Trace) -> Row {
|
||||
Row::new([
|
||||
Text::from(trace.file.clone()),
|
||||
Text::from(if trace.line > 0 {
|
||||
trace.line.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
})
|
||||
.alignment(Alignment::Right),
|
||||
Text::from(trace.function().to_string()),
|
||||
])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::app::{App, LogMatch};
|
||||
use crate::copy_osc;
|
||||
use crate::logline::LogLine;
|
||||
use crate::logline::{FullLogLine, LogLine};
|
||||
use derive_more::From;
|
||||
use ratatui::widgets::{ScrollbarState, TableState};
|
||||
use table_state::TableStateExt;
|
||||
|
|
@ -56,7 +56,10 @@ impl<'a> LogsState<'a> {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct LogState<'a> {
|
||||
pub trace_len: usize,
|
||||
pub log: &'a LogLine,
|
||||
pub full_line: FullLogLine,
|
||||
pub table_state: TableState,
|
||||
pub previous: Box<UiState<'a>>,
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +87,7 @@ impl<'a> UiState<'a> {
|
|||
UiState::MatchList(state) => Some(&mut state.table_state),
|
||||
UiState::Match(state) => Some(&mut state.table_state),
|
||||
UiState::Logs(state) => Some(&mut state.table_state),
|
||||
UiState::Log(state) => Some(&mut state.table_state),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +106,7 @@ impl<'a> UiState<'a> {
|
|||
UiState::MatchList(_) => app.match_lines(),
|
||||
UiState::Match(state) => state.result.grouped.len(),
|
||||
UiState::Logs(state) => state.lines.len(),
|
||||
UiState::Log(state) => state.trace_len,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
|
@ -115,8 +120,9 @@ impl<'a> UiState<'a> {
|
|||
let count = state.row_count(app);
|
||||
if let Some(table_state) = state.table_state() {
|
||||
let pos = table_state.down(count, step);
|
||||
let scroll_state = state.scroll_state().unwrap();
|
||||
*scroll_state = scroll_state.position(pos);
|
||||
if let Some(scroll_state) = state.scroll_state() {
|
||||
*scroll_state = scroll_state.position(pos);
|
||||
}
|
||||
}
|
||||
state
|
||||
}
|
||||
|
|
@ -124,8 +130,9 @@ impl<'a> UiState<'a> {
|
|||
let count = state.row_count(app);
|
||||
if let Some(table_state) = state.table_state() {
|
||||
let pos = table_state.up(count, step);
|
||||
let scroll_state = state.scroll_state().unwrap();
|
||||
*scroll_state = scroll_state.position(pos);
|
||||
if let Some(scroll_state) = state.scroll_state() {
|
||||
*scroll_state = scroll_state.position(pos);
|
||||
}
|
||||
}
|
||||
state
|
||||
}
|
||||
|
|
@ -168,8 +175,18 @@ impl<'a> UiState<'a> {
|
|||
|
||||
let line = state.lines[selected];
|
||||
let log = &app.lines[line];
|
||||
let raw_line = app.get_line(log.index).unwrap();
|
||||
let full_line: FullLogLine = serde_json::from_str(raw_line).unwrap();
|
||||
let trace_len = if let Some(exception) = &full_line.exception {
|
||||
exception.stack().map(|e| 1 + e.trace.len()).sum()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
UiState::Log(LogState {
|
||||
log,
|
||||
full_line,
|
||||
trace_len,
|
||||
table_state,
|
||||
previous: Box::new(state.into()),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue