some cleanup

This commit is contained in:
Robin Appelman 2024-07-30 23:11:26 +02:00
commit 6530749a01
9 changed files with 70 additions and 60 deletions

View file

@ -4,9 +4,17 @@ use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use time::format_description::well_known::iso8601::{Config, EncodedConfig, TimePrecision};
use time::format_description::well_known::Iso8601;
use time::OffsetDateTime; use time::OffsetDateTime;
use tinystr::TinyAsciiStr; use tinystr::TinyAsciiStr;
pub const TIME_FORMAT: EncodedConfig = Config::DEFAULT
.set_time_precision(TimePrecision::Second {
decimal_digits: None,
})
.encode();
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct LogLine { pub struct LogLine {
#[serde(default)] #[serde(default)]
@ -31,6 +39,11 @@ impl LogLine {
} }
} }
pub fn format_time(time: OffsetDateTime) -> String {
time.format(&Iso8601::<TIME_FORMAT>)
.unwrap_or_else(|_| "Invalid time".into())
}
impl LogLine { impl LogLine {
pub fn display(&self) -> String { pub fn display(&self) -> String {
if let Some(exception) = self.exception.as_ref() { if let Some(exception) = self.exception.as_ref() {

View file

@ -47,7 +47,7 @@ fn main() -> MainResult {
let mut lines = log_file.iter(); let mut lines = log_file.iter();
let mut counts: HashMap<MatchResult, Vec<usize>> = HashMap::new(); let mut counts: HashMap<MatchResult, Vec<usize>> = HashMap::new();
let first = lines.next().unwrap(); let first = lines.next().unwrap_or_default();
let first_parsed = match parse_line(first) { let first_parsed = match parse_line(first) {
Ok(first_parsed) => first_parsed, Ok(first_parsed) => first_parsed,
Err(e) => { Err(e) => {

View file

@ -21,7 +21,7 @@ impl LogMatch {
pub fn new(index: usize, statement: &LoggingStatement) -> LogMatch { pub fn new(index: usize, statement: &LoggingStatement) -> LogMatch {
LogMatch { LogMatch {
level: statement.level, level: statement.level,
pattern: Regex::new(statement.regex).unwrap(), pattern: Regex::new(statement.regex).expect("Invalid regex"),
pattern_length: statement.regex.len(), pattern_length: statement.regex.len(),
has_meaningful_message: statement has_meaningful_message: statement
.regex .regex

View file

@ -29,7 +29,7 @@ impl TimeGraph {
pub fn add(&mut self, time: OffsetDateTime) { pub fn add(&mut self, time: OffsetDateTime) {
self.histogram self.histogram
.record(time.unix_timestamp() as u64 - self.start + 1) .record(time.unix_timestamp() as u64 - self.start + 1)
.unwrap() .ok();
} }
pub fn counts(&self, buckets: usize) -> impl Iterator<Item = u64> + '_ { pub fn counts(&self, buckets: usize) -> impl Iterator<Item = u64> + '_ {
@ -45,7 +45,7 @@ impl TimeGraph {
for (value, count) in values.iter_mut().zip(self.counts(N)) { for (value, count) in values.iter_mut().zip(self.counts(N)) {
*value = count; *value = count;
} }
let max = values.iter().copied().max().unwrap() as f64; let max = values.iter().copied().max().unwrap_or_default() as f64;
let len = SPARKS.len() as f64 - 1.0; let len = SPARKS.len() as f64 - 1.0;
values values
.iter() .iter()

View file

@ -52,9 +52,9 @@ fn log_row<'a>(result: &'a LogMatch, app: &'a App, name: &'static str) -> Row<'a
let mut lines = String::new(); let mut lines = String::new();
for index in match_result.iter() { for index in match_result.iter() {
let statement = app.log_statements.get(index).expect("invalid match index"); let statement = app.log_statements.get(index).expect("invalid match index");
writeln!(&mut message, "{}", statement.message()).unwrap(); writeln!(&mut message, "{}", statement.message()).ok();
writeln!(&mut paths, "{}", statement.path()).unwrap(); writeln!(&mut paths, "{}", statement.path()).ok();
writeln!(&mut lines, "{}", statement.line).unwrap(); writeln!(&mut lines, "{}", statement.line).ok();
} }
Row::new([ Row::new([
Text::from(message), Text::from(message),

View file

@ -1,11 +1,10 @@
use crate::app::App; use crate::app::App;
use crate::logline::LogLine; use crate::logline::{format_time, LogLine};
use crate::ui::style::{TABLE_HEADER_STYLE, TIME_FORMAT}; use crate::ui::style::TABLE_HEADER_STYLE;
use crate::ui::table::ScrollbarTable; use crate::ui::table::ScrollbarTable;
use ratatui::layout::{Alignment, Constraint}; use ratatui::layout::{Alignment, Constraint};
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{Cell, Row}; use ratatui::widgets::{Cell, Row};
use time::format_description::well_known::Iso8601;
pub fn raw_logs<'a>(app: &'a App, lines: &[usize]) -> ScrollbarTable<'a> { pub fn raw_logs<'a>(app: &'a App, lines: &[usize]) -> ScrollbarTable<'a> {
let lines = lines.iter().copied().map(|i| &app.lines[i]); let lines = lines.iter().copied().map(|i| &app.lines[i]);
@ -35,6 +34,6 @@ fn log_row(line: &LogLine) -> Row {
Text::from(line.level.as_str()), Text::from(line.level.as_str()),
Text::from(line.app.as_str()), Text::from(line.app.as_str()),
Text::from(line.display()), Text::from(line.display()),
Text::from(line.time.format(&Iso8601::<TIME_FORMAT>).unwrap()).alignment(Alignment::Right), Text::from(format_time(line.time)).alignment(Alignment::Right),
]) ])
} }

View file

@ -1,21 +1,20 @@
use crate::app::App; use crate::app::App;
use crate::logline::{FullException, FullLogLine, LogLine, Trace}; use crate::logline::{format_time, FullException, FullLogLine, LogLine, Trace};
use crate::parse_line_full; use crate::parse_line_full;
use crate::ui::style::{TABLE_HEADER_STYLE, TIME_FORMAT}; use crate::ui::style::TABLE_HEADER_STYLE;
use crate::ui::table::{ScrollbarTable, ScrollbarTableState}; use crate::ui::table::{ScrollbarTable, ScrollbarTableState};
use ratatui::prelude::*; use ratatui::prelude::*;
use ratatui::widgets::{Cell, Paragraph, Row, Wrap}; use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use std::iter::once; use std::iter::once;
use time::format_description::well_known::Iso8601;
pub fn single_log(app: &App, line: &LogLine) -> SingleLog { pub fn single_log(app: &App, line: &LogLine) -> SingleLog {
let raw_line = app.get_line(line.index).unwrap(); let raw_line = app.get_line(line.index);
let line = parse_line_full(raw_line).unwrap(); let line = raw_line.and_then(|raw_line| parse_line_full(raw_line).ok());
SingleLog { line } SingleLog { line }
} }
pub struct SingleLog { pub struct SingleLog {
line: FullLogLine, line: Option<FullLogLine>,
} }
impl StatefulWidget for SingleLog { impl StatefulWidget for SingleLog {
@ -25,46 +24,51 @@ impl StatefulWidget for SingleLog {
where where
Self: Sized, Self: Sized,
{ {
let par = Paragraph::new(format!( if let Some(line) = self.line {
"{}\n\n {} {}\n {}\n\n from {} by {} at {}", let par = Paragraph::new(format!(
self.line.message, "{}\n\n {} {}\n {}\n\n from {} by {} at {}",
self.line.method, line.message,
self.line.url, line.method,
self.line.user_agent, line.url,
self.line.remote_address, line.user_agent,
self.line.user, line.remote_address,
self.line.time.format(&Iso8601::<TIME_FORMAT>).unwrap() line.user,
)) format_time(line.time),
.wrap(Wrap::default()); ))
.wrap(Wrap::default());
let layout = Layout::default() let layout = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.constraints(vec![ .constraints(vec![
Constraint::Min(7), Constraint::Min(7),
Constraint::Min(5), Constraint::Min(5),
Constraint::Percentage(100), Constraint::Percentage(100),
]) ])
.split(area); .split(area);
par.render(layout[0], buf); par.render(layout[0], buf);
if let Some(exception) = &self.line.exception { if let Some(exception) = &line.exception {
if self.line.message.contains(&exception.message) { if line.message.contains(&exception.message) {
StatefulWidget::render( StatefulWidget::render(
render_exception(exception), render_exception(exception),
layout[1].union(layout[2]), layout[1].union(layout[2]),
buf, buf,
state, state,
); );
} else { } else {
let ex_par = Paragraph::new(format!( let ex_par = Paragraph::new(format!(
"\n{}:\n {}", "\n{}:\n {}",
exception.exception, exception.message exception.exception, exception.message
)) ))
.wrap(Wrap::default()); .wrap(Wrap::default());
ex_par.render(layout[1], buf); ex_par.render(layout[1], buf);
StatefulWidget::render(render_exception(exception), layout[2], buf, state); StatefulWidget::render(render_exception(exception), layout[2], buf, state);
}
} }
} else {
let par = Paragraph::new("Failed to parse log line").wrap(Wrap::default());
par.render(area, buf);
} }
} }
} }

View file

@ -1,11 +1,5 @@
use ratatui::prelude::Style; use ratatui::prelude::Style;
use ratatui::style::palette::tailwind; use ratatui::style::palette::tailwind;
use time::format_description::well_known::iso8601::{Config, EncodedConfig, TimePrecision};
pub const TABLE_HEADER_STYLE: Style = Style::new().bg(tailwind::BLACK).fg(tailwind::GREEN.c600); pub const TABLE_HEADER_STYLE: Style = Style::new().bg(tailwind::BLACK).fg(tailwind::GREEN.c600);
pub const TABLE_SELECTED_STYLE: Style = Style::new().fg(tailwind::BLACK).bg(tailwind::GREEN.c600); pub const TABLE_SELECTED_STYLE: Style = Style::new().fg(tailwind::BLACK).bg(tailwind::GREEN.c600);
pub const TIME_FORMAT: EncodedConfig = Config::DEFAULT
.set_time_precision(TimePrecision::Second {
decimal_digits: None,
})
.encode();

View file

@ -57,7 +57,7 @@ impl ScrollbarTableState {
} }
pub fn selected(&self) -> usize { pub fn selected(&self) -> usize {
self.table.selected().unwrap() self.table.selected().unwrap_or_default()
} }
pub fn up(&mut self, step: usize) -> usize { pub fn up(&mut self, step: usize) -> usize {