mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 18:14:11 +02:00
initial matching
This commit is contained in:
parent
73e9c08413
commit
246b4552f9
31 changed files with 87489 additions and 43394 deletions
44
src/main.rs
44
src/main.rs
|
|
@ -1,3 +1,45 @@
|
|||
use crate::matcher::Matcher;
|
||||
use clap::Parser;
|
||||
use cloud_log_analyser_data::get_statements;
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
|
||||
mod matcher;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
enum Args {
|
||||
Log(LogCommand),
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct LogCommand {
|
||||
line: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct LogLine<'a> {
|
||||
version: &'a str,
|
||||
level: i64,
|
||||
message: Cow<'a, str>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let args = Args::parse();
|
||||
|
||||
match args {
|
||||
Args::Log(LogCommand { line }) => {
|
||||
let parsed_line: LogLine = serde_json::from_str(&line).unwrap();
|
||||
let major = parsed_line.version.split(".").next().unwrap();
|
||||
let major = major.parse().unwrap();
|
||||
let statements = get_statements("server", major);
|
||||
let matcher = Matcher::new(statements);
|
||||
let index = matcher.match_log(parsed_line.level.into(), parsed_line.message.as_ref());
|
||||
if let Some(index) = index {
|
||||
let statement = &statements[index];
|
||||
println!("match found: {} line {}", statement.path, statement.line);
|
||||
} else {
|
||||
eprintln!("No match found");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
129
src/matcher.rs
Normal file
129
src/matcher.rs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
use cloud_log_analyser_data::{LogLevel, LoggingStatement};
|
||||
use regex::{escape, Regex, RegexBuilder};
|
||||
|
||||
pub struct LogMatch {
|
||||
level: LogLevel,
|
||||
pattern: Regex,
|
||||
pattern_length: usize,
|
||||
}
|
||||
|
||||
impl LogMatch {
|
||||
pub fn new(statement: &LoggingStatement) -> LogMatch {
|
||||
LogMatch {
|
||||
level: statement.level,
|
||||
pattern: build_pattern(statement.message_parts),
|
||||
pattern_length: statement.message_parts.iter().copied().map(str::len).sum(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Matcher {
|
||||
matches: Vec<LogMatch>,
|
||||
}
|
||||
|
||||
impl Matcher {
|
||||
pub fn new(statements: &[LoggingStatement]) -> Matcher {
|
||||
Matcher {
|
||||
matches: statements.iter().map(LogMatch::new).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_log(&self, level: LogLevel, message: &str) -> Option<usize> {
|
||||
let mut best_match = None;
|
||||
let mut best_length = 0;
|
||||
|
||||
for (i, log_match) in self.matches.iter().enumerate() {
|
||||
if (log_match.level == level
|
||||
|| log_match.level == LogLevel::Exception
|
||||
|| level == LogLevel::Unknown)
|
||||
&& log_match.pattern.is_match(message)
|
||||
&& log_match.pattern_length > best_length
|
||||
{
|
||||
best_match = Some(i);
|
||||
best_length = log_match.pattern_length;
|
||||
}
|
||||
}
|
||||
|
||||
best_match
|
||||
}
|
||||
}
|
||||
|
||||
fn build_pattern<'a>(parts: &[&str]) -> Regex {
|
||||
let mut pattern = String::with_capacity(128);
|
||||
for part in parts {
|
||||
pattern.push_str(&escape(part));
|
||||
pattern.push_str("(.*)");
|
||||
}
|
||||
RegexBuilder::new(&pattern)
|
||||
.build()
|
||||
.expect("Failed to build regex")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_pattern() {
|
||||
let regex = build_pattern(["foobar", "asd"]);
|
||||
assert!(regex.is_match("foobar with asd and more"));
|
||||
assert!(regex.is_match("foobarasd"));
|
||||
assert!(!regex.is_match("fooasd"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matcher() {
|
||||
let statements = &[
|
||||
LoggingStatement {
|
||||
line: 68,
|
||||
level: LogLevel::Exception,
|
||||
path: "foo",
|
||||
message_parts: vec!["Not allowed to rename a shared album".into()],
|
||||
},
|
||||
LoggingStatement {
|
||||
line: 69,
|
||||
level: LogLevel::Error,
|
||||
path: "bar",
|
||||
message_parts: vec![
|
||||
"You are not allowed to edit link shares that you don".into(),
|
||||
"'".into(),
|
||||
"t own".into(),
|
||||
],
|
||||
},
|
||||
LoggingStatement {
|
||||
line: 69,
|
||||
level: LogLevel::Error,
|
||||
path: "asd",
|
||||
message_parts: vec![
|
||||
"Unsupported query value for mimetype: ".into(),
|
||||
", only values in the format \"mime/type\" or \"mime/%\" are supported".into(),
|
||||
],
|
||||
},
|
||||
LoggingStatement {
|
||||
line: 68,
|
||||
level: LogLevel::Exception,
|
||||
path: "short",
|
||||
message_parts: vec!["Not allowed to rename".into()],
|
||||
},
|
||||
];
|
||||
let matcher = Matcher::new(statements);
|
||||
assert_eq!(
|
||||
Some(0),
|
||||
matcher.match_log(LogLevel::Error, "Not allowed to rename a shared album")
|
||||
);
|
||||
assert_eq!(
|
||||
Some(3),
|
||||
matcher.match_log(LogLevel::Error, "Not allowed to rename an album")
|
||||
);
|
||||
assert_eq!(
|
||||
Some(1),
|
||||
matcher.match_log(
|
||||
LogLevel::Error,
|
||||
"You are not allowed to edit link shares that you don't own"
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
None,
|
||||
matcher.match_log(
|
||||
LogLevel::Info,
|
||||
"You are not allowed to edit link shares that you don't own"
|
||||
)
|
||||
);
|
||||
assert_eq!(Some(2), matcher.match_log(LogLevel::Error, "Unsupported query value for mimetype: %/text, only values in the format \"mime/type\" or \"mime/%\" are supported"));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue