pub mod config;
pub mod core;
pub mod diagnostics;
pub mod error;
pub mod mpi;
pub mod shutdown;
pub mod sinks;
pub mod utils;
#[cfg(feature = "database")]
pub mod database {
pub use crate::sinks::database::*;
}
pub use config::{
load_config_from_file, BackpressureStrategy, OutputFormat, QuantumLogConfig,
QuantumLoggerConfig, StdoutConfig,
};
pub use diagnostics::{get_diagnostics, DiagnosticsSnapshot};
pub use error::{QuantumLogError, Result};
pub use shutdown::{
ShutdownCoordinator, ShutdownHandle as QuantumShutdownHandle, ShutdownListener, ShutdownSignal,
ShutdownState,
};
pub use core::event::QuantumLogEvent;
pub use core::subscriber::{BufferStats, QuantumLogSubscriber, QuantumLogSubscriberBuilder};
use once_cell::sync::Lazy;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
};
use crate::diagnostics::init_diagnostics;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
static GLOBAL_SUBSCRIBER: Lazy<Arc<Mutex<Option<QuantumLogSubscriber>>>> =
Lazy::new(|| Arc::new(Mutex::new(None)));
pub static IS_QUANTUM_LOG_INITIALIZED: AtomicBool = AtomicBool::new(false);
pub async fn init() -> Result<()> {
let _ = init_diagnostics();
let config = QuantumLogConfig {
pre_init_stdout_enabled: true,
stdout: Some(crate::config::StdoutConfig {
enabled: true,
..Default::default()
}),
..Default::default()
};
let mut subscriber = QuantumLogSubscriber::with_config(config)?;
subscriber.initialize().await?;
if let Ok(mut global) = GLOBAL_SUBSCRIBER.lock() {
*global = Some(subscriber.clone());
}
subscriber.install_global()?;
Ok(())
}
pub async fn init_with_config(config: QuantumLogConfig) -> Result<()> {
let _ = init_diagnostics();
let mut subscriber = QuantumLogSubscriber::with_config(config)?;
subscriber.initialize().await?;
if let Ok(mut global) = GLOBAL_SUBSCRIBER.lock() {
*global = Some(subscriber.clone());
}
subscriber.install_global()?;
Ok(())
}
pub async fn init_with_builder<F>(
builder_fn: F,
) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>>
where
F: FnOnce(QuantumLogSubscriberBuilder) -> QuantumLogSubscriberBuilder,
{
let _ = init_diagnostics();
let builder = QuantumLogSubscriber::builder();
let mut subscriber = builder_fn(builder).build()?;
subscriber.initialize().await?;
if let Ok(mut global) = GLOBAL_SUBSCRIBER.lock() {
*global = Some(subscriber.clone());
}
subscriber.install_global()?;
Ok(())
}
pub async fn shutdown() -> Result<()> {
let subscriber = if let Ok(mut global) = GLOBAL_SUBSCRIBER.lock() {
global.take()
} else {
None
};
if let Some(subscriber) = subscriber {
subscriber.shutdown().await?;
}
Ok(())
}
pub fn get_buffer_stats() -> Option<BufferStats> {
if let Ok(global) = GLOBAL_SUBSCRIBER.lock() {
global
.as_ref()
.map(|subscriber| subscriber.get_buffer_stats())
} else {
None
}
}
pub fn is_initialized() -> bool {
if let Ok(global) = GLOBAL_SUBSCRIBER.lock() {
global
.as_ref()
.is_some_and(|subscriber| subscriber.is_initialized())
} else {
false
}
}
pub fn get_config() -> Option<QuantumLogConfig> {
if let Ok(global) = GLOBAL_SUBSCRIBER.lock() {
global
.as_ref()
.map(|subscriber| subscriber.config().clone())
} else {
None
}
}
use tokio::sync::oneshot;
#[derive(Debug)]
pub struct ShutdownHandle {
sender: Option<oneshot::Sender<()>>,
}
impl ShutdownHandle {
pub fn new(sender: oneshot::Sender<()>) -> Self {
Self {
sender: Some(sender),
}
}
pub async fn shutdown(mut self) -> Result<()> {
if let Some(sender) = self.sender.take() {
sender.send(()).map_err(|_| {
QuantumLogError::ShutdownError("Failed to send shutdown signal".to_string())
})?;
}
Ok(())
}
}
pub async fn init_quantum_logger() -> Result<ShutdownHandle> {
let _ = init_diagnostics();
if IS_QUANTUM_LOG_INITIALIZED
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_err()
{
return Err(QuantumLogError::InitializationError(
"QuantumLog has already been initialized".to_string(),
));
}
let mut subscriber = QuantumLogSubscriber::new().map_err(|e| {
QuantumLogError::InitializationError(format!("Failed to create subscriber: {}", e))
})?;
subscriber.initialize().await.map_err(|e| {
QuantumLogError::InitializationError(format!("Failed to initialize subscriber: {}", e))
})?;
let (shutdown_sender, shutdown_receiver) = oneshot::channel();
let subscriber_for_shutdown = subscriber.clone();
if let Ok(mut global) = GLOBAL_SUBSCRIBER.lock() {
*global = Some(subscriber.clone());
} else {
IS_QUANTUM_LOG_INITIALIZED.store(false, Ordering::SeqCst);
return Err(QuantumLogError::InitializationError(
"Failed to acquire global subscriber lock".to_string(),
));
}
if let Err(e) = subscriber.install_global() {
IS_QUANTUM_LOG_INITIALIZED.store(false, Ordering::SeqCst);
if let Ok(mut global) = GLOBAL_SUBSCRIBER.lock() {
*global = None;
}
return Err(QuantumLogError::InitializationError(format!(
"Failed to install global subscriber: {}",
e
)));
}
tokio::spawn(async move {
if shutdown_receiver.await.is_ok() {
if let Err(e) = subscriber_for_shutdown.shutdown().await {
eprintln!("Error during shutdown: {}", e);
}
IS_QUANTUM_LOG_INITIALIZED.store(false, Ordering::SeqCst);
if let Ok(mut global) = GLOBAL_SUBSCRIBER.lock() {
*global = None;
}
}
});
Ok(ShutdownHandle::new(shutdown_sender))
}