1 use crate::pri::{compose_pri, SyslogFacility, SyslogSeverity};
2 use crate::structured_data;
3 use crate::procid::ProcId;
4 use chrono::prelude::*;
5 use std::fmt;
6 
7 
8 #[derive(Clone, Debug, PartialEq, Eq)]
9 pub enum Protocol {
10     RFC3164,
11     RFC5424(u32),
12 }
13 
14 #[derive(Clone, Debug)]
15 pub struct Message<S: AsRef<str> + Ord + PartialEq + Clone> {
16     pub protocol: Protocol,
17     pub facility: Option<SyslogFacility>,
18     pub severity: Option<SyslogSeverity>,
19     pub timestamp: Option<DateTime<FixedOffset>>,
20     pub hostname: Option<S>,
21     pub appname: Option<S>,
22     pub procid: Option<ProcId<S>>,
23     pub msgid: Option<S>,
24     pub structured_data: Vec<structured_data::StructuredElement<S>>,
25     pub msg: S,
26 }
27 
28 impl<S: AsRef<str> + Ord + PartialEq + Clone> fmt::Display for Message<S> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result29     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30         let empty = "-".to_string();
31 
32         write!(
33             f,
34             "<{}>{} {} {} ",
35             compose_pri(
36                 self.facility.unwrap_or(SyslogFacility::LOG_SYSLOG),
37                 self.severity.unwrap_or(SyslogSeverity::SEV_DEBUG)
38             ),
39             match self.protocol {
40                 Protocol::RFC3164 => "".to_string(),
41                 Protocol::RFC5424(version) => version.to_string()
42             },
43             self.timestamp.unwrap_or(Utc::now().into()).to_rfc3339(),
44             self.hostname
45                 .as_ref()
46                 .map(|s| s.as_ref())
47                 .unwrap_or(&empty)
48         )?;
49 
50         match self.protocol {
51             Protocol::RFC5424(_) => {
52                 write!(f, "{} ", self.appname
53                        .as_ref()
54                        .map(|s| s.as_ref())
55                        .unwrap_or(&empty))?;
56                 match &self.procid {
57                     None => write!(f, "- ")?,
58                     Some(procid) => write!(f, "{} ", procid)?,
59                 };
60             }
61             Protocol::RFC3164 =>
62                 match (&self.appname, &self.procid) {
63                     (Some(appname), Some(procid)) =>
64                         write!(f, "{}[{}]: ", appname.as_ref(), procid)?,
65                      (Some(appname), None) =>
66                         write!(f, "{}: ", appname.as_ref())?,
67                     _ =>
68                         write!(f, ": ")?,
69                 }
70         }
71 
72 
73         if let Protocol::RFC5424(_) = self.protocol {
74             write!(f, "{} ", self.msgid
75                    .as_ref()
76                    .map(|s| s.as_ref())
77                    .unwrap_or(&empty))?;
78         }
79 
80         if self.structured_data.len() == 0 {
81             if let Protocol::RFC5424(_) = self.protocol {
82                 write!(f, "- ")?;
83             }
84         } else {
85             for elem in &self.structured_data {
86                 write!(f, "{}", elem)?;
87             }
88             write!(f, " ")?;
89         }
90 
91         write!(f, "{}", self.msg.as_ref())
92     }
93 }
94 
95 impl<S: AsRef<str> + Ord + Clone> PartialEq for Message<S> {
eq(&self, other: &Self) -> bool96     fn eq(&self, other: &Self) -> bool {
97         self.facility == other.facility
98             && self.severity == other.severity
99             && self.timestamp == other.timestamp
100             && self.hostname == other.hostname
101             && self.appname == other.appname
102             && self.procid == other.procid
103             && self.msgid == other.msgid
104             && self.structured_data == other.structured_data
105             && self.msg == other.msg
106     }
107 }
108 
109 impl From<Message<&str>> for Message<String> {
from(message: Message<&str>) -> Self110     fn from(message: Message<&str>) -> Self {
111         Message {
112             facility: message.facility,
113             severity: message.severity,
114             timestamp: message.timestamp,
115             hostname: message.hostname.map(|s| s.to_string()),
116             appname: message.appname.map(|s| s.to_string()),
117             procid: message.procid.map(|s| s.into()),
118             msgid: message.msgid.map(|s| s.to_string()),
119             protocol: message.protocol,
120             structured_data: message
121                 .structured_data
122                 .iter()
123                 .map(|e| e.clone().into())
124                 .collect(),
125             msg: message.msg.to_string(),
126         }
127     }
128 }
129 
130 
131 
132