syslog_client/
log04.rs

1//!Implementation for `log` crate interface
2
3use log04::{kv, Log, Metadata, Record, Level, max_level, STATIC_MAX_LEVEL};
4
5use crate::{writer, Writer, Syslog, Severity, Rfc3164Buffer, Rfc3164RecordWriter};
6
7use core::fmt;
8
9///Syslog with log interface
10///
11///When [key values](https://docs.rs/log/0.4.22/log/struct.Record.html#method.key_values) is
12///available appends it after message in format of [KV [<key>=<value>]...]
13pub struct Rfc3164Logger<W> {
14    syslog: Syslog,
15    writer: W,
16}
17
18impl<W> Rfc3164Logger<W> {
19    ///Creates new instance
20    pub const fn new(syslog: Syslog, writer: W) -> Self {
21        Self {
22            syslog,
23            writer,
24        }
25    }
26}
27
28impl From<Level> for Severity {
29    #[inline(always)]
30    fn from(level: Level) -> Self {
31        match level {
32            Level::Error => Self::LOG_ERR,
33            Level::Warn => Self::LOG_WARNING,
34            Level::Info => Self::LOG_NOTICE,
35            Level::Debug => Self::LOG_INFO,
36            Level::Trace => Self::LOG_DEBUG,
37        }
38    }
39}
40
41impl<W: Sync + Send + writer::MakeTransport> Log for Rfc3164Logger<W> where W::Transport: Sync + Send {
42    #[inline(always)]
43    fn enabled(&self, metadata: &Metadata) -> bool {
44        metadata.level() <= max_level() && metadata.level() <= STATIC_MAX_LEVEL
45    }
46
47    #[inline]
48    fn log(&self, record: &Record) {
49        let level = record.level().into();
50        let args = record.args();
51
52        let mut writer = Writer::new(&self.writer);
53        let mut buffer = Rfc3164Buffer::new();
54        let mut syslog = self.syslog.rfc3164_record(&mut writer, &mut buffer, level);
55        if let Some(log) = args.as_str() {
56            if syslog.write_str(log).is_err() {
57                return;
58            }
59        } else {
60            if fmt::Write::write_fmt(&mut syslog, *args).is_err() {
61                return;
62            }
63        }
64
65        //Visitor will do final flush
66        let mut key_values_writer = StructuredVisitor {
67            record: syslog,
68            //no key values written unless visit() is called
69            is_written: false,
70        };
71
72        if record.key_values().visit(&mut key_values_writer).is_err() {
73            return;
74        }
75    }
76
77    #[inline(always)]
78    fn flush(&self) {
79    }
80}
81
82#[cold]
83#[inline(never)]
84fn unlikely_write_error() -> kv::Error {
85    kv::Error::msg("Logger unable to flush")
86}
87
88struct StructuredVisitor<'a, W: writer::MakeTransport> {
89    record: Rfc3164RecordWriter<'a, W>,
90    is_written: bool,
91}
92
93impl<'a, W: Sync + Send + writer::MakeTransport> kv::VisitSource<'_> for StructuredVisitor<'a, W> {
94    #[inline(always)]
95    fn visit_pair(&mut self, key: kv::Key<'_>, value: kv::Value<'_>) -> Result<(), kv::Error> {
96        if !self.is_written {
97            if self.record.write_str(" [KV").is_err() {
98                return Err(unlikely_write_error());
99            }
100
101            self.is_written = true;
102        }
103
104        if fmt::Write::write_fmt(&mut self.record, format_args!(" {key}={value}")).is_err() {
105            return Err(unlikely_write_error());
106        }
107
108        Ok(())
109    }
110}
111
112impl<'a, W: writer::MakeTransport> Drop for StructuredVisitor<'a, W> {
113    #[inline(always)]
114    fn drop(&mut self) {
115        if self.is_written {
116            let _ = self.record.write_str("]");
117        }
118        let _ = self.record.flush_without_clear();
119    }
120}