use noema::core::{Container, Injectable};
pub trait Logger: Send + Sync {
fn debug(&self, msg: &str);
fn info(&self, msg: &str);
fn warn(&self, msg: &str);
fn error(&self, msg: &str);
}
#[derive(Clone, Copy, Default)]
pub struct TracingLogger;
impl Logger for TracingLogger {
fn debug(&self, msg: &str) {
tracing::debug!("{msg}");
}
fn info(&self, msg: &str) {
tracing::info!("{msg}");
}
fn warn(&self, msg: &str) {
tracing::warn!("{msg}");
}
fn error(&self, msg: &str) {
tracing::error!("{msg}");
}
}
impl Injectable<Container> for TracingLogger {
fn inject(_: &Container) -> Self {
Self
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::{Arc, Mutex};
struct MemLogger {
lines: Mutex<Vec<String>>,
}
impl Logger for MemLogger {
fn debug(&self, msg: &str) {
self.lines.lock().unwrap().push(format!("debug:{msg}"));
}
fn info(&self, msg: &str) {
self.lines.lock().unwrap().push(format!("info:{msg}"));
}
fn warn(&self, msg: &str) {
self.lines.lock().unwrap().push(format!("warn:{msg}"));
}
fn error(&self, msg: &str) {
self.lines.lock().unwrap().push(format!("error:{msg}"));
}
}
#[test]
fn logger_port_is_usable_from_a_handler() {
let mem = Arc::new(MemLogger {
lines: Mutex::new(Vec::new()),
});
let log: Arc<dyn Logger + Send + Sync> = Arc::clone(&mem) as _;
log.info("send CreateUser");
log.warn("slow query");
let lines = mem.lines.lock().unwrap();
assert_eq!(
lines.as_slice(),
["info:send CreateUser", "warn:slow query"]
);
}
#[test]
fn logger_resolve_is_singleton() {
let a = noema::resolve::<dyn Logger + Send + Sync>();
let b = noema::resolve::<dyn Logger + Send + Sync>();
assert!(std::sync::Arc::ptr_eq(&a, &b));
a.info("boot");
}
}