| // Copyright 2018 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| use std::env; | |
| pub use log::LevelFilter; | |
| use log::SetLoggerError; | |
| use nix::unistd::getpid; | |
| use stderrlog::StdErrLog; | |
| use syslog::{BasicLogger, Facility, Formatter3164}; | |
| #[derive(Debug, thiserror::Error)] | |
| pub enum Error { | |
| #[error("unix socket syslog setup failed: {0}")] | |
| SyslogUnix(#[source] syslog::Error), | |
| #[error("failed to set logger: {0}")] | |
| SetLoggerError(#[source] SetLoggerError), | |
| } | |
| pub type Result<T> = std::result::Result<T, Error>; | |
| /// Get an identifier to be used with init(...) from the current process. | |
| pub fn get_ident_from_process() -> Option<String> { | |
| env::current_exe() | |
| .map(|p| p.file_name().map(|n| n.to_string_lossy().to_string())) | |
| .unwrap_or(None) | |
| } | |
| /// Get the default syslog-based logger. | |
| pub fn get_syslog_logger(ident: String) -> Result<BasicLogger> { | |
| Ok(BasicLogger::new( | |
| syslog::unix(Formatter3164 { | |
| facility: Facility::LOG_USER, | |
| hostname: None, | |
| pid: getpid().as_raw() as u32, | |
| process: ident, | |
| }) | |
| .map_err(Error::SyslogUnix)?, | |
| )) | |
| } | |
| /// Initialize logging to the system log and stderr if |log_to_stderr| is true. | |
| /// | |
| /// Before logging is initialized eprintln(...) and println(...) should be | |
| /// used. Afterward, debug!(...), info!(...), warn!(....), and error!(...) | |
| /// should be used instead. | |
| pub fn init(ident: String, log_to_stderr: bool) -> Result<()> { | |
| init_with_level(ident, log_to_stderr, LevelFilter::Info) | |
| } | |
| pub fn init_with_level(ident: String, log_to_stderr: bool, max_level: LevelFilter) -> Result<()> { | |
| let syslog_logger = Box::new(get_syslog_logger(ident)?); | |
| if log_to_stderr { | |
| let mut stderr_logger = StdErrLog::new(); | |
| stderr_logger.verbosity(max_level as usize); | |
| if let Some(level) = max_level.to_level() { | |
| multi_log::MultiLogger::init(vec![Box::new(stderr_logger), syslog_logger], level) | |
| } else { | |
| // When max_level is LevelFilter::Off, max_level.to_level() returns | |
| // None. In this case, we don't need to initialize MultiLogger. | |
| Ok(()) | |
| } | |
| } else { | |
| log::set_boxed_logger(syslog_logger).map(|()| log::set_max_level(max_level)) | |
| } | |
| .map_err(Error::SetLoggerError) | |
| } |