Skip to content

Commit

Permalink
tweak: Improve OTel reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
notheotherben committed Jul 25, 2024
1 parent c42cf16 commit 9aa8c7d
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 71 deletions.
14 changes: 12 additions & 2 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ use reqwest::StatusCode;

impl convert::From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self {
if err.is_redirect() {
if err.is_connect() {
user_with_internal(
"We could not connect to the remote server to make a web request.",
"Make sure that your internet connection is working correctly and the service is not blocked by your firewall.",
err)
} else if err.is_decode() {
system_with_internal(
"We could not decode the response from the remote server.",
"This is likely due to a problem with the remote server, please try again later and report the problem to us on GitHub if the issue persists.",
err)
} else if err.is_redirect() {
user_with_internal(
"We could not complete a web request to due to a redirect loop.",
"This is likely due to a problem with the remote server, please try again later and report the problem to us on GitHub if the issue persists.",
Expand All @@ -19,7 +29,7 @@ impl convert::From<reqwest::Error> for Error {
} else {
system_with_internal(
"An internal error occurred which we could not recover from.",
"Please read the internal error below and decide if there is something you can do to fix the problem, or report it to us on GitHub.",
"Please read the error above and decide if there is something you can do to fix the problem, or report it to us on GitHub.",
err)
}
}
Expand Down
118 changes: 61 additions & 57 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use errors::Error;
use policy::BackupPolicy;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::time::Duration;
use tokio::task::JoinSet;
use tracing::Instrument;

Expand Down Expand Up @@ -57,8 +58,6 @@ pub trait BackupEntity {
}

async fn run(args: Args) -> Result<(), Error> {
telemetry::setup();

let config = config::Config::try_from(&args)?;

let github = sources::GitHubSource::from(&config);
Expand All @@ -67,70 +66,68 @@ async fn run(args: Args) -> Result<(), Error> {
let cancel = AtomicBool::new(false);

loop {
let _span = tracing::info_span!("backup.all").entered();

for policy in config.backups.iter() {
let span = tracing::info_span!("backup.policy", policy = %policy);

match github.get_repos(policy, &cancel).instrument(span).await {
Ok(repos) => {
println!("Backing up repositories for: {}", &policy);
let mut join_set: JoinSet<Result<(_, String), (_, errors::Error)>> = JoinSet::new();
for repo in repos {
if policy.filters.iter().all(|p| repo.matches(p)) {
if args.dry_run {
println!(" - {} (dry-run)", repo.full_name());
continue;
}
let next_run = config.schedule.as_ref()
.and_then(|s| s.find_next_occurrence(&chrono::Utc::now(), false).ok());

{
let _span = tracing::info_span!("backup.all").entered();

for policy in config.backups.iter() {
let policy_span = tracing::info_span!("backup.policy", policy = %policy).entered();

match github.get_repos(policy, &cancel).instrument(tracing::info_span!(parent: &policy_span, "backup.get_repos")).await {
Ok(repos) => {
println!("Backing up repositories for: {}", &policy);
let mut join_set: JoinSet<Result<(_, String), (_, errors::Error)>> = JoinSet::new();
for repo in repos {
if policy.filters.iter().all(|p| repo.matches(p)) {
if args.dry_run {
println!(" - {} (dry-run)", repo.full_name());
continue;
}

let git_backup = git_backup.clone();
let cancel = AtomicBool::new(false);
let git_backup = git_backup.clone();
let cancel = AtomicBool::new(false);

let span = tracing::info_span!("backup.repo", repo = %repo.full_name());
join_set.spawn(async move {
match git_backup.backup(&repo, &cancel) {
Ok(id) => Ok((repo, id)),
Err(e) => Err((repo, e)),
}
}.instrument(span));
let span = tracing::info_span!(parent: &policy_span, "backup.repo", repo = %repo.full_name());
join_set.spawn(async move {
match git_backup.backup(&repo, &cancel) {
Ok(id) => Ok((repo, id)),
Err(e) => Err((repo, e)),
}
}.instrument(span));
}
}
}

while let Some(fut) = join_set.join_next().await {
match fut.map_err(|e| errors::system_with_internal(
"Failed to complete a background backup task due to an internal runtime error.",
"Please report this issue to us on GitHub with details of what you were doing when it occurred.",
e))? {
Ok((repo, id)) => println!(" - {} (backup at {})", repo.full_name(), id),
Err((repo, e)) => {
println!(" - {} (backup failed)", repo.full_name());
eprintln!("{}", e)
},
while let Some(fut) = join_set.join_next().await {
match fut.map_err(|e| errors::system_with_internal(
"Failed to complete a background backup task due to an internal runtime error.",
"Please report this issue to us on GitHub with details of what you were doing when it occurred.",
e))? {
Ok((repo, id)) => println!(" - {} (backup at {})", repo.full_name(), id),
Err((repo, e)) => {
println!(" - {} (backup failed)", repo.full_name());
eprintln!("{}", e)
},
}
}
},
Err(e) => {
eprintln!("Failed to get repositories for policy '{}'", policy);
eprintln!("{}", e);
continue;
}
},
Err(e) => {
eprintln!("Failed to get repositories for policy '{}'", policy);
eprintln!("{}", e);
continue;
}

println!();
}

println!();
}

if let Some(schedule) = &config.schedule {
let now = chrono::Utc::now();
match schedule.find_next_occurrence(&now, false) {
Ok(next) => {
let wait = next - now;
println!("Next backup scheduled for: {}", next);
tokio::time::sleep(wait.to_std().unwrap()).await;
}
Err(err) => {
eprintln!("Failed to calculate the next backup time: {}", err);
break;
}
if let Some(next_run) = next_run {
println!("Next backup scheduled for: {}", next_run);

while chrono::Utc::now() < next_run && !cancel.load(std::sync::atomic::Ordering::Relaxed) {
tokio::time::sleep(Duration::from_millis(500)).await;
}
} else {
break;
Expand All @@ -143,7 +140,14 @@ async fn run(args: Args) -> Result<(), Error> {
#[tokio::main]
async fn main() {
let args = Args::parse();
if let Err(e) = run(args).await {

telemetry::setup();

let result = run(args).await;

telemetry::shutdown();

if let Err(e) = result {
eprintln!("{}", e);
std::process::exit(1);
}
Expand Down
2 changes: 1 addition & 1 deletion src/policy.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::Deserialize;
use std::fmt::{Display, Formatter};

#[derive(Debug, Deserialize)]
#[derive(Deserialize)]
pub struct BackupPolicy {
pub user: Option<String>,
pub org: Option<String>,
Expand Down
10 changes: 8 additions & 2 deletions src/sources/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct GitHubSource {

#[async_trait::async_trait]
impl RepositorySource<GitHubRepo> for GitHubSource {
#[instrument(skip(self, cancel))]
#[instrument(skip(self, cancel, policy), fields(policy = %policy), err)]
async fn get_repos(
&self,
policy: &BackupPolicy,
Expand Down Expand Up @@ -167,7 +167,7 @@ impl From<&Config> for GitHubSource {
}

#[allow(dead_code)]
#[derive(Debug, serde::Deserialize)]
#[derive(serde::Deserialize)]
pub struct GitHubRepo {
name: String,
full_name: String,
Expand All @@ -179,6 +179,12 @@ pub struct GitHubRepo {
size: u64,
}

impl std::fmt::Debug for GitHubRepo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "gh:{}", self.full_name)
}
}

impl BackupEntity for GitHubRepo {
fn backup_path(&self) -> PathBuf {
PathBuf::from(&self.full_name)
Expand Down
12 changes: 3 additions & 9 deletions src/targets/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
};

use gix::{credentials::helper::Action, progress::Discard, sec::identity::Account};
use tracing::{instrument, warn};
use tracing::instrument;

use crate::{config::Config, errors, BackupEntity, BackupTarget};

Expand All @@ -16,7 +16,6 @@ pub struct FileSystemBackupTarget {
}

impl<T: BackupEntity + std::fmt::Debug> BackupTarget<T> for FileSystemBackupTarget {
#[instrument(skip(self, cancel))]
fn backup(&self, repo: &T, cancel: &AtomicBool) -> Result<String, errors::Error> {
if !self.target.as_ref().exists() {
std::fs::create_dir_all(self.target.as_ref()).map_err(|e| {
Expand Down Expand Up @@ -45,13 +44,6 @@ impl<T: BackupEntity + std::fmt::Debug> BackupTarget<T> for FileSystemBackupTarg

if target_path.exists() {
self.fetch(repo, &target_path, cancel)
// {
// Ok(id) => Ok(id),
// Err(e) => {
// warn!(error=%e, "Failed to fetch repository '{}', falling back to cloning it.", repo.full_name());
// self.clone(repo, &target_path, cancel)
// }
// }
} else {
self.clone(repo, &target_path, cancel)
}
Expand All @@ -71,6 +63,7 @@ impl FileSystemBackupTarget {
self
}

#[instrument(skip(self, repo, target, cancel), err)]
fn clone<T: BackupEntity>(
&self,
repo: &T,
Expand Down Expand Up @@ -126,6 +119,7 @@ impl FileSystemBackupTarget {
Ok(format!("{}", head_id.to_hex()))
}

#[instrument(skip(self, repo, target, cancel), err)]
fn fetch<T: BackupEntity>(
&self,
repo: &T,
Expand Down

0 comments on commit 9aa8c7d

Please sign in to comment.