#[derive(StructOpt,Debug)]
pub struct LogOpts {
/// Increase debug level
+ ///
+ /// May be repeated for more verbosity.
+ ///
+ /// When using syslog, one `-D` this arranges to send to syslog even
+ /// trace messages (mapped onto syslog level `DEBUG`);
+ /// and two -`D` means to send to syslog even messages from lower layers
+ /// (normally just the hippotat modules log to
+ /// syslog).
#[structopt(long, short="D", parse(from_occurrences))]
debug: usize,
+
+ /// Syslog facility to use
+ #[structopt(long, parse(try_from_str=parse_syslog_facility))]
+ syslog_facility: Option<syslog::Facility>,
+}
+
+#[throws(AE)]
+fn parse_syslog_facility(s: &str) -> syslog::Facility {
+ s.parse().map_err(|()| anyhow!("unrecognised syslog facility: {:?}", s))?
+}
+
+#[derive(Debug)]
+struct FilteringLogWrapper<T>(T);
+
+impl<T> FilteringLogWrapper<T> {
+ fn wanted(&self, md: &log::Metadata<'_>) -> bool {
+ let first = |mod_path| {
+ let mod_path: &str = mod_path; // can't do in args as breaks lifetimes
+ mod_path.split_once("::").map(|s| s.0).unwrap_or(mod_path)
+ };
+ first(md.target()) == first(module_path!())
+ }
+}
+
+impl<T> log::Log for FilteringLogWrapper<T> where T: log::Log {
+ fn enabled(&self, md: &log::Metadata<'_>) -> bool {
+ self.wanted(md) && self.0.enabled(md)
+ }
+
+ fn log(&self, record: &log::Record<'_>) {
+ if self.wanted(record.metadata()) {
+ self.0.log(record)
+ }
+ }
+
+ fn flush(&self) {
+ self.0.flush()
+ }
}
impl LogOpts {
#[throws(AE)]
pub fn log_init(&self) {
- let env = env_logger::Env::new()
- .filter("HIPPOTAT_LOG")
- .write_style("HIPPOTAT_LOG_STYLE");
+ if let Some(facility) = self.syslog_facility {
+ let f = syslog::Formatter3164 {
+ facility,
+ hostname: None,
+ process: "hippotatd".into(),
+ pid: std::process::id(),
+ };
+ let l = syslog::unix(f)
+ // syslog::Error is not Sync.
+ // https://github.com/Geal/rust-syslog/issues/65
+ .map_err(|e| anyhow!(e.to_string()))
+ .context("set up syslog logger")?;
+ let l = syslog::BasicLogger::new(l);
+ let l = if self.debug < 2 {
+ Box::new(FilteringLogWrapper(l)) as _
+ } else {
+ Box::new(l) as _
+ };
+ log::set_boxed_logger(l).context("install syslog logger")?;
+ log::set_max_level(if self.debug < 1 {
+ log::LevelFilter::Debug
+ } else {
+ log::LevelFilter::Trace
+ });
+ } else {
+ let env = env_logger::Env::new()
+ .filter("HIPPOTAT_LOG")
+ .write_style("HIPPOTAT_LOG_STYLE");
- let mut logb = env_logger::Builder::new();
- logb.filter(Some("hippotat"),
- *[ log::LevelFilter::Info,
- log::LevelFilter::Debug ]
- .get(self.debug)
- .unwrap_or(
- &log::LevelFilter::Trace
- ));
- logb.parse_env(env);
- logb.init();
+ let mut logb = env_logger::Builder::new();
+ logb.filter(Some("hippotat"),
+ *[ log::LevelFilter::Info,
+ log::LevelFilter::Debug ]
+ .get(self.debug)
+ .unwrap_or(
+ &log::LevelFilter::Trace
+ ));
+ logb.parse_env(env);
+ logb.init();
+ }
}
}