forked from Orchid/orchid
78 lines
2.1 KiB
Rust
78 lines
2.1 KiB
Rust
use std::any::Any;
|
|
use std::cell::RefCell;
|
|
use std::fmt::Arguments;
|
|
use std::io::Write;
|
|
use std::rc::Rc;
|
|
|
|
use futures::future::LocalBoxFuture;
|
|
use task_local::task_local;
|
|
|
|
use crate::api;
|
|
|
|
task_local! {
|
|
static DEFAULT_WRITER: RefCell<Box<dyn Write>>
|
|
}
|
|
|
|
/// Set the stream used for [api::LogStrategy::Default]. If not set,
|
|
/// [std::io::stderr] will be used.
|
|
pub async fn with_default_stream<F: Future>(stderr: impl Write + 'static, fut: F) -> F::Output {
|
|
DEFAULT_WRITER.scope(RefCell::new(Box::new(stderr)), fut).await
|
|
}
|
|
|
|
pub trait LogWriter {
|
|
fn write_fmt<'a>(&'a self, fmt: Arguments<'a>) -> LocalBoxFuture<'a, ()>;
|
|
}
|
|
|
|
pub trait Logger: Any {
|
|
fn writer(&self, category: &str) -> Rc<dyn LogWriter>;
|
|
fn strat(&self, category: &str) -> api::LogStrategy;
|
|
fn is_active(&self, category: &str) -> bool {
|
|
!matches!(self.strat(category), api::LogStrategy::Discard)
|
|
}
|
|
}
|
|
|
|
task_local! {
|
|
static LOGGER: Rc<dyn Logger>;
|
|
}
|
|
|
|
pub async fn with_logger<F: Future>(logger: impl Logger + 'static, fut: F) -> F::Output {
|
|
LOGGER.scope(Rc::new(logger), fut).await
|
|
}
|
|
|
|
pub fn log(category: &str) -> Rc<dyn LogWriter> {
|
|
LOGGER.try_with(|l| l.writer(category)).expect("Logger not set!")
|
|
}
|
|
|
|
pub fn get_logger() -> Rc<dyn Logger> { LOGGER.try_with(|l| l.clone()).expect("Logger not set!") }
|
|
|
|
pub mod test {
|
|
use std::fmt::Arguments;
|
|
use std::rc::Rc;
|
|
|
|
use futures::future::LocalBoxFuture;
|
|
|
|
use crate::clone;
|
|
use crate::logging::{LogWriter, Logger};
|
|
|
|
#[derive(Clone)]
|
|
pub struct TestLogger(Rc<dyn Fn(String) -> LocalBoxFuture<'static, ()>>);
|
|
impl LogWriter for TestLogger {
|
|
fn write_fmt<'a>(&'a self, fmt: Arguments<'a>) -> LocalBoxFuture<'a, ()> {
|
|
(self.0)(fmt.to_string())
|
|
}
|
|
}
|
|
impl Logger for TestLogger {
|
|
fn strat(&self, _category: &str) -> orchid_api::LogStrategy { orchid_api::LogStrategy::Default }
|
|
fn writer(&self, _category: &str) -> std::rc::Rc<dyn LogWriter> { Rc::new(self.clone()) }
|
|
}
|
|
impl TestLogger {
|
|
pub fn new(f: impl AsyncFn(String) + 'static) -> Self {
|
|
let f = Rc::new(f);
|
|
Self(Rc::new(move |s| clone!(f; Box::pin(async move { f(s).await }))))
|
|
}
|
|
}
|
|
impl Default for TestLogger {
|
|
fn default() -> Self { TestLogger::new(async |s| eprint!("{s}")) }
|
|
}
|
|
}
|