single-user service manager
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139use log::kv;use std::fmt::Write as _;use std::io::Write as _;use std::{process, sync};
type SyslogLogger = syslog::Logger<syslog::LoggerBackend, syslog::Formatter3164>;
pub enum ServiceLogger { Syslog(SyslogLogger),}
impl ServiceLogger { pub fn new(name: &str, pid: u32) -> syslog::Result<Self> { let formatter = syslog::Formatter3164 { facility: syslog::Facility::LOG_DAEMON, hostname: None, process: name.to_owned(), pid, }; Ok(Self::Syslog(syslog::unix(formatter)?)) }
pub fn emit<T>(&mut self, level: log::Level, message: T) where T: AsRef<str>, { match self { Self::Syslog(logger) => { let result = match level { log::Level::Error => logger.err(message.as_ref()), log::Level::Warn => logger.warning(message.as_ref()), log::Level::Info => logger.info(message.as_ref()), log::Level::Debug | log::Level::Trace => logger.debug(message.as_ref()), }; let _ = result; } } }}
/// A syslog logger which preserves the key-values supplied to `log!` macros.////// `syslog::BasicLogger` currently formats only `Record::args()`, silently/// dropping `Record::key_values()`. Keep the traditional RFC 3164 transport/// and put the fields in the message body so existing syslog deployments keep/// working.pub struct KvLogger { logger: sync::Arc<sync::Mutex<SyslogLogger>>,}
impl KvLogger { fn new(logger: SyslogLogger) -> Self { Self { logger: sync::Arc::new(sync::Mutex::new(logger)), } }}
impl log::Log for KvLogger { fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { metadata.level() <= log::max_level() && metadata.level() <= log::STATIC_MAX_LEVEL }
fn log(&self, record: &log::Record<'_>) { if !self.enabled(record.metadata()) { return; }
let message = format_message(record); let Ok(mut logger) = self.logger.lock() else { return; };
let result = match record.level() { log::Level::Error => logger.err(message), log::Level::Warn => logger.warning(message), log::Level::Info => logger.info(message), log::Level::Debug | log::Level::Trace => logger.debug(message), }; let _ = result; }
fn flush(&self) { if let Ok(mut logger) = self.logger.lock() { let _ = logger.backend.flush(); } }}
struct FieldVisitor { fields: String,}
impl<'kvs> kv::VisitSource<'kvs> for FieldVisitor { fn visit_pair(&mut self, key: kv::Key<'kvs>, value: kv::Value<'kvs>) -> Result<(), kv::Error> { if !self.fields.is_empty() { self.fields.push(' '); } let _ = write!(self.fields, "{}={}", key.as_str(), value); Ok(()) }}
fn format_message(record: &log::Record<'_>) -> String { let mut message = record.args().to_string(); let mut visitor = FieldVisitor { fields: String::new(), };
if let Err(error) = record.key_values().visit(&mut visitor) { if !visitor.fields.is_empty() { message.push(' '); } let _ = write!(message, "kv_error={error}"); }
if !visitor.fields.is_empty() { message.push(' '); message.push_str(&visitor.fields); } message}
pub fn init_syslog(facility: syslog::Facility, log_level: log::LevelFilter) -> syslog::Result<()> { let formatter = syslog::Formatter3164 { facility, hostname: None, process: "apogee".to_owned(), pid: process::id(), };
let logger = syslog::unix(formatter)?;
log::set_boxed_logger(Box::new(KvLogger::new(logger))) .map_err(|error| syslog::Error::Initialization(Box::new(error)))?; log::set_max_level(log_level); Ok(())}