support reading logs from csv files
All checks were successful
CI / build (push) Successful in 24s
CI / checks (push) Successful in 27s
CI / build-nixpkgs (push) Successful in 16s

This commit is contained in:
Robin Appelman 2025-06-03 15:57:07 +02:00
commit e2474640d6
3 changed files with 41 additions and 3 deletions

24
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "adler2" name = "adler2"
@ -429,6 +429,27 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "csv"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.10" version = "0.20.10"
@ -883,6 +904,7 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bzip2-rs", "bzip2-rs",
"clap", "clap",
"csv",
"derive_more", "derive_more",
"dialoguer", "dialoguer",
"flate2", "flate2",

View file

@ -31,6 +31,7 @@ ruzstd = "0.8.0"
sevenz-rust2 = "0.13.2" sevenz-rust2 = "0.13.2"
dialoguer = "0.11.0" dialoguer = "0.11.0"
indicatif = { version = "0.17.11", features = ["rayon"] } indicatif = { version = "0.17.11", features = ["rayon"] }
csv = "1.3.1"
[target.'cfg(target_env = "musl")'.dependencies] [target.'cfg(target_env = "musl")'.dependencies]
tikv-jemallocator = "0.6.0" tikv-jemallocator = "0.6.0"

View file

@ -4,12 +4,13 @@ pub mod logline;
use crate::error::ReadError; use crate::error::ReadError;
use crate::logfile::archive::{Archive, ArchiveEntry, SevenZipArchive, TarArchive, ZipArchive}; use crate::logfile::archive::{Archive, ArchiveEntry, SevenZipArchive, TarArchive, ZipArchive};
use bzip2_rs::DecoderReader; use bzip2_rs::DecoderReader;
use csv::Reader;
use dialoguer::Select; use dialoguer::Select;
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
pub use logline::{LineNumber, LogLine}; pub use logline::{LineNumber, LogLine};
use ruzstd::decoding::StreamingDecoder; use ruzstd::decoding::StreamingDecoder;
use serde::Deserialize; use serde::Deserialize;
use std::io::{Cursor, Read, Seek}; use std::io::{BufReader, Cursor, Read, Seek};
use xz2::read::XzDecoder; use xz2::read::XzDecoder;
#[derive(Debug, Deserialize, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] #[derive(Debug, Deserialize, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
@ -55,7 +56,21 @@ impl LogFile {
return Self::open_no_seek(path, decoder); return Self::open_no_seek(path, decoder);
} }
Self::open_no_seek(path, Box::new(file)) if path.ends_with(".csv") {
let mut reader = Reader::from_reader(BufReader::new(file));
let mut content = String::with_capacity(8192);
for result in reader.records().filter_map(Result::ok) {
for field in result.iter() {
if field.starts_with('{') && field.ends_with('}') && field.contains("reqId") {
content.push_str(field);
content.push('\n');
}
}
}
Ok(LogFile { content })
} else {
Self::open_no_seek(path, Box::new(file))
}
} }
fn open_no_seek<R: Read>(path: &str, mut file: R) -> Result<LogFile, ReadError> { fn open_no_seek<R: Read>(path: &str, mut file: R) -> Result<LogFile, ReadError> {