Skip to content

Commit

Permalink
feat: add tracing logs (#8)
Browse files Browse the repository at this point in the history
Signed-off-by: Jérémie Drouet <jeremie.drouet@gmail.com>
  • Loading branch information
jdrouet authored May 19, 2024
1 parent 27b32b6 commit a07e1ad
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 18 deletions.
134 changes: 134 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ indexmap = { version = "2.2.6", features = ["serde"] }
serde = { version = "1.0.200", features = ["derive"] }
thiserror = { version = "1.0.60" }
toml = { version = "0.8.12", features = ["preserve_order"] }
tracing = { version = "0.1.40" }
tracing-subscriber = { version = "0.3.18" }

[dev-dependencies]
mockall = "0.12.1"
1 change: 1 addition & 0 deletions src/cmd/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub(crate) struct CommandAdd {
}

impl super::Executor for CommandAdd {
#[tracing::instrument(name = "add", skip_all, fields(target = self.target.as_str(), name = self.name.as_str()))]
fn execute<Repo: Repository, Out: Write, Err: Write>(
self,
repo: Repo,
Expand Down
1 change: 1 addition & 0 deletions src/cmd/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) struct CommandPush {
}

impl super::Executor for CommandPush {
#[tracing::instrument(name = "push", skip_all, fields(remote = self.remote.as_str()))]
fn execute<Repo: Repository, Out: Write, Err: Write>(
self,
repo: Repo,
Expand Down
1 change: 1 addition & 0 deletions src/cmd/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub(crate) struct CommandRemove {
}

impl super::Executor for CommandRemove {
#[tracing::instrument(name = "remove", skip_all, fields(target = self.target.as_str(), index = self.index))]
fn execute<Repo: Repository, Out: Write, Err: Write>(
self,
repo: Repo,
Expand Down
1 change: 1 addition & 0 deletions src/cmd/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) struct CommandShow {
}

impl super::Executor for CommandShow {
#[tracing::instrument(name = "show", skip_all, fields(target = self.target.as_str()))]
fn execute<Repo: Repository, Out: Write, Err: Write>(
self,
repo: Repo,
Expand Down
21 changes: 21 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,33 @@ struct Args {
/// Allows to use git as an external fallback when command fails.
#[clap(long, default_value = "true")]
fallback_git: bool,
/// Enables verbosity
#[clap(short, long, action = clap::ArgAction::Count)]
verbose: u8,
#[command(subcommand)]
command: cmd::Command,
}

impl Args {
fn log_level(&self) -> Option<tracing::Level> {
match self.verbose {
0 => None,
1 => Some(tracing::Level::ERROR),
2 => Some(tracing::Level::WARN),
3 => Some(tracing::Level::INFO),
4 => Some(tracing::Level::DEBUG),
_ => Some(tracing::Level::TRACE),
}
}
}

fn main() {
let args = Args::parse();

if let Some(level) = args.log_level() {
tracing_subscriber::fmt().with_max_level(level).init();
}

let repo = crate::repository::GitRepository::from_env()
.unwrap()
.with_fallback_git(args.fallback_git);
Expand Down
74 changes: 56 additions & 18 deletions src/repository/git2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,33 +66,50 @@ impl GitRepository {
}

fn revision_id(&self, target: &str) -> Result<git2::Oid, Error> {
tracing::trace!("fetching revision id for target {target:?}");
self.repo
.revparse_single(target)
.map(|rev| rev.id())
.map_err(Error::target_not_found)
.map_err(|err| {
tracing::error!("unable to find revision id for target {target:?}: {err:?}");
Error::target_not_found(err)
})
}

fn signature(&self) -> Result<git2::Signature, Error> {
self.repo.signature().map_err(Error::signature_not_found)
tracing::trace!("fetching signature");
self.repo.signature().map_err(|err| {
tracing::error!("unable to get signature: {err:?}");
Error::signature_not_found(err)
})
}

fn command_push(&self, remote: &str) -> Result<(), Error> {
tracing::trace!("pushing metrics");
std::process::Command::new("git")
.args(["push", remote, super::NOTES_REF])
.spawn()
.map_err(Error::unable_to_push)
.and_then(|mut cmd| cmd.wait().map(|_| ()).map_err(Error::unable_to_push))
.map_err(|err| {
tracing::error!("unable to start pushing: {err:?}");
Error::unable_to_push(err)
})
.and_then(|mut cmd| {
cmd.wait().map(|_| ()).map_err(|err| {
tracing::error!("pushing failed: {err:?}");
Error::unable_to_push(err)
})
})
}

fn manual_push(&self, remote: &str) -> Result<(), Error> {
let config = self
.repo
.config()
.map_err(|err| Error::new(super::ErrorKind::UnableToReadConfig, err))?;
let mut remote = self
.repo
.find_remote(remote)
.map_err(Error::remote_not_found)?;
let config = self.repo.config().map_err(|err| {
tracing::error!("unable to read config: {err:?}");
Error::new(super::ErrorKind::UnableToReadConfig, err)
})?;
let mut remote = self.repo.find_remote(remote).map_err(|err| {
tracing::error!("unable to find remote {remote:?}: {err:?}");
Error::remote_not_found(err)
})?;
let mut remote_cb = git2::RemoteCallbacks::new();
remote_cb.credentials(|url, username, allowed_types| {
with_credentials(&config, url, username, allowed_types)
Expand All @@ -101,7 +118,10 @@ impl GitRepository {
push_opts.remote_callbacks(remote_cb);
remote
.push(&[NOTES_REF], Some(&mut push_opts))
.map_err(Error::unable_to_push)
.map_err(|err| {
tracing::error!("unable to push metrics: {err:?}");
Error::unable_to_push(err)
})
}
}

Expand All @@ -116,27 +136,45 @@ impl Repository for GitRepository {
}

fn get_metrics(&self, target: &str) -> Result<Vec<Metric>, Error> {
tracing::trace!("getting metrics for target {target:?}");
let rev_id = self.revision_id(target)?;

let Ok(note) = self.repo.find_note(super::NOTES_REF_OPTS, rev_id) else {
tracing::debug!("no note found for revision");
return Ok(Default::default());
};

note.message()
.map(|msg| toml::from_str::<super::Note>(msg).map_err(Error::unable_to_decode))
.unwrap_or(Ok(super::Note::default()))
.map(|msg| {
tracing::trace!("deserializing note content");
toml::from_str::<super::Note>(msg).map_err(|err| {
tracing::error!("unable to deserialize note: {err:?}");
Error::unable_to_decode(err)
})
})
.unwrap_or_else(|| {
tracing::debug!("no message found for note {:?}", note.id());
Ok(super::Note::default())
})
.map(|res| res.metrics)
}

fn set_metrics(&self, target: &str, metrics: Vec<Metric>) -> Result<(), Error> {
tracing::trace!("settings {} metrics for target {target:?}", metrics.len());
let head_id = self.revision_id(target)?;
let sig = self.signature()?;

let note =
toml::to_string_pretty(&super::Note { metrics }).map_err(Error::unable_to_encode)?;
tracing::trace!("serializing metrics");
let note = toml::to_string_pretty(&super::Note { metrics }).map_err(|err| {
tracing::error!("unable to serialize metrics: {err:?}");
Error::unable_to_encode(err)
})?;
self.repo
.note(&sig, &sig, super::NOTES_REF_OPTS, head_id, &note, true)
.map_err(Error::unable_to_persist)?;
.map_err(|err| {
tracing::error!("unable to persist metrics: {err:?}");
Error::unable_to_persist(err)
})?;

Ok(())
}
Expand Down

0 comments on commit a07e1ad

Please sign in to comment.