mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 18:14:11 +02:00
group matches by loglevel for faster matching
This commit is contained in:
parent
ece904f791
commit
7af8f0d63d
3 changed files with 74 additions and 28 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -3,3 +3,4 @@ target
|
||||||
.env
|
.env
|
||||||
result
|
result
|
||||||
*.log
|
*.log
|
||||||
|
profile.json
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Clone, Copy, Deserialize, Hash)]
|
#[derive(Debug, Default, PartialEq, Clone, Copy, Deserialize, Hash, PartialOrd, Ord, Eq)]
|
||||||
#[serde(from = "i64")]
|
#[serde(from = "i64")]
|
||||||
pub enum LogLevel {
|
pub enum LogLevel {
|
||||||
Debug = 0,
|
Debug = 0,
|
||||||
|
|
@ -26,6 +26,18 @@ impl From<i64> for LogLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogLevel {
|
impl LogLevel {
|
||||||
|
pub fn iter() -> impl Iterator<Item = LogLevel> {
|
||||||
|
[
|
||||||
|
LogLevel::Debug,
|
||||||
|
LogLevel::Info,
|
||||||
|
LogLevel::Warn,
|
||||||
|
LogLevel::Error,
|
||||||
|
LogLevel::Exception,
|
||||||
|
LogLevel::Unknown,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn matches(&self, matcher_level: LogLevel) -> bool {
|
pub fn matches(&self, matcher_level: LogLevel) -> bool {
|
||||||
matcher_level == *self || matcher_level == LogLevel::Exception || *self == LogLevel::Unknown
|
matcher_level == *self || matcher_level == LogLevel::Exception || *self == LogLevel::Unknown
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,12 @@ use itertools::Either;
|
||||||
use logsmash_data::{LogLevel, LoggingStatement, StatementList};
|
use logsmash_data::{LogLevel, LoggingStatement, StatementList};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct LogMatch {
|
pub struct LogMatch {
|
||||||
level: LogLevel,
|
level: LogLevel,
|
||||||
pattern: Option<&'static str>,
|
pattern: &'static str,
|
||||||
exception: Option<&'static str>,
|
exception: Option<&'static str>,
|
||||||
path: &'static str,
|
path: &'static str,
|
||||||
line: usize,
|
line: usize,
|
||||||
|
|
@ -17,9 +19,11 @@ 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: statement
|
pattern: if statement.has_meaningful_message() {
|
||||||
.has_meaningful_message()
|
statement.pattern
|
||||||
.then_some(statement.pattern),
|
} else {
|
||||||
|
""
|
||||||
|
},
|
||||||
exception: statement.exception,
|
exception: statement.exception,
|
||||||
path: statement.path,
|
path: statement.path,
|
||||||
line: statement.line,
|
line: statement.line,
|
||||||
|
|
@ -28,12 +32,13 @@ impl LogMatch {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pattern_len(&self) -> usize {
|
pub fn pattern_len(&self) -> usize {
|
||||||
self.pattern.map(|pat| pat.len()).unwrap_or_default()
|
self.pattern.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Matcher {
|
pub struct Matcher {
|
||||||
matches: Vec<LogMatch>,
|
matches: Vec<LogMatch>,
|
||||||
|
level_ranges: Vec<Range<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Matcher {
|
impl Matcher {
|
||||||
|
|
@ -43,9 +48,37 @@ impl Matcher {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, statement)| LogMatch::new(index, statement))
|
.map(|(index, statement)| LogMatch::new(index, statement))
|
||||||
.collect();
|
.collect();
|
||||||
matches.sort_by(|a, b| a.pattern_len().cmp(&b.pattern_len()).reverse());
|
matches.sort_by(|a, b| {
|
||||||
|
// sort first by level, then by longest pattern
|
||||||
|
a.level
|
||||||
|
.cmp(&b.level)
|
||||||
|
.then(a.pattern_len().cmp(&b.pattern_len()).reverse())
|
||||||
|
});
|
||||||
|
let level_starts =
|
||||||
|
LogLevel::iter().map(|level| matches.iter().position(|m| m.level == level));
|
||||||
|
let level_ends =
|
||||||
|
LogLevel::iter().map(|level| matches.iter().rposition(|m| m.level == level));
|
||||||
|
let level_ranges = level_starts
|
||||||
|
.zip(level_ends)
|
||||||
|
.map(|(start, end)| match (start, end) {
|
||||||
|
(Some(start), Some(end)) => start..end + 1,
|
||||||
|
_ => 0..0,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
Matcher { matches }
|
Matcher {
|
||||||
|
matches,
|
||||||
|
level_ranges,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_for_level(&self, level: LogLevel) -> impl Iterator<Item = &[LogMatch]> {
|
||||||
|
LogLevel::iter()
|
||||||
|
.zip(self.level_ranges.iter())
|
||||||
|
.filter_map(move |(match_level, range)| {
|
||||||
|
level.matches(match_level).then_some(range.clone())
|
||||||
|
})
|
||||||
|
.map(|range| &self.matches[range])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_log(&self, log: &LogLine) -> Option<MatchResult> {
|
pub fn match_log(&self, log: &LogLine) -> Option<MatchResult> {
|
||||||
|
|
@ -58,15 +91,14 @@ impl Matcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for log_match in self.matches.iter() {
|
for matches_for_level in self.matches_for_level(log.level) {
|
||||||
|
for log_match in matches_for_level {
|
||||||
if log_match.pattern_len() < best_length {
|
if log_match.pattern_len() < best_length {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(source_pattern) = log_match.pattern {
|
if !log_match.pattern.is_empty() {
|
||||||
if log.level.matches(log_match.level)
|
if match_single(log_match.pattern, log.message.as_ref()) {
|
||||||
&& match_single(source_pattern, log.message.as_ref())
|
|
||||||
{
|
|
||||||
best_length = log_match.pattern_len();
|
best_length = log_match.pattern_len();
|
||||||
best_match = Some(match best_match {
|
best_match = Some(match best_match {
|
||||||
Some(MatchResult::Single(res)) => {
|
Some(MatchResult::Single(res)) => {
|
||||||
|
|
@ -81,6 +113,7 @@ impl Matcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo: handle translated log messages
|
// todo: handle translated log messages
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue