use {
crate::SyslogBuilder,
libsyslog_sys::*,
log::{
Level,
LevelFilter,
Metadata,
Record,
SetLoggerError,
set_boxed_logger,
set_max_level,
},
std::{
ffi::CString,
os::raw::c_int,
},
};
#[derive(Debug)]
pub struct Syslog {
pub(crate) facility: c_int,
pub(crate) ident: CString,
pub(crate) level: LevelFilter,
pub(crate) logopt: c_int,
pub(crate) module_levels: Vec<(String, LevelFilter)>,
}
impl Syslog {
#[must_use = "No Syslog is constructed unless .build() is called."]
pub fn builder() -> SyslogBuilder {
SyslogBuilder::default()
}
pub fn init(mut self) -> Result<(), SetLoggerError> {
unsafe { openlog(self.ident.as_ptr(), self.logopt, self.facility); }
self.module_levels.sort_by_key(|(modpath, _)| modpath.len().wrapping_neg());
let max_module_level = self.module_levels.iter().map(|(_, level)| level).copied().max();
let max_level = max_module_level.map(|level| level.max(self.level)).unwrap_or(self.level);
set_max_level(max_level);
set_boxed_logger(Box::new(self))
}
}
impl Drop for Syslog {
fn drop(&mut self) {
unsafe { closelog(); }
}
}
impl log::Log for Syslog {
fn enabled(&self, metadata: &Metadata) -> bool {
&metadata.level().to_level_filter() <= self.module_levels.iter()
.find(|(modpath, _)| metadata.target().starts_with(modpath) ).map(|(_, level)| level)
.unwrap_or(&self.level)
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
if let (Ok(fmt), Ok(msg)) = ( CString::new("%s"),
CString::new(format!("{}", record.args())))
{
let fmt_ptr = fmt.as_ptr();
let msg_ptr = msg.as_ptr();
match record.level() {
Level::Debug => unsafe { syslog(LOG_DEBUG, fmt_ptr, msg_ptr); }
Level::Error => unsafe { syslog(LOG_ERR, fmt_ptr, msg_ptr); }
Level::Info => unsafe { syslog(LOG_INFO, fmt_ptr, msg_ptr); }
Level::Warn => unsafe { syslog(LOG_WARNING, fmt_ptr, msg_ptr); }
Level::Trace => unsafe { syslog(LOG_DEBUG, fmt_ptr, msg_ptr); }
}
}
}
}
fn flush(&self) {}
}