top + report + log --follow (issues #37 #38) - top 10 par lancements, digest markdown hebdo/mensuel, suivi du journal en direct

This commit is contained in:
2026-08-17 09:03:44 -04:00
parent f14b59e63b
commit 16926ffb00
7 changed files with 331 additions and 2 deletions
+40
View File
@@ -35,6 +35,34 @@ pub fn filter_events(
Ok(events)
}
/// Live view: print matching events as they arrive (issue #38).
fn follow_loop(app: &App, agent: Option<&str>, kinds: Option<&str>, since: Option<&str>) -> Result<i32> {
app.log.info("following the journal (Ctrl-C to stop)");
let mut seen: usize = 0;
loop {
let events = filter_events(app, agent, kinds, since, 200)?;
let mut rendered = String::new();
for e in events.iter().rev() {
rendered.push_str(&e.ts);
rendered.push(' ');
rendered.push_str(e.kind.as_str());
if let Some(a) = &e.agent {
rendered.push(' ');
rendered.push_str(a);
}
rendered.push('\n');
}
let bytes = rendered.as_bytes();
if bytes.len() > seen {
print!("{}", text_after(&rendered, seen));
use std::io::Write;
let _ = std::io::stdout().flush();
}
seen = bytes.len();
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
pub fn parse_since(s: &str) -> Result<chrono::DateTime<chrono::FixedOffset>> {
if let Ok(t) = chrono::DateTime::parse_from_rfc3339(s) {
return Ok(t);
@@ -71,13 +99,25 @@ impl From<&Event> for LogRow {
}
}
/// Chars of text after byte offset seen (UTF-8 safe).
pub fn text_after(text: &str, seen: usize) -> String {
text.char_indices()
.filter(|(i, _)| *i >= seen)
.map(|(_, c)| c)
.collect()
}
pub fn run(
app: &App,
agent: Option<&str>,
kinds: Option<&str>,
since: Option<&str>,
limit: usize,
follow: bool,
) -> Result<i32> {
if follow {
return follow_loop(app, agent, kinds, since);
}
let events = filter_events(app, agent, kinds, since, limit)?;
if app.json() {
let rows: Vec<LogRow> = events.iter().map(LogRow::from).collect();