mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 18:14:11 +02:00
some cleanup
This commit is contained in:
parent
c946b9a8a6
commit
6530749a01
9 changed files with 70 additions and 60 deletions
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,15 +24,16 @@ impl StatefulWidget for SingleLog {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
if let Some(line) = self.line {
|
||||||
let par = Paragraph::new(format!(
|
let par = Paragraph::new(format!(
|
||||||
"{}\n\n {} {}\n {}\n\n from {} by {} at {}",
|
"{}\n\n {} {}\n {}\n\n from {} by {} at {}",
|
||||||
self.line.message,
|
line.message,
|
||||||
self.line.method,
|
line.method,
|
||||||
self.line.url,
|
line.url,
|
||||||
self.line.user_agent,
|
line.user_agent,
|
||||||
self.line.remote_address,
|
line.remote_address,
|
||||||
self.line.user,
|
line.user,
|
||||||
self.line.time.format(&Iso8601::<TIME_FORMAT>).unwrap()
|
format_time(line.time),
|
||||||
))
|
))
|
||||||
.wrap(Wrap::default());
|
.wrap(Wrap::default());
|
||||||
|
|
||||||
|
|
@ -48,8 +48,8 @@ impl StatefulWidget for SingleLog {
|
||||||
|
|
||||||
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]),
|
||||||
|
|
@ -66,6 +66,10 @@ impl StatefulWidget for SingleLog {
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue