use parking_lot::RwLock;
use std::fmt;
use std::io;
use std::sync::Arc;
use crate::formatters::Formatter;
use crate::level::LogLevel;
use crate::record::Record;
pub type HandlerFilter = Arc<dyn Fn(&Record) -> bool + Send + Sync>;
#[derive(Debug)]
pub enum HandlerError {
IoError(io::Error),
NotInitialized,
Custom(String),
}
impl std::fmt::Display for HandlerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HandlerError::IoError(e) => write!(f, "I/O error: {}", e),
HandlerError::NotInitialized => write!(f, "Handler not initialized"),
HandlerError::Custom(msg) => write!(f, "{}", msg),
}
}
}
impl std::error::Error for HandlerError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
HandlerError::IoError(e) => Some(e),
_ => None,
}
}
}
pub trait Handler: Send + Sync + fmt::Debug {
fn level(&self) -> LogLevel;
fn set_level(&mut self, level: LogLevel);
fn is_enabled(&self) -> bool;
fn set_enabled(&mut self, enabled: bool);
fn formatter(&self) -> &Formatter;
fn set_formatter(&mut self, formatter: Formatter);
fn set_filter(&mut self, filter: Option<HandlerFilter>);
fn filter(&self) -> Option<&HandlerFilter>;
fn handle(&self, record: &Record) -> Result<(), HandlerError>;
fn handle_batch(&self, records: &[Record]) -> Result<(), HandlerError> {
for record in records {
self.handle(record)?;
}
Ok(())
}
fn init(&mut self) -> Result<(), HandlerError> {
Ok(())
}
fn flush(&self) -> Result<(), HandlerError> {
Ok(())
}
fn shutdown(&mut self) -> Result<(), HandlerError> {
Ok(())
}
}
pub struct NullHandler {
level: LogLevel,
enabled: bool,
formatter: Formatter,
filter: Option<HandlerFilter>,
}
impl Default for NullHandler {
fn default() -> Self {
Self {
level: LogLevel::Info,
enabled: true,
formatter: Formatter::text(),
filter: None,
}
}
}
impl Handler for NullHandler {
fn level(&self) -> LogLevel {
self.level
}
fn set_level(&mut self, level: LogLevel) {
self.level = level;
}
fn is_enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn formatter(&self) -> &Formatter {
&self.formatter
}
fn set_formatter(&mut self, formatter: Formatter) {
self.formatter = formatter;
}
fn set_filter(&mut self, filter: Option<HandlerFilter>) {
self.filter = filter;
}
fn filter(&self) -> Option<&HandlerFilter> {
self.filter.as_ref()
}
fn handle(&self, _record: &Record) -> Result<(), HandlerError> {
Ok(())
}
}
impl NullHandler {
pub fn new(level: LogLevel) -> Self {
Self {
level,
enabled: true,
formatter: Formatter::text(),
filter: None,
}
}
}
impl fmt::Debug for NullHandler {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NullHandler")
.field("level", &self.level)
.field("enabled", &self.enabled)
.field("formatter", &self.formatter)
.finish()
}
}
pub mod console;
pub mod file;
pub mod network;
pub type HandlerRef = Arc<RwLock<dyn Handler>>;
pub fn new_handler_ref<H: Handler + 'static>(handler: H) -> HandlerRef {
Arc::new(RwLock::new(handler))
}
pub struct BaseHandler {
level: LogLevel,
enabled: bool,
formatter: Formatter,
filter: Option<HandlerFilter>,
}
impl BaseHandler {
pub fn new(level: LogLevel) -> Self {
Self {
level,
enabled: true,
formatter: Formatter::text(),
filter: None,
}
}
}
impl Handler for BaseHandler {
fn level(&self) -> LogLevel {
self.level
}
fn set_level(&mut self, level: LogLevel) {
self.level = level;
}
fn is_enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn formatter(&self) -> &Formatter {
&self.formatter
}
fn set_formatter(&mut self, formatter: Formatter) {
self.formatter = formatter;
}
fn set_filter(&mut self, filter: Option<HandlerFilter>) {
self.filter = filter;
}
fn filter(&self) -> Option<&HandlerFilter> {
self.filter.as_ref()
}
fn handle(&self, record: &Record) -> Result<(), HandlerError> {
if !self.is_enabled() {
return Ok(());
}
if let Some(filter) = &self.filter {
if !filter(record) {
return Ok(());
}
}
Ok(())
}
}
impl fmt::Debug for BaseHandler {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BaseHandler")
.field("level", &self.level)
.field("enabled", &self.enabled)
.field("formatter", &self.formatter)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_base_handler() {
let mut handler = BaseHandler::new(LogLevel::Info);
assert_eq!(handler.level(), LogLevel::Info);
assert!(handler.is_enabled());
handler.set_enabled(false);
assert!(!handler.is_enabled());
let record = Record::new(LogLevel::Info, "test", None::<String>, None::<String>, None);
assert!(handler.handle(&record).is_ok());
handler.set_enabled(true);
let debug_record = Record::new(
LogLevel::Debug,
"test",
None::<String>,
None::<String>,
None,
);
assert!(handler.handle(&debug_record).is_ok());
let info_record = Record::new(LogLevel::Info, "test", None::<String>, None::<String>, None);
assert!(handler.handle(&info_record).is_ok());
let formatter = Formatter::text();
handler.set_formatter(formatter);
assert!(handler.formatter().format(&info_record).contains("test"));
}
}