use std::{future::IntoFuture, io::Write, path::Path};
use linera_chain::types::CertificateValue;
use tokio::select;
use crate::storage::ExporterStorage;
pub(crate) struct LoggingExporter {
file: std::fs::File,
}
impl LoggingExporter {
pub fn new(log_file: &Path) -> Self {
let file = std::fs::File::create(log_file).expect("Failed to create log file");
LoggingExporter { file }
}
pub(crate) async fn run_with_shutdown<S, F: IntoFuture<Output = ()>>(
self,
shutdown_signal: F,
storage: ExporterStorage<S>,
) -> anyhow::Result<()>
where
S: linera_storage::Storage + Clone + Send + Sync + 'static,
{
let shutdown_signal_future = shutdown_signal.into_future();
let mut pinned_shutdown_signal = Box::pin(shutdown_signal_future);
select! {
_ = &mut pinned_shutdown_signal => {
tracing::info!("logging exporter shutdown signal received, exiting.");
}
_ = self.start_logger(storage) => {
}
}
Ok(())
}
async fn start_logger<S>(mut self, storage: ExporterStorage<S>) -> anyhow::Result<()>
where
S: linera_storage::Storage + Clone + Send + Sync + 'static,
{
let mut canonical_chain_height = storage.get_latest_index();
tracing::info!(
"starting logging exporter at height {}",
canonical_chain_height
);
loop {
if let Ok((block, blobs)) = storage.get_block_with_blobs(canonical_chain_height).await {
let inner = block.inner();
writeln!(
self.file,
"Block ID: {}, Chain: {}, Height: {}, State Hash: {}, Authenticated Signer: {}",
inner.hash(),
inner.chain_id(),
inner.height(),
inner.block().header.state_hash,
inner
.block()
.header
.authenticated_signer
.map_or_else(|| "N/A".into(), |signer| signer.to_string()),
)?;
for blob in blobs {
writeln!(self.file, "\tBlob ID: {}", blob.id(),)?;
}
canonical_chain_height += 1;
} else {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
}
}
}