use std::sync::OnceLock;
use tracing_indicatif::IndicatifLayer;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
#[allow(dead_code)]
static INDICATIF_LAYER: OnceLock<IndicatifLayer<tracing_subscriber::Registry>> = OnceLock::new();
pub fn setup_tracing() {
init_tracing(false);
}
pub fn init_tracing(verbose: bool) {
use std::sync::Once;
static INIT: Once = Once::new();
INIT.call_once(|| {
let indicatif_layer = IndicatifLayer::new();
let env_filter = if verbose {
tracing_subscriber::EnvFilter::new("vx=debug,info")
} else {
tracing_subscriber::EnvFilter::new("vx=info,warn,error")
};
tracing_subscriber::registry()
.with(env_filter)
.with(
tracing_subscriber::fmt::layer()
.with_writer(indicatif_layer.get_stderr_writer())
.with_target(false)
.with_level(verbose),
)
.with(indicatif_layer)
.try_init()
.ok(); });
}
pub fn get_indicatif_layer() -> Option<()> {
None
}
#[macro_export]
macro_rules! progress_span {
($name:expr, $($field:tt)*) => {
tracing::info_span!($name, $($field)*)
};
}
#[macro_export]
macro_rules! with_progress_span {
($name:expr, $operation:expr) => {{
let span = tracing::info_span!($name);
async move {
let _enter = span.enter();
$operation.await
}
}};
}
#[macro_export]
macro_rules! with_progress_events {
($name:expr, $success_msg:expr, $error_msg:expr, $operation:expr) => {{
let span = tracing::info_span!($name);
async move {
let _enter = span.enter();
match $operation.await {
Ok(result) => {
tracing::info!($success_msg);
Ok(result)
}
Err(error) => {
tracing::error!("{}: {}", $error_msg, error);
Err(error)
}
}
}
}};
}
pub fn create_manual_progress_bar(len: u64, message: &str) -> indicatif::ProgressBar {
use indicatif::{ProgressBar, ProgressStyle};
let pb = ProgressBar::new(len);
pb.set_style(
ProgressStyle::with_template(
"{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len} {msg}",
)
.unwrap()
.progress_chars("#>-"),
);
pb.set_message(message.to_string());
if let Some(_layer) = get_indicatif_layer() {
}
pb
}
pub fn suspend_progress_bars<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
if let Some(_layer) = get_indicatif_layer() {
tracing_indicatif::suspend_tracing_indicatif(f)
} else {
f()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_progress_span_macro() {
init_tracing(true);
let result = with_progress_span!("test_operation", async {
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
Ok::<_, anyhow::Error>(42)
})
.await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 42);
}
#[tokio::test]
async fn test_progress_events_macro() {
init_tracing(true);
let result = with_progress_events!(
"test_operation_with_events",
"Operation completed successfully",
"Operation failed",
async {
tokio::time::sleep(std::time::Duration::from_millis(5)).await;
Ok::<_, anyhow::Error>("success")
}
)
.await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), "success");
}
}