log4rs_syslog/
file.rs

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
98/// Register deserializer for creating syslog appender based on log4rs configuration file.
99///
100/// See `./examples/from_conf.rs` for full example.
101///
102/// # Examples
103///
104/// ```
105/// extern crate log4rs;
106/// extern crate log4rs_syslog;
107///
108/// let mut deserializers = log4rs::file::Deserializers::new();
109/// log4rs_syslog::register(&mut deserializers);
110/// let result = log4rs::init_file("/path/to/log-conf.yaml", deserializers);
111/// ```
112pub fn register(deserializers: &mut log4rs::file::Deserializers) {
113    deserializers.insert("libc-syslog", SyslogAppenderDeserializer);
114}