chiark / gitweb /
syslog: Add syslog support
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 18 Sep 2022 18:01:49 +0000 (19:01 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Sep 2022 11:04:46 +0000 (12:04 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock
Cargo.toml
src/reporter.rs

index 79c9711001963bde12cb11d7ba792338ab0636e9..d2a14c21010bbb8d7c2ff3bca7a76ae6073727d4 100644 (file)
@@ -180,6 +180,15 @@ dependencies = [
  "termcolor",
 ]
 
+[[package]]
+name = "error-chain"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
+dependencies = [
+ "version_check",
+]
+
 [[package]]
 name = "extend"
 version = "1.1.1"
@@ -437,6 +446,7 @@ dependencies = [
  "sha2",
  "structopt",
  "subtle",
+ "syslog",
  "thiserror",
  "tokio",
  "void",
@@ -452,6 +462,17 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "hostname"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
+dependencies = [
+ "libc",
+ "match_cfg",
+ "winapi",
+]
+
 [[package]]
 name = "http"
 version = "0.2.4"
@@ -460,7 +481,7 @@ checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
 dependencies = [
  "bytes",
  "fnv",
- "itoa",
+ "itoa 0.4.7",
 ]
 
 [[package]]
@@ -507,7 +528,7 @@ dependencies = [
  "http-body",
  "httparse",
  "httpdate",
- "itoa",
+ "itoa 0.4.7",
  "pin-project-lite",
  "socket2",
  "tokio",
@@ -575,6 +596,12 @@ version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
 
+[[package]]
+name = "itoa"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+
 [[package]]
 name = "lazy-regex"
 version = "2.2.1"
@@ -606,9 +633,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.98"
+version = "0.2.132"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
+checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
 
 [[package]]
 name = "lock_api"
@@ -628,6 +655,12 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "match_cfg"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
+
 [[package]]
 name = "memchr"
 version = "2.4.0"
@@ -709,6 +742,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "num_threads"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "object"
 version = "0.26.0"
@@ -1077,6 +1119,19 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "syslog"
+version = "6.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "978044cc68150ad5e40083c9f6a725e6fd02d7ba1bcf691ec2ff0d66c0b41acc"
+dependencies = [
+ "error-chain",
+ "hostname",
+ "libc",
+ "log",
+ "time",
+]
+
 [[package]]
 name = "tempfile"
 version = "3.2.0"
@@ -1129,6 +1184,17 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "time"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b"
+dependencies = [
+ "itoa 1.0.3",
+ "libc",
+ "num_threads",
+]
+
 [[package]]
 name = "tokio"
 version = "1.8.2"
index e6c0659bc93cee2c575a947cfba3055197168dec..2d6289b98eecc822db6c6611b4d6deb242402916 100644 (file)
@@ -46,6 +46,7 @@ pin-project-lite = "0.2"
 sha2 = "0.9"
 structopt = "0.3"
 subtle = "2"
+syslog = "6"
 tokio = { version = "1", features = ["full"] }
 thiserror = "1"
 void = "1"
index 6f4fb0d4cb17f073391dc171aea8d7e4520b015e..49c26a2f5fbced321209b31eed66494b94fb0e63 100644 (file)
@@ -7,27 +7,99 @@ use crate::prelude::*;
 #[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();
+    }
   }
 }