set envvars
This commit is contained in:
commit
3963fc50c3
9 changed files with 3248 additions and 0 deletions
163
src/tui/reader.rs
Normal file
163
src/tui/reader.rs
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io::{self, BufRead, BufReader},
|
||||
mem,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
use crate::tui::{
|
||||
filter::{Filter, FilterKind},
|
||||
model::{LogEntry, RawLogEntry},
|
||||
};
|
||||
|
||||
pub struct LogfileReader {
|
||||
pub path: PathBuf,
|
||||
file: BufReader<File>,
|
||||
|
||||
entries: Vec<Rc<LogEntry>>,
|
||||
filters: Vec<Rc<Filter>>,
|
||||
}
|
||||
|
||||
impl LogfileReader {
|
||||
pub fn new(p: &Path) -> io::Result<Self> {
|
||||
Ok(Self {
|
||||
file: BufReader::new(File::open(p)?),
|
||||
path: p.to_path_buf(),
|
||||
entries: Vec::new(),
|
||||
filters: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_filter(&mut self, filter: Filter) {
|
||||
self.filters.push(Rc::new(filter));
|
||||
}
|
||||
|
||||
fn next_line(&mut self) -> Option<String> {
|
||||
let mut res = String::new();
|
||||
match self.file.read_line(&mut res) {
|
||||
Err(e) => {
|
||||
eprintln!("error: {e:?}");
|
||||
None
|
||||
}
|
||||
Ok(0) => None,
|
||||
Ok(_) => Some(res),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_raw_entry(&mut self) -> Option<RawLogEntry> {
|
||||
let line = self.next_line()?;
|
||||
match serde_json::from_str(&line) {
|
||||
Ok(i) => Some(i),
|
||||
Err(e) => {
|
||||
eprintln!("deserializing: {e:?} in {line}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next_entry(&mut self) -> Option<Rc<LogEntry>> {
|
||||
let mut stack = Vec::<(RawLogEntry, Vec<Rc<LogEntry>>)>::new();
|
||||
let mut curr = Vec::<Rc<LogEntry>>::new();
|
||||
|
||||
loop {
|
||||
let entry = self.next_raw_entry()?;
|
||||
|
||||
let new_entry = Rc::new(match entry.fields.message() {
|
||||
Some("enter") => {
|
||||
stack.push((entry, mem::take(&mut curr)));
|
||||
continue;
|
||||
}
|
||||
Some("exit") => {
|
||||
// TODO: does it match?
|
||||
let Some((enter, prev)) = stack.pop() else {
|
||||
panic!("exit before entry");
|
||||
};
|
||||
let sub_entries = mem::replace(&mut curr, prev);
|
||||
LogEntry::Sub {
|
||||
enter: enter,
|
||||
sub_entries,
|
||||
exit: entry,
|
||||
count_sub: OnceLock::new(),
|
||||
}
|
||||
}
|
||||
_ => LogEntry::Single { raw: entry },
|
||||
});
|
||||
|
||||
if stack.is_empty() {
|
||||
return Some(new_entry);
|
||||
} else {
|
||||
curr.push(new_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_from(&mut self, start: usize) -> FilterAdapter<EntryIterator<'_>> {
|
||||
FilterAdapter {
|
||||
filters: self.filters.clone(),
|
||||
inner: EntryIterator {
|
||||
curr: start,
|
||||
reader: self,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn add_next_entry(&mut self) -> Option<()> {
|
||||
let entry = self.next_entry()?;
|
||||
self.entries.push(entry);
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EntryIterator<'a> {
|
||||
curr: usize,
|
||||
reader: &'a mut LogfileReader,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for EntryIterator<'a> {
|
||||
type Item = Rc<LogEntry>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while self.reader.entries.len() <= self.curr {
|
||||
self.reader.add_next_entry()?;
|
||||
}
|
||||
|
||||
let res = Rc::clone(&self.reader.entries[self.curr]);
|
||||
self.curr += 1;
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FilterAdapter<I> {
|
||||
filters: Vec<Rc<Filter>>,
|
||||
inner: I,
|
||||
}
|
||||
|
||||
impl<I: IntoIterator> FilterAdapter<I> {
|
||||
pub fn new(file: &LogfileReader, inner: I) -> FilterAdapter<I::IntoIter> {
|
||||
Self {
|
||||
filters: file.filters.clone(),
|
||||
inner: inner.into_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for FilterAdapter<I> {
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
'next_entry: loop {
|
||||
let res = self.inner.next()?;
|
||||
|
||||
for filter in &self.reader.filters {
|
||||
if let FilterKind::Remove = filter.kind
|
||||
&& filter.matcher.matches(&res)
|
||||
{
|
||||
continue 'next_entry;
|
||||
}
|
||||
}
|
||||
break Some(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue