syslog5424/
types.rs

1//! Types used to specify values in a RFC5424 message
2
3use {Error, NILVALUE};
4
5/// Syslog facility
6///
7/// * [Definition in RFC5424 Section 6.2.1](https://tools.ietf.org/html/rfc5424#section-6.2.1)
8#[derive(Debug, Clone, Copy)]
9pub enum Facility {
10    Kernel = 0,
11    User = 1,
12    Mail = 2,
13    Daemon = 3,
14    Auth = 4,
15    Syslog = 5,
16    LinePrinter = 6,
17    News = 7,
18    UUCP = 8,
19    Cron = 9,
20    AuthPriv = 10,
21    FTP = 11,
22    NTP = 12,
23    Security = 13,
24    Console = 14,
25    ClockDaemon = 15,
26    Local0 = 16,
27    Local1 = 17,
28    Local2 = 18,
29    Local3 = 19,
30    Local4 = 20,
31    Local5 = 21,
32    Local6 = 22,
33    Local7 = 23,
34}
35
36impl Default for Facility {
37    fn default() -> Facility {
38        Facility::User
39    }
40}
41
42/// Syslog severity
43///
44/// * [Definition in RFC5424 Section 6.2.1](https://tools.ietf.org/html/rfc5424#section-6.2.1)
45/// * [Severity Values A.3.](https://tools.ietf.org/html/rfc5424#appendix-A.3)
46#[derive(Debug, Clone, Copy)]
47pub enum Severity {
48    Emergency = 0,
49    Alert = 1,
50    Critical = 2,
51    Error = 3,
52    Warning = 4,
53    Notice = 5,
54    Informational = 6,
55    Debug = 7,
56}
57
58/// The message portion of a syslog message may be either UTF-8 or
59/// binary.
60#[derive(Debug, Clone)]
61pub enum Message {
62    Text(String),
63    Binary(Vec<u8>),
64}
65
66/// Wrapper for `String` containing the Host Name. Limited to 255 ASCII chars.
67#[derive(Debug)]
68pub struct HostName(pub String);
69impl HostName {
70    pub fn new(hostname: &str) -> Result<HostName, Error> {
71        Ok(HostName(new_header_val(hostname, 255)?))
72    }
73}
74
75impl Default for HostName {
76    fn default() -> HostName {
77        HostName(format!("{}", NILVALUE))
78    }
79}
80
81/// Wrapper for `String` containing the App Name. Limited to 48 ASCII chars.
82#[derive(Debug)]
83pub struct AppName(pub String);
84impl AppName {
85    pub fn new(name: &str) -> Result<AppName, Error> {
86        Ok(AppName(new_header_val(name, 48)?))
87    }
88}
89
90impl Default for AppName {
91    fn default() -> AppName {
92        AppName(format!("{}", NILVALUE))
93    }
94}
95
96/// Wrapper for `String` containing the Process ID. Limited to 128 ASCII chars.
97#[derive(Debug)]
98pub struct ProcessId(pub String);
99impl ProcessId {
100    pub fn new(id: &str) -> Result<ProcessId, Error> {
101        Ok(ProcessId(new_header_val(id, 128)?))
102    }
103}
104
105impl Default for ProcessId {
106    fn default() -> ProcessId {
107        ProcessId(format!("{}", NILVALUE))
108    }
109}
110
111/// Wrapper for `String` containing the Message ID. Limited to 32 ASCII chars.
112#[derive(Debug)]
113pub struct MessageId(pub String);
114impl MessageId {
115    pub fn new(id: &str) -> Result<MessageId, Error> {
116        Ok(MessageId(new_header_val(id, 32)?))
117    }
118}
119
120impl Default for MessageId {
121    fn default() -> MessageId {
122        MessageId(format!("{}", NILVALUE))
123    }
124}
125
126/// Convert a string into a header value after verifying it is valid.
127///
128/// # Errors
129/// * `value`'s length is larger than `max_length`
130/// * `value` is an empty string
131/// * `value` doesn't contain printable ASCII characters (see `char::is_ascii_graphic`)
132fn new_header_val(value: &str, max_length: usize) -> Result<String, Error> {
133    if value.is_empty() {
134        return Err(Error::FieldEmpty);
135    }
136    if !value.chars().all(|x| x.is_ascii_graphic()) {
137        return Err(Error::InvalidCharacters);
138    }
139    if value.len() > max_length {
140        return Err(Error::FieldTooLong);
141    }
142    Ok(value.to_string())
143}
144
145/// Escape the `val` parameter according to PARAM-VALUE rule from RFC5424.
146#[inline]
147pub fn escape_val(val: &str) -> String {
148    val.replace('\\', r#"\\"#)
149        .replace('"', r#"\""#)
150        .replace(']', r#"\]"#)
151}
152
153/// Remove invalid characters from `name`. Used for values in PARAM-NAME
154/// and SD-ID from RFC5424. Removes `'=', ' ', ']', '"'`, and non-printable
155/// ASCII characters. The filtered message is then truncated to 32 characters.
156#[inline]
157pub fn remove_invalid(name: &str) -> String {
158    name.chars()
159        .filter(char::is_ascii_graphic)
160        .filter(|c| *c != '=')
161        .filter(|c| *c != ' ')
162        .filter(|c| *c != ']')
163        .filter(|c| *c != '"')
164        .take(32)
165        .collect()
166}