log file stats

This commit is contained in:
Robin Appelman 2024-07-21 01:50:55 +02:00
commit 19c1c57acc
2 changed files with 55 additions and 0 deletions

View file

@ -11,3 +11,6 @@ regex = "1.10.5"
log = "0.4.22" log = "0.4.22"
clap = { version = "=4.1.3", features = ["derive"] } clap = { version = "=4.1.3", features = ["derive"] }
cloud-log-analyser-data = { version = "0.1.0", path = "./data" } cloud-log-analyser-data = { version = "0.1.0", path = "./data" }
[profile.dev.package."*"]
opt-level = 3

View file

@ -3,12 +3,18 @@ use clap::Parser;
use cloud_log_analyser_data::get_statements; use cloud_log_analyser_data::get_statements;
use serde::Deserialize; use serde::Deserialize;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::iter::once;
use std::ops::AddAssign;
mod matcher; mod matcher;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
enum Args { enum Args {
Log(LogCommand), Log(LogCommand),
File(FileCommand),
} }
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -16,6 +22,11 @@ struct LogCommand {
line: String, line: String,
} }
#[derive(Debug, Parser)]
struct FileCommand {
file: String,
}
#[derive(Deserialize)] #[derive(Deserialize)]
struct LogLine<'a> { struct LogLine<'a> {
version: &'a str, version: &'a str,
@ -41,5 +52,46 @@ fn main() {
eprintln!("No match found"); eprintln!("No match found");
} }
} }
Args::File(FileCommand { file }) => {
let file = BufReader::new(File::open(file).unwrap());
let mut counts: HashMap<usize, usize> = HashMap::default();
let mut lines = file.lines().flatten();
let first = lines.next().unwrap();
let first_parsed: LogLine = serde_json::from_str(&first).unwrap();
let major = first_parsed.version.split(".").next().unwrap();
let major = major.parse().unwrap();
let statements = get_statements("server", major);
let matcher = Matcher::new(statements);
let lines = once(first).chain(lines);
let mut error_count = 0;
for line in lines {
if line.starts_with('{') {
let parsed = match serde_json::from_str::<LogLine>(&line) {
Ok(parsed) => parsed,
Err(_) => {
error_count += 1;
continue;
}
};
if let Some(index) =
matcher.match_log(parsed.level.into(), parsed.message.as_ref())
{
counts.entry(index).or_default().add_assign(1);
}
}
}
let mut counts: Vec<(_, _)> = counts.into_iter().collect();
counts.sort_by_key(|(_, count)| *count);
counts.reverse();
for (index, count) in counts {
let statement = &statements[index];
println!("{} line {}: {}", statement.path, statement.line, count);
}
if error_count > 0 {
eprintln!("{error_count} lines failed to parse as valid log json");
}
}
} }
} }