aboutsummaryrefslogtreecommitdiff
path: root/src/syslog.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/syslog.rs')
-rw-r--r--src/syslog.rs73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/syslog.rs b/src/syslog.rs
new file mode 100644
index 0000000..0a12ae2
--- /dev/null
+++ b/src/syslog.rs
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CStr;
+
+use log::{self, Level, LevelFilter, Metadata, Record, SetLoggerError};
+
+static LOGGER: SyslogLogger = SyslogLogger;
+
+struct SyslogLogger;
+
+impl log::Log for SyslogLogger {
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ if cfg!(debug_assertions) {
+ metadata.level() <= Level::Debug
+ } else {
+ metadata.level() <= Level::Info
+ }
+ }
+
+ fn log(&self, record: &Record) {
+ if !self.enabled(&record.metadata()) {
+ return;
+ }
+
+ let level = match record.level() {
+ Level::Error => libc::LOG_ERR,
+ Level::Warn => libc::LOG_WARNING,
+ Level::Info => libc::LOG_INFO,
+ Level::Debug => libc::LOG_DEBUG,
+ Level::Trace => libc::LOG_DEBUG,
+ };
+
+ let msg = format!("{}\0", record.args());
+ let cmsg = if let Ok(m) = CStr::from_bytes_with_nul(msg.as_bytes()) {
+ m
+ } else {
+ // For now we just drop messages with interior nuls.
+ return;
+ };
+
+ // Safe because this doesn't modify any memory. There's not much use
+ // in checking the return value because this _is_ the logging function
+ // so there's no way for us to tell anyone about the error.
+ unsafe {
+ libc::syslog(level, cmsg.as_ptr());
+ }
+ }
+ fn flush(&self) {}
+}
+
+/// Initializes the logger to send log messages to syslog.
+pub fn init(ident: &'static CStr) -> Result<(), SetLoggerError> {
+ // Safe because this only modifies libc's internal state and is safe to call
+ // multiple times.
+ unsafe {
+ libc::openlog(
+ ident.as_ptr(),
+ libc::LOG_NDELAY | libc::LOG_PID,
+ libc::LOG_USER,
+ )
+ };
+ log::set_logger(&LOGGER)?;
+ let level = if cfg!(debug_assertions) {
+ LevelFilter::Debug
+ } else {
+ LevelFilter::Info
+ };
+ log::set_max_level(level);
+
+ Ok(())
+}