forked from Orchid/orchid
Traditional route appears to work
Beginnings of dylib extensions, entirely untestted
This commit is contained in:
@@ -1,47 +1,74 @@
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Arguments;
|
||||
use std::fs::File;
|
||||
use std::io::{Write, stderr};
|
||||
use std::io::Write;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub use api::LogStrategy;
|
||||
use itertools::Itertools;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use task_local::task_local;
|
||||
|
||||
use crate::api;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Logger(api::LogStrategy);
|
||||
impl Logger {
|
||||
pub fn new(strat: api::LogStrategy) -> Self { Self(strat) }
|
||||
pub fn log(&self, msg: impl AsRef<str>) { writeln!(self, "{}", msg.as_ref()) }
|
||||
pub fn strat(&self) -> api::LogStrategy { self.0.clone() }
|
||||
pub fn is_active(&self) -> bool { !matches!(self.0, api::LogStrategy::Discard) }
|
||||
pub fn log_buf(&self, event: impl AsRef<str>, buf: &[u8]) {
|
||||
if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) {
|
||||
writeln!(self, "{}: [{}]", event.as_ref(), buf.iter().map(|b| format!("{b:02x}")).join(" "))
|
||||
}
|
||||
}
|
||||
pub fn write_fmt(&self, fmt: Arguments) {
|
||||
match &self.0 {
|
||||
api::LogStrategy::Discard => (),
|
||||
api::LogStrategy::StdErr => {
|
||||
stderr().write_fmt(fmt).expect("Could not write to stderr!");
|
||||
stderr().flush().expect("Could not flush stderr")
|
||||
},
|
||||
api::LogStrategy::File(f) => {
|
||||
let mut file = (File::options().write(true).create(true).truncate(true).open(f))
|
||||
.expect("Could not open logfile");
|
||||
file.write_fmt(fmt).expect("Could not write to logfile");
|
||||
},
|
||||
}
|
||||
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: Logger;
|
||||
static LOGGER: Rc<dyn Logger>;
|
||||
}
|
||||
|
||||
pub async fn with_logger<F: Future>(logger: Logger, fut: F) -> F::Output {
|
||||
LOGGER.scope(logger, fut).await
|
||||
pub async fn with_logger<F: Future>(logger: impl Logger + 'static, fut: F) -> F::Output {
|
||||
LOGGER.scope(Rc::new(logger), fut).await
|
||||
}
|
||||
|
||||
pub fn logger() -> Logger { LOGGER.try_with(|l| l.clone()).expect("Logger not set!") }
|
||||
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 }))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user