@@ -115,7 +115,7 @@ impl Display for Outage<'_> {
115
115
key_value_write (
116
116
& mut buf,
117
117
"From" ,
118
- fmt_timestamp ( self . end . unwrap ( ) . timestamp_parsed ( ) ) ,
118
+ fmt_timestamp ( self . start . timestamp_parsed ( ) ) ,
119
119
) ?;
120
120
key_value_write (
121
121
& mut buf,
@@ -131,8 +131,16 @@ impl Display for Outage<'_> {
131
131
key_value_write ( & mut buf, "To" , "(None)" ) ?;
132
132
}
133
133
key_value_write ( & mut buf, "Total" , self . len ( ) ) ?;
134
- writeln ! ( buf, "\n Details" ) ?;
135
- display_group ( & self . all , & mut buf) ?;
134
+ writeln ! ( buf, "\n First\n {}" , self . start) ?;
135
+ writeln ! (
136
+ buf,
137
+ "\n Last\n {}" ,
138
+ if let Some ( c) = self . end {
139
+ c. to_string( )
140
+ } else {
141
+ "(None)" . to_string( )
142
+ }
143
+ ) ?;
136
144
write ! ( f, "{buf}" ) ?;
137
145
Ok ( ( ) )
138
146
}
@@ -230,17 +238,6 @@ fn key_value_write(
230
238
writeln ! ( f, "{:<24}: {}" , title, content)
231
239
}
232
240
233
- /// Writes a key-value pair to the report in aligned columns.
234
- ///
235
- /// Format: `<key>: <value>`
236
- fn key_value_write_indented (
237
- f : & mut String ,
238
- title : & str ,
239
- content : impl Display ,
240
- ) -> Result < ( ) , std:: fmt:: Error > {
241
- writeln ! ( f, " {:<16}: {}" , title, content)
242
- }
243
-
244
241
/// Analyzes and formats outage information from the store.
245
242
///
246
243
/// Groups consecutive failed checks by check type and creates
@@ -253,9 +250,7 @@ fn outages(store: &Store, f: &mut String) -> Result<(), AnalysisError> {
253
250
return Ok ( ( ) ) ;
254
251
}
255
252
256
- let failed_checks: Vec < & & Check > = all_checks. iter ( ) . filter ( |c| !c. is_success ( ) ) . collect ( ) ;
257
-
258
- let fail_groups = fail_groups ( & failed_checks) ;
253
+ let fail_groups = fail_groups ( & all_checks) ;
259
254
for ( outage_idx, group) in fail_groups. into_iter ( ) . enumerate ( ) {
260
255
if group. is_empty ( ) {
261
256
error ! ( "empty outage group" ) ;
@@ -275,32 +270,44 @@ fn outages(store: &Store, f: &mut String) -> Result<(), AnalysisError> {
275
270
/// - Checks are consecutive by index
276
271
/// - All checks in group are failures
277
272
/// - Gap between groups is > 1 check
278
- fn fail_groups < ' check > ( checks : & [ & & ' check Check ] ) -> Vec < Vec < & ' check Check > > {
273
+ fn fail_groups < ' check > ( checks : & [ & ' check Check ] ) -> Vec < Vec < & ' check Check > > {
279
274
let failed_idxs: Vec < usize > = checks
280
275
. iter ( )
281
276
. enumerate ( )
282
277
. filter ( |( _idx, c) | !c. is_success ( ) )
283
278
. map ( |( idx, _c) | idx)
284
279
. collect ( ) ;
280
+
285
281
if failed_idxs. is_empty ( ) {
286
282
return Vec :: new ( ) ;
287
283
}
284
+
288
285
let mut groups: Vec < Vec < & Check > > = Vec :: new ( ) ;
286
+ let mut current_group: Vec < & Check > = Vec :: new ( ) ;
289
287
290
- let mut first = failed_idxs[ 0 ] ;
291
- let mut last = first;
292
- for idx in failed_idxs {
293
- if idx == last + 1 {
294
- last = idx;
288
+ // Start with the first index
289
+ let mut last_idx = failed_idxs[ 0 ] ;
290
+ current_group. push ( checks[ last_idx] ) ;
291
+
292
+ // Process remaining indices
293
+ for & idx in failed_idxs. iter ( ) . skip ( 1 ) {
294
+ if idx == last_idx + 1 {
295
+ // Consecutive failure, add to current group
296
+ current_group. push ( checks[ idx] ) ;
295
297
} else {
296
- let mut group: Vec < & Check > = Vec :: new ( ) ;
297
- for check in checks. iter ( ) . take ( last + 1 ) . skip ( first) {
298
- group. push ( * check) ;
298
+ // Gap found, start new group
299
+ if !current_group. is_empty ( ) {
300
+ groups. push ( current_group) ;
301
+ current_group = Vec :: new ( ) ;
299
302
}
300
- groups. push ( group) ;
301
-
302
- first = idx;
303
+ current_group. push ( checks[ idx] ) ;
303
304
}
305
+ last_idx = idx;
306
+ }
307
+
308
+ // Don't forget to add the last group
309
+ if !current_group. is_empty ( ) {
310
+ groups. push ( current_group) ;
304
311
}
305
312
306
313
groups
0 commit comments