1use 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
9pub struct Rfc3164Logger<W> {
14 syslog: Syslog,
15 writer: W,
16}
17
18impl<W> Rfc3164Logger<W> {
19 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 let mut key_values_writer = StructuredVisitor {
67 record: syslog,
68 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}