Skip to content

Commit 7762bda

Browse files
committed
fix(analyze): outages were not displayed #34
1 parent 44de68a commit 7762bda

File tree

2 files changed

+61
-39
lines changed

2 files changed

+61
-39
lines changed

src/analyze.rs

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@
3131
3232
use chrono::{DateTime, Local};
3333
use deepsize::DeepSizeOf;
34+
use tracing::error;
3435

3536
use crate::errors::AnalysisError;
36-
use crate::records::{Check, CheckType, IpType};
37+
use crate::records::{display_group, indented_check, Check, CheckType, IpType};
3738
use crate::store::Store;
3839

3940
use std::fmt::{Display, Write};
@@ -85,38 +86,57 @@ impl<'check> Outage<'check> {
8586
) -> Self {
8687
Self {
8788
start,
88-
end,
89+
end: if Some(start) == end { None } else { end },
8990
all: all_checks.to_vec(),
9091
}
9192
}
93+
94+
/// Returns the length of this [`Outage`].
95+
pub fn len(&self) -> usize {
96+
self.all.len()
97+
}
98+
99+
/// Returns true if this [`Outage`] is empty.
100+
#[must_use]
101+
pub fn is_empty(&self) -> bool {
102+
self.len() == 0
103+
}
92104
}
93105

94106
impl Display for Outage<'_> {
95107
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108+
let mut buf: String = String::new();
96109
if self.end.is_some() {
97-
writeln!(
98-
f,
99-
"From {} To {}",
100-
fmt_timestamp(self.start.timestamp_parsed()),
101-
fmt_timestamp(self.end.unwrap().timestamp_parsed())
110+
key_value_write(
111+
&mut buf,
112+
"From",
113+
fmt_timestamp(self.end.unwrap().timestamp_parsed()),
114+
)?;
115+
key_value_write(
116+
&mut buf,
117+
"To",
118+
fmt_timestamp(self.end.unwrap().timestamp_parsed()),
102119
)?;
103120
} else {
104-
writeln!(
105-
f,
106-
"From {} STILL ONGOING",
121+
key_value_write(
122+
&mut buf,
123+
"From",
107124
fmt_timestamp(self.start.timestamp_parsed()),
108125
)?;
126+
key_value_write(&mut buf, "To", "(None)")?;
109127
}
110-
writeln!(f, "Checks: {}", self.all.len())?;
111-
writeln!(
112-
f,
113-
"Type: {}",
114-
self.start.calc_type().unwrap_or(CheckType::Unknown)
115-
)?;
128+
key_value_write(&mut buf, "Total", self.len())?;
129+
writeln!(buf, "\nDetails")?;
130+
display_group(&self.all, &mut buf)?;
131+
write!(f, "{buf}")?;
116132
Ok(())
117133
}
118134
}
119135

136+
fn more_indent(buf: &str) -> String {
137+
format!("\t{}", buf.to_string().replace("\n", "\n\t"))
138+
}
139+
120140
/// Generate a comprehensive analysis report for the given store.
121141
///
122142
/// The report includes:
@@ -205,44 +225,42 @@ fn key_value_write(
205225
writeln!(f, "{:<24}: {}", title, content)
206226
}
207227

228+
/// Writes a key-value pair to the report in aligned columns.
229+
///
230+
/// Format: `<key>: <value>`
231+
fn key_value_write_indented(
232+
f: &mut String,
233+
title: &str,
234+
content: impl Display,
235+
) -> Result<(), std::fmt::Error> {
236+
writeln!(f, " {:<16}: {}", title, content)
237+
}
238+
208239
/// Analyzes and formats outage information from the store.
209240
///
210241
/// Groups consecutive failed checks by check type and creates
211242
/// Outage records for reporting.
212243
fn outages(store: &Store, f: &mut String) -> Result<(), AnalysisError> {
213244
let all_checks: Vec<&Check> = store.checks().iter().collect();
214-
let mut outages: Vec<Outage> = Vec::new();
215-
let fails_exist = all_checks
216-
.iter()
217-
.fold(true, |fails_exist, c| fails_exist & !c.is_success());
245+
let fails_exist = !all_checks.iter().all(|c| c.is_success());
218246
if !fails_exist || all_checks.is_empty() {
219247
writeln!(f, "None\n")?;
220248
return Ok(());
221249
}
222250

223-
for check_type in CheckType::all() {
224-
let checks: Vec<&&Check> = all_checks
225-
.iter()
226-
.filter(|c| c.calc_type().unwrap_or(CheckType::Unknown) == *check_type)
227-
.collect();
251+
let failed_checks: Vec<&&Check> = all_checks.iter().filter(|c| !c.is_success()).collect();
228252

229-
let fail_groups = fail_groups(&checks);
230-
for group in fail_groups {
231-
// writeln!(f, "Group {gidx}:")?;
232-
// display_group(group, f)?;
233-
if !group.is_empty() {
234-
outages.push(Outage::new(
235-
checks.first().unwrap(),
236-
Some(checks.last().unwrap()),
237-
&group,
238-
));
239-
}
253+
let fail_groups = fail_groups(&failed_checks);
254+
for (outage_idx, group) in fail_groups.into_iter().enumerate() {
255+
if group.is_empty() {
256+
error!("empty outage group");
257+
continue;
240258
}
259+
let outage = Outage::new(group.first().unwrap(), group.last().copied(), &group);
260+
writeln!(f, "{outage_idx}:\n{}", more_indent(&outage.to_string()))?;
241261
}
262+
writeln!(f)?;
242263

243-
for outage in outages {
244-
writeln!(f, "{outage}")?;
245-
}
246264
Ok(())
247265
}
248266

src/records.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,10 @@ pub fn display_group(group: &[&Check], f: &mut String) -> Result<(), std::fmt::E
462462
Ok(())
463463
}
464464

465+
pub(crate) fn indented_check(buf: &mut String, check: &Check) -> Result<(), std::fmt::Error> {
466+
writeln!(buf, "\t{}", check.to_string().replace("\n", "\n\t"))
467+
}
468+
465469
#[cfg(test)]
466470
mod test {
467471
use crate::TIMEOUT_MS;

0 commit comments

Comments
 (0)