Skip to content

Commit 2292948

Browse files
committed
feat(analyze): short outages in general view, add -o option to reader
1 parent f5e2817 commit 2292948

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

src/analyze.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,31 @@ impl<'check> Outage<'check> {
9696
}
9797
}
9898

99+
pub fn short_report(&self) -> Result<String, std::fmt::Error> {
100+
let mut buf: String = String::new();
101+
if self.end.is_some() {
102+
write!(
103+
&mut buf,
104+
"From {}",
105+
fmt_timestamp(self.start.timestamp_parsed()),
106+
)?;
107+
write!(
108+
&mut buf,
109+
" To {}",
110+
fmt_timestamp(self.end.unwrap().timestamp_parsed()),
111+
)?;
112+
} else {
113+
write!(
114+
&mut buf,
115+
"From {}",
116+
fmt_timestamp(self.start.timestamp_parsed()),
117+
)?;
118+
write!(&mut buf, " To {}", "(None)")?;
119+
}
120+
write!(&mut buf, ", Total {}", self.len())?;
121+
Ok(buf)
122+
}
123+
99124
/// Returns the length of this [`Outage`].
100125
pub fn len(&self) -> usize {
101126
self.all.len()
@@ -243,14 +268,42 @@ fn key_value_write(
243268
/// Groups consecutive failed checks by check type and creates
244269
/// Outage records for reporting.
245270
fn outages(store: &Store, f: &mut String) -> Result<(), AnalysisError> {
246-
let all_checks: Vec<&Check> = store.checks().iter().collect();
247-
let fails_exist = !all_checks.iter().all(|c| c.is_success());
248-
if !fails_exist || all_checks.is_empty() {
271+
let all: Vec<&Check> = store.checks().iter().collect();
272+
let fails_exist = !all.iter().all(|c| c.is_success());
273+
if !fails_exist || all.is_empty() {
274+
writeln!(f, "None\n")?;
275+
return Ok(());
276+
}
277+
278+
let fail_groups = fail_groups(&all);
279+
for (outage_idx, group) in fail_groups.into_iter().rev().enumerate() {
280+
if group.is_empty() {
281+
error!("empty outage group");
282+
continue;
283+
}
284+
let outage = Outage::new(group.first().unwrap(), group.last().copied(), &group);
285+
writeln!(f, "{outage_idx}:\t{}", &outage.short_report()?)?;
286+
if outage_idx > 10 {
287+
writeln!(f, "showing only the 10 latest outages")?;
288+
break;
289+
}
290+
}
291+
writeln!(f)?;
292+
Ok(())
293+
}
294+
295+
/// Analyzes and formats outage information from the store.
296+
///
297+
/// Groups consecutive failed checks by check type and creates
298+
/// Outage records for reporting. This is the more detailed version of [outages]
299+
pub fn outages_detailed(all: &[&Check], f: &mut String) -> Result<(), AnalysisError> {
300+
let fails_exist = !all.iter().all(|c| c.is_success());
301+
if !fails_exist || all.is_empty() {
249302
writeln!(f, "None\n")?;
250303
return Ok(());
251304
}
252305

253-
let fail_groups = fail_groups(&all_checks);
306+
let fail_groups = fail_groups(all);
254307
for (outage_idx, group) in fail_groups.into_iter().enumerate() {
255308
if group.is_empty() {
256309
error!("empty outage group");

src/bins/netpulse.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//! Use the `--help` flag for more information about the usage.
1313
1414
use getopts::Options;
15-
use netpulse::analyze;
15+
use netpulse::analyze::{self, outages_detailed};
1616
use netpulse::common::{init_logging, print_usage, setup_panic_handler};
1717
use netpulse::errors::RunError;
1818
use netpulse::records::{display_group, Check};
@@ -30,6 +30,7 @@ fn main() {
3030
opts.optflag("V", "version", "print the version");
3131
opts.optflag("t", "test", "test run all checks");
3232
opts.optflag("d", "dump", "print out all checks");
33+
opts.optflag("o", "outages", "print out all outages");
3334
opts.optflag(
3435
"r",
3536
"rewrite",
@@ -63,6 +64,11 @@ fn main() {
6364
error!("{e}");
6465
std::process::exit(1)
6566
}
67+
} else if matches.opt_present("outages") {
68+
if let Err(e) = print_outages(None) {
69+
error!("{e}");
70+
std::process::exit(1)
71+
}
6672
} else if matches.opt_present("rewrite") {
6773
if let Err(e) = rewrite() {
6874
error!("{e}");
@@ -84,6 +90,22 @@ fn test_checks() -> Result<(), RunError> {
8490
Ok(())
8591
}
8692

93+
fn print_outages(latest: Option<usize>) -> Result<(), RunError> {
94+
let store = Store::load(true)?;
95+
let mut buf = String::new();
96+
let ref_checks: Vec<&Check> = if let Some(limit) = latest {
97+
store.checks().iter().rev().take(limit).collect()
98+
} else {
99+
store.checks().iter().collect()
100+
};
101+
if let Err(e) = outages_detailed(&ref_checks, &mut buf) {
102+
eprintln!("{e}");
103+
std::process::exit(1);
104+
}
105+
println!("{buf}");
106+
Ok(())
107+
}
108+
87109
fn dump(failed_only: bool) -> Result<(), RunError> {
88110
let store = Store::load(true)?;
89111
let mut buf = String::new();

0 commit comments

Comments
 (0)