1#![forbid(unsafe_code)]
2
3use std;
4
5use libc;
6use log;
7use log4rs;
8use syslog;
9
10#[derive(Deserialize)]
11struct SyslogAppenderOpenlogConfig {
12 ident: String,
13 option: syslog::LogOption,
14 facility: syslog::Facility,
15}
16
17#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize)]
18#[allow(non_camel_case_types)]
19enum FakeLibcLogLevel {
20 LOG_EMERG,
21 LOG_ALERT,
22 LOG_CRIT,
23 LOG_ERR,
24 LOG_WARNING,
25 LOG_NOTICE,
26 LOG_INFO,
27 LOG_DEBUG,
28}
29
30type LevelMapConf = std::collections::BTreeMap<log::Level, FakeLibcLogLevel>;
31
32#[derive(Deserialize)]
33struct SyslogAppenderConfig {
34 openlog: Option<SyslogAppenderOpenlogConfig>,
35 encoder: Option<log4rs::encode::EncoderConfig>,
36 level_map: Option<LevelMapConf>,
37}
38
39struct SyslogAppenderDeserializer;
40
41impl log4rs::file::Deserialize for SyslogAppenderDeserializer {
42 type Trait = log4rs::append::Append;
43 type Config = SyslogAppenderConfig;
44
45 fn deserialize(
46 &self,
47 config: Self::Config,
48 deserializers: &log4rs::file::Deserializers,
49 ) -> Result<Box<Self::Trait>, Box<std::error::Error + Sync + Send>> {
50 let mut builder = syslog::SyslogAppender::builder();
51
52 if let Some(openlog_conf) = config.openlog {
53 builder = builder.openlog(
54 &openlog_conf.ident,
55 openlog_conf.option,
56 openlog_conf.facility,
57 );
58 };
59
60 if let Some(encoder_conf) = config.encoder {
61 builder = builder.encoder(deserializers.deserialize(&encoder_conf.kind, encoder_conf.config)?);
62 }
63
64 if let Some(level_map) = config.level_map {
65 let mut map = std::collections::BTreeMap::new();
66 for (level, libc_level) in level_map {
67 let libc_level = match libc_level {
68 FakeLibcLogLevel::LOG_EMERG => libc::LOG_EMERG,
69 FakeLibcLogLevel::LOG_ALERT => libc::LOG_ALERT,
70 FakeLibcLogLevel::LOG_CRIT => libc::LOG_CRIT,
71 FakeLibcLogLevel::LOG_ERR => libc::LOG_ERR,
72 FakeLibcLogLevel::LOG_WARNING => libc::LOG_WARNING,
73 FakeLibcLogLevel::LOG_NOTICE => libc::LOG_NOTICE,
74 FakeLibcLogLevel::LOG_INFO => libc::LOG_INFO,
75 FakeLibcLogLevel::LOG_DEBUG => libc::LOG_DEBUG,
76 };
77 let _ = map.insert(level, libc_level);
78 }
79
80 for level in &[
81 log::Level::Error,
82 log::Level::Warn,
83 log::Level::Info,
84 log::Level::Debug,
85 log::Level::Trace,
86 ] {
87 let _ = map.get(level)
88 .ok_or_else(|| format!("Log level missing in map: {:?}", level))?;
89 }
90
91 builder = builder.level_map(Box::new(move |l| map[&l]));
92 }
93
94 Ok(Box::new(builder.build()))
95 }
96}
97
98pub fn register(deserializers: &mut log4rs::file::Deserializers) {
113 deserializers.insert("libc-syslog", SyslogAppenderDeserializer);
114}