Files
dioxus/packages/cli/src/tracer.rs
T

97 lines
2.8 KiB
Rust

use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
use std::{
env, io,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
};
use tracing_subscriber::{prelude::*, EnvFilter};
const LOG_ENV: &str = "DIOXUS_LOG";
/// Build tracing infrastructure.
pub fn build_tracing() -> CLILogControl {
// If {LOG_ENV} is set, default to env, otherwise filter to cli
// and manganis warnings and errors from other crates
let mut filter = EnvFilter::new("error,dx=info,dioxus-cli=info,manganis-cli-support=info");
if env::var(LOG_ENV).is_ok() {
filter = EnvFilter::from_env(LOG_ENV);
}
// Create writer controller and custom writer.
let (tui_tx, tui_rx) = unbounded();
let tui_enabled = Arc::new(AtomicBool::new(false));
let writer_control = CLILogControl {
tui_rx,
tui_enabled: tui_enabled.clone(),
};
let cli_writer = Mutex::new(CLIWriter::new(tui_enabled, tui_tx));
// Build tracing
let fmt_layer = tracing_subscriber::fmt::layer()
.with_writer(cli_writer)
.with_filter(filter);
let sub = tracing_subscriber::registry().with(fmt_layer);
#[cfg(feature = "tokio-console")]
let sub = sub.with(console_subscriber::spawn());
sub.init();
writer_control
}
/// Contains the sync primitives to control the CLIWriter.
pub struct CLILogControl {
pub tui_rx: UnboundedReceiver<String>,
pub tui_enabled: Arc<AtomicBool>,
}
/// Represents the CLI's custom tracing writer for conditionally writing logs between outputs.
pub struct CLIWriter {
stdout: io::Stdout,
tui_tx: UnboundedSender<String>,
tui_enabled: Arc<AtomicBool>,
}
impl CLIWriter {
/// Create a new CLIWriter with required sync primitives for conditionally routing logs.
pub fn new(tui_enabled: Arc<AtomicBool>, tui_tx: UnboundedSender<String>) -> Self {
Self {
stdout: io::stdout(),
tui_tx,
tui_enabled,
}
}
}
// Implement a conditional writer so that logs are routed to the appropriate place.
impl io::Write for CLIWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.tui_enabled.load(Ordering::SeqCst) {
let len = buf.len();
let as_string = String::from_utf8(buf.to_vec())
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
self.tui_tx
.unbounded_send(as_string)
.map_err(|e| io::Error::new(io::ErrorKind::BrokenPipe, e))?;
Ok(len)
} else {
self.stdout.write(buf)
}
}
fn flush(&mut self) -> io::Result<()> {
if !self.tui_enabled.load(Ordering::SeqCst) {
self.stdout.flush()
} else {
Ok(())
}
}
}