Browse Source

Send logs to syslog

pull/5/head
Rodolphe Breard 6 years ago
parent
commit
ff9bdb3491
  1. 2
      CHANGELOG.md
  2. 1
      acmed/Cargo.toml
  3. 7
      acmed/src/errors.rs
  4. 79
      acmed/src/logs.rs
  5. 46
      acmed/src/main.rs

2
CHANGELOG.md

@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `kp_reuse` flag allow to reuse a key pair instead of creating a new one at each renewal.
- It is now possible to define hook groups that can reference either hooks or other hook groups.
- Hooks can be defined when before and after a file is created or edited (`file_pre_create_hooks`, `file_post_create_hooks`, `file_pre_edit_hooks` and `file_post_edit_hooks`).
- It is now possible to send logs either to syslog or stderr using the `--to-syslog` and `--to-stderr` arguments.
### Changed
- `post_operation_hook` has been renamed `post_operation_hooks`.
- By default, logs are now sent to syslog instead of stderr.

1
acmed/Cargo.toml

@ -19,6 +19,7 @@ log = "0.4"
openssl = "0.10"
pem = "0.5"
serde = { version = "1.0", features = ["derive"] }
syslog = "4.0"
time = "0.1"
toml = "0.5"
x509-parser = "0.4"

7
acmed/src/errors.rs

@ -1,5 +1,6 @@
use std::fmt;
#[derive(Debug)]
pub struct Error {
pub message: String,
}
@ -30,6 +31,12 @@ impl From<&str> for Error {
}
}
impl From<syslog::Error> for Error {
fn from(error: syslog::Error) -> Self {
Error::new(&format!("syslog error: {}", error))
}
}
impl From<toml::de::Error> for Error {
fn from(error: toml::de::Error) -> Self {
Error::new(&format!("IO error: {}", error))

79
acmed/src/logs.rs

@ -0,0 +1,79 @@
use crate::errors::Error;
use env_logger::Builder;
use log::LevelFilter;
use syslog::Facility;
#[derive(Debug, PartialEq, Eq)]
pub enum LogSystem {
SysLog,
StdErr,
}
fn get_loglevel(log_level: Option<&str>) -> Result<LevelFilter, Error> {
let level = match log_level {
Some(v) => match v {
"error" => LevelFilter::Error,
"warn" => LevelFilter::Warn,
"info" => LevelFilter::Info,
"debug" => LevelFilter::Debug,
"trace" => LevelFilter::Trace,
_ => {
return Err(Error::new(&format!("{}: invalid log level", v)));
}
},
None => crate::DEFAULT_LOG_LEVEL,
};
Ok(level)
}
fn set_log_syslog(log_level: LevelFilter) -> Result<(), Error> {
syslog::init(Facility::LOG_DAEMON, log_level, Some(crate::APP_NAME))?;
Ok(())
}
fn set_log_stderr(log_level: LevelFilter) -> Result<(), Error> {
let mut builder = Builder::from_env("ACMED_LOG_LEVEL");
builder.filter_level(log_level);
builder.init();
Ok(())
}
pub fn set_log_system(
log_level: Option<&str>,
has_syslog: bool,
has_stderr: bool,
) -> Result<(LogSystem, LevelFilter), Error> {
let log_level = get_loglevel(log_level)?;
let mut logtype = crate::DEFAULT_LOG_SYSTEM;
if has_stderr {
logtype = LogSystem::StdErr;
}
if has_syslog {
logtype = LogSystem::SysLog;
}
match logtype {
LogSystem::SysLog => set_log_syslog(log_level)?,
LogSystem::StdErr => set_log_stderr(log_level)?,
};
Ok((logtype, log_level))
}
#[cfg(test)]
mod tests {
use super::set_log_system;
#[test]
fn test_invalid_level() {
let ret = set_log_system(Some("invalid"), false, false);
assert!(ret.is_err());
}
#[test]
fn test_default_values() {
let ret = set_log_system(None, false, false);
assert!(ret.is_ok());
let (logtype, log_level) = ret.unwrap();
assert_eq!(logtype, crate::DEFAULT_LOG_SYSTEM);
assert_eq!(log_level, crate::DEFAULT_LOG_LEVEL);
}
}

46
acmed/src/main.rs

@ -1,5 +1,4 @@
use clap::{App, Arg};
use env_logger::Builder;
use log::{error, LevelFilter};
mod acmed;
@ -7,8 +6,10 @@ mod config;
mod encoding;
mod errors;
mod hooks;
mod logs;
mod storage;
pub const APP_NAME: &str = "acmed";
pub const DEFAULT_CONFIG_FILE: &str = "/etc/acmed/acmed.toml";
pub const DEFAULT_ACCOUNTS_DIR: &str = "/etc/acmed/accounts";
pub const DEFAULT_CERT_DIR: &str = "/etc/acmed/certs";
@ -20,6 +21,8 @@ pub const DEFAULT_POOL_TIME: u64 = 5000;
pub const DEFAULT_CERT_FILE_MODE: u32 = 0o644;
pub const DEFAULT_PK_FILE_MODE: u32 = 0o600;
pub const DEFAULT_KP_REUSE: bool = false;
pub const DEFAULT_LOG_SYSTEM: logs::LogSystem = logs::LogSystem::SysLog;
pub const DEFAULT_LOG_LEVEL: LevelFilter = LevelFilter::Warn;
fn main() {
let matches = App::new("acmed")
@ -40,30 +43,31 @@ fn main() {
.value_name("LEVEL")
.possible_values(&["error", "warn", "info", "debug", "trace"]),
)
.arg(
Arg::with_name("to-syslog")
.long("log-syslog")
.help("Send log messages via syslog.")
.conflicts_with("to-stderr"),
)
.arg(
Arg::with_name("to-stderr")
.long("log-stderr")
.help("Print log messages to the standard error output.")
.conflicts_with("log-syslog"),
)
.get_matches();
let mut builder = Builder::from_env("ACMED_LOG_LEVEL");
if let Some(v) = matches.value_of("log-level") {
match v {
"error" => {
builder.filter_level(LevelFilter::Error);
}
"warn" => {
builder.filter_level(LevelFilter::Warn);
}
"info" => {
builder.filter_level(LevelFilter::Info);
}
"debug" => {
builder.filter_level(LevelFilter::Debug);
}
"trace" => {
builder.filter_level(LevelFilter::Trace);
}
_ => {}
match logs::set_log_system(
matches.value_of("log-level"),
matches.is_present("log-syslog"),
matches.is_present("to-stderr"),
) {
Ok(_) => {}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
};
builder.init();
let config_file = matches.value_of("config").unwrap_or(DEFAULT_CONFIG_FILE);
let mut srv = match acmed::Acmed::new(&config_file) {

Loading…
Cancel
Save