use async_trait::async_trait;
use std::time::Instant;
#[async_trait]
pub trait ILogger: Send + Sync {
async fn info(&self, msg: &str);
async fn debug(&self, msg: &str);
async fn warn(&self, msg: &str);
async fn error(&self, msg: &str);
async fn exec(&self, msg: &str);
fn time(&self, msg: &str) -> TimeEvent;
}
pub struct TimeEvent {
start: Instant,
message: String,
on_end: Option<Box<dyn FnOnce(std::time::Duration) + Send>>,
}
impl TimeEvent {
pub fn new(message: impl Into<String>, on_end: Option<Box<dyn FnOnce(std::time::Duration) + Send>>) -> Self {
Self { start: Instant::now(), message: message.into(), on_end }
}
pub fn stop(self) -> std::time::Duration {
self.start.elapsed()
}
pub fn end(self) -> std::time::Duration {
let d = self.start.elapsed();
if let Some(cb) = self.on_end {
cb(d);
}
d
}
pub fn elapsed(&self) -> std::time::Duration {
self.start.elapsed()
}
pub fn message(&self) -> &str {
&self.message
}
}
#[derive(Clone)]
pub struct ConsoleLogger {
is_production: bool,
}
impl ConsoleLogger {
pub fn new(is_production: bool) -> Self {
Self { is_production }
}
pub fn global() -> Self {
let prod = crate::env::AppEnvironment::try_get().map(|e| e.is_production()).unwrap_or(false);
Self::new(prod)
}
fn prefix() -> String {
"framework".to_string()
}
}
#[async_trait]
impl ILogger for ConsoleLogger {
async fn info(&self, msg: &str) {
tracing::info!(target: "console", executor = %Self::prefix(), "{}", msg);
}
async fn debug(&self, msg: &str) {
if self.is_production {
return;
}
tracing::debug!(target: "console", executor = %Self::prefix(), "{}", msg);
}
async fn warn(&self, msg: &str) {
tracing::warn!(target: "console", executor = %Self::prefix(), "{}", msg);
}
async fn error(&self, msg: &str) {
tracing::error!(target: "console", executor = %Self::prefix(), "{}", msg);
}
async fn exec(&self, msg: &str) {
tracing::info!(target: "console", executor = %Self::prefix(), exec = true, "{}", msg);
}
fn time(&self, msg: &str) -> TimeEvent {
let msg_owned = msg.to_string();
let label = msg_owned.clone();
TimeEvent::new(msg_owned, Some(Box::new(move |d| {
tracing::info!(target: "console", operation = %label, duration_ms = d.as_millis() as u64, "Operation completed");
})))
}
}
pub struct MonitorLogger {
inner: ConsoleLogger,
}
impl MonitorLogger {
pub fn new(is_production: bool) -> Self {
Self { inner: ConsoleLogger::new(is_production) }
}
}
#[async_trait]
impl ILogger for MonitorLogger {
async fn info(&self, msg: &str) { self.inner.info(msg).await }
async fn debug(&self, msg: &str) { self.inner.debug(msg).await }
async fn warn(&self, msg: &str) { self.inner.warn(msg).await }
async fn error(&self, msg: &str) { self.inner.error(msg).await }
async fn exec(&self, msg: &str) { self.inner.exec(msg).await }
fn time(&self, msg: &str) -> TimeEvent { self.inner.time(msg) }
}