use std::{
path::Path,
sync::{
atomic::{AtomicU32, Ordering},
Arc,
},
};
use gix::progress::DoOrDiscard;
use parking_lot::Mutex;
use rusqlite::params;
use tracing_forest::tree::Tree;
use tracing_subscriber::layer::SubscriberExt;
type ProgressItem = DoOrDiscard<gix::progress::prodash::tree::Item>;
pub fn override_thread_subscriber(
db_path: impl AsRef<Path>,
progress: Option<ProgressItem>,
reverse_lines: bool,
) -> anyhow::Result<(tracing::subscriber::DefaultGuard, Arc<AtomicU32>)> {
let current_id = Arc::new(AtomicU32::default());
let processor = tracing_forest::Printer::new().formatter(StoreTreeToDb {
con: Arc::new(Mutex::new(rusqlite::Connection::open(&db_path)?)),
run_id: current_id.clone(),
progress: progress.map(Mutex::new),
reverse_lines,
});
let subscriber = tracing_subscriber::Registry::default().with(tracing_forest::ForestLayer::from(processor));
let guard = tracing::subscriber::set_default(subscriber);
Ok((guard, current_id))
}
pub struct StoreTreeToDb {
con: Arc<Mutex<rusqlite::Connection>>,
run_id: Arc<AtomicU32>,
progress: Option<Mutex<ProgressItem>>,
reverse_lines: bool,
}
impl tracing_forest::printer::Formatter for StoreTreeToDb {
type Error = rusqlite::Error;
fn fmt(&self, tree: &Tree) -> Result<String, Self::Error> {
if let Some((progress, tree)) = self
.progress
.as_ref()
.map(Mutex::lock)
.zip(tracing_forest::printer::Pretty.fmt(tree).ok())
{
use gix::Progress;
if self.reverse_lines {
for line in tree.lines().rev() {
progress.info(line.into());
}
} else {
for line in tree.lines() {
progress.info(line.into());
}
}
}
let json = serde_json::to_string_pretty(&tree).expect("serialization to string always works");
let run_id = self.run_id.load(Ordering::SeqCst);
self.con
.lock()
.execute("UPDATE run SET spans_json = ?1 WHERE id = ?2", params![json, run_id])?;
Ok(String::new())
}
}