I got very confused and started mucking about with "spawn" when in fact all I needed was the "inline" extension type in orcx that allows the interpreter to expose custom constants.
85 lines
2.8 KiB
Rust
85 lines
2.8 KiB
Rust
use std::fmt::Arguments;
|
|
use std::fs::File;
|
|
use std::io::{Write, stderr};
|
|
use std::rc::Rc;
|
|
|
|
use futures::future::LocalBoxFuture;
|
|
use hashbrown::HashMap;
|
|
use itertools::Itertools;
|
|
use orchid_base::{LogWriter, Logger};
|
|
|
|
use crate::api;
|
|
|
|
pub struct LogWriterImpl(api::LogStrategy);
|
|
impl LogWriter for LogWriterImpl {
|
|
fn write_fmt<'a>(&'a self, fmt: Arguments<'a>) -> LocalBoxFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
match &self.0 {
|
|
api::LogStrategy::Discard => (),
|
|
api::LogStrategy::Default => {
|
|
stderr().write_fmt(fmt).expect("Could not write to stderr!");
|
|
stderr().flush().expect("Could not flush stderr")
|
|
},
|
|
api::LogStrategy::File { path, .. } => {
|
|
let mut file = (File::options().write(true).create(true).truncate(false).open(path))
|
|
.unwrap_or_else(|e| panic!("Could not open {path}: {e}"));
|
|
file.write_fmt(fmt).unwrap_or_else(|e| panic!("Could not write to {path}: {e}"));
|
|
},
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Default)]
|
|
pub struct LoggerImpl {
|
|
routing: HashMap<String, api::LogStrategy>,
|
|
default: Option<api::LogStrategy>,
|
|
}
|
|
impl LoggerImpl {
|
|
pub fn to_api(&self) -> api::Logger {
|
|
api::Logger {
|
|
default: self.default.clone(),
|
|
routing: self.routing.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
|
|
}
|
|
}
|
|
|
|
pub fn new(
|
|
default: Option<api::LogStrategy>,
|
|
strats: impl IntoIterator<Item = (String, api::LogStrategy)>,
|
|
) -> Self {
|
|
Self { routing: strats.into_iter().collect(), default }
|
|
}
|
|
pub fn set_default(&mut self, strat: api::LogStrategy) { self.default = Some(strat) }
|
|
pub fn clear_default(&mut self) { self.default = None }
|
|
pub fn set_category(&mut self, category: &str, strat: api::LogStrategy) {
|
|
self.routing.insert(category.to_string(), strat);
|
|
}
|
|
pub fn with_default(mut self, strat: api::LogStrategy) -> Self {
|
|
self.set_default(strat);
|
|
self
|
|
}
|
|
pub fn with_category(mut self, category: &str, strat: api::LogStrategy) -> Self {
|
|
self.set_category(category, strat);
|
|
self
|
|
}
|
|
pub async fn log(&self, category: &str, msg: impl AsRef<str>) {
|
|
writeln!(self.writer(category), "{}", msg.as_ref()).await
|
|
}
|
|
pub fn has_category(&self, category: &str) -> bool { self.routing.contains_key(category) }
|
|
pub async fn log_buf(&self, category: &str, event: impl AsRef<str>, buf: &[u8]) {
|
|
if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) {
|
|
let data = buf.iter().map(|b| format!("{b:02x}")).join(" ");
|
|
writeln!(self.writer(category), "{}: [{data}]", event.as_ref()).await
|
|
}
|
|
}
|
|
}
|
|
impl Logger for LoggerImpl {
|
|
fn writer(&self, category: &str) -> Rc<dyn LogWriter> {
|
|
Rc::new(LogWriterImpl(self.strat(category).clone()))
|
|
}
|
|
fn strat(&self, category: &str) -> api::LogStrategy {
|
|
(self.routing.get(category).cloned().or(self.default.clone()))
|
|
.expect("Invalid category and catchall logger not set")
|
|
}
|
|
}
|