more logging
This commit is contained in:
parent
6643c471a0
commit
63af6a613d
1 changed files with 41 additions and 9 deletions
50
src/main.rs
50
src/main.rs
|
@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
const RESTIC_ALARM_BUCKET: &str = "restic-alarm-state";
|
const RESTIC_ALARM_BUCKET: &str = "restic-alarm-state";
|
||||||
const RESTIC_ALARM_STATE_FILE: &str = "state.toml";
|
const RESTIC_ALARM_STATE_FILE: &str = "state.toml";
|
||||||
|
@ -51,6 +52,30 @@ struct RepoConfig {
|
||||||
alert_duration: u64,
|
alert_duration: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AlertStatus {
|
||||||
|
alert: bool,
|
||||||
|
inactivity: Duration,
|
||||||
|
last_alert: Option<Duration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for AlertStatus {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let days = |d: Duration| {
|
||||||
|
d.as_secs() / (3600 * 24)
|
||||||
|
};
|
||||||
|
let hours = |d: Duration| {
|
||||||
|
(d.as_secs() / 3600) % 24
|
||||||
|
};
|
||||||
|
write!(f, "{}: inactivity: {} days, {} hours, last_alert: {}",
|
||||||
|
(if self.alert { "ALERT" } else { "no alert" }),
|
||||||
|
days(self.inactivity), hours(self.inactivity),
|
||||||
|
match self.last_alert {
|
||||||
|
None => "none".to_owned(),
|
||||||
|
Some(d) => format!("{} days, {} hours", days(d), hours(d))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn is_alert_needed(
|
fn is_alert_needed(
|
||||||
cfg: &RepoConfig,
|
cfg: &RepoConfig,
|
||||||
inactive_for: Duration,
|
inactive_for: Duration,
|
||||||
|
@ -200,17 +225,21 @@ async fn repo_last_snapshot(client: &s3::Client, repo: &str) -> eyre::Result<Opt
|
||||||
// (e.g. if it fails to parse).
|
// (e.g. if it fails to parse).
|
||||||
// So the error must not be propagated to the toplevel, which would abort the
|
// So the error must not be propagated to the toplevel, which would abort the
|
||||||
// alert for remaining repositories; it should instead just be reported/logged.
|
// alert for remaining repositories; it should instead just be reported/logged.
|
||||||
async fn check_repo(client: &s3::Client, state: &mut State, repo: &str) -> eyre::Result<()> {
|
async fn check_repo(client: &s3::Client, state: &mut State, repo: &str) -> eyre::Result<Option<AlertStatus>> {
|
||||||
let config = read_repo_config(client, repo).await?;
|
let config = read_repo_config(client, repo).await?;
|
||||||
if let Some(last_snapshot) = repo_last_snapshot(client, repo).await? {
|
if let Some(inactivity) = repo_last_snapshot(client, repo).await? {
|
||||||
if is_alert_needed(&config, last_snapshot, state.last_alert(repo)) {
|
let last_alert = state.last_alert(repo);
|
||||||
|
let alert = is_alert_needed(&config, inactivity, last_alert);
|
||||||
|
if alert {
|
||||||
println!("Sending alert to {} about bucket {}", config.email, repo);
|
println!("Sending alert to {} about bucket {}", config.email, repo);
|
||||||
send_email(&config.email, repo, last_snapshot).await?;
|
send_email(&config.email, repo, inactivity).await?;
|
||||||
}
|
}
|
||||||
state.update_last_alert(repo);
|
state.update_last_alert(repo);
|
||||||
write_state(client, state).await?;
|
write_state(client, state).await?;
|
||||||
|
Ok(Some(AlertStatus { alert, inactivity, last_alert }))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[::tokio::main]
|
#[::tokio::main]
|
||||||
|
@ -224,17 +253,20 @@ async fn main() -> eyre::Result<()> {
|
||||||
let client = aws_sdk_s3::Client::from_conf(config);
|
let client = aws_sdk_s3::Client::from_conf(config);
|
||||||
|
|
||||||
let repos = to_watch(&client).await?;
|
let repos = to_watch(&client).await?;
|
||||||
println!("Watching repos:");
|
println!("Watching {} repos", repos.len());
|
||||||
for r in repos.iter() {
|
for r in repos.iter() {
|
||||||
println!("{}", r);
|
println!("- {}", r);
|
||||||
}
|
}
|
||||||
let mut state = read_state(&client).await?;
|
let mut state = read_state(&client).await?;
|
||||||
println!("Current state: {:?}", &state);
|
println!("Current state: {:?}", &state);
|
||||||
|
|
||||||
for repo in repos {
|
for repo in repos {
|
||||||
match check_repo(&client, &mut state, &repo).await {
|
match check_repo(&client, &mut state, &repo).await {
|
||||||
Ok(()) => {
|
Ok(None) => {
|
||||||
println!("{}: OK", &repo);
|
println!("{}: no snapshot, skipping", &repo)
|
||||||
|
},
|
||||||
|
Ok(Some(status)) => {
|
||||||
|
println!("{}: {}", &repo, status);
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// is this the best way to log the error?
|
// is this the best way to log the error?
|
||||||
|
|
Loading…
Reference in a new issue