77 lines
2.3 KiB
Rust
77 lines
2.3 KiB
Rust
|
use std::collections::HashMap;
|
||
|
use std::error::Error;
|
||
|
use std::fs::File;
|
||
|
use std::io::Read;
|
||
|
use std::time::{Duration, UNIX_EPOCH};
|
||
|
|
||
|
fn parse(
|
||
|
file: File,
|
||
|
) -> Result<HashMap<String, HashMap<std::time::SystemTime, f64>>, Box<dyn Error>> {
|
||
|
let mut file = file;
|
||
|
let mut contents = String::new();
|
||
|
file.read_to_string(&mut contents)?;
|
||
|
|
||
|
let mut metrics: HashMap<String, HashMap<std::time::SystemTime, Vec<f64>>> = HashMap::new();
|
||
|
|
||
|
for line in contents.lines() {
|
||
|
let re = regex::Regex::new(r"(\d+) (\w+) (\d+)").unwrap();
|
||
|
if let Some(caps) = re.captures(line) {
|
||
|
let timestamp_raw = &caps[1];
|
||
|
let metric_name = &caps[2];
|
||
|
let metric_value_raw = &caps[3];
|
||
|
|
||
|
let timestamp = timestamp_raw.parse::<i64>().unwrap();
|
||
|
let metric_value = metric_value_raw.parse::<f64>().unwrap();
|
||
|
|
||
|
if !metrics.contains_key(metric_name) {
|
||
|
metrics.insert(metric_name.to_string(), HashMap::new());
|
||
|
}
|
||
|
|
||
|
let minute = UNIX_EPOCH + Duration::from_secs((timestamp - (timestamp % 60)) as u64);
|
||
|
metrics
|
||
|
.get_mut(metric_name)
|
||
|
.unwrap()
|
||
|
.insert(minute, vec![metric_value]);
|
||
|
} else {
|
||
|
println!("invalid line");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let mut aggregated_metrics: HashMap<String, HashMap<std::time::SystemTime, f64>> =
|
||
|
HashMap::new();
|
||
|
|
||
|
for (metric_name, time_val_list) in metrics {
|
||
|
aggregated_metrics.insert(metric_name.clone(), HashMap::new());
|
||
|
|
||
|
for (time, values) in time_val_list {
|
||
|
let mut sum = 0.0;
|
||
|
for v in values.iter() {
|
||
|
sum += *v
|
||
|
}
|
||
|
let average = sum / values.len() as f64;
|
||
|
|
||
|
aggregated_metrics
|
||
|
.get_mut(&metric_name)
|
||
|
.unwrap()
|
||
|
.insert(time, average);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(aggregated_metrics)
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let file = File::open("input.txt").expect("Unable to open file");
|
||
|
let metrics = parse(file).expect("Unable to parse file");
|
||
|
for (metric_name, time_val) in metrics {
|
||
|
for (time, value) in time_val {
|
||
|
println!(
|
||
|
"{} {:?} {:.2}",
|
||
|
metric_name,
|
||
|
chrono::DateTime::<chrono::Utc>::from(time),
|
||
|
value
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|