syslog_rs/formatters/
syslog_5424.rs

1/*-
2 * syslog-rs - a syslog client translated from libc to rust
3 * 
4 * Copyright 2025 Aleksandr Morozov
5 * 
6 * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
7 * the European Commission - subsequent versions of the EUPL (the "Licence").
8 * 
9 * You may not use this work except in compliance with the Licence.
10 * 
11 * You may obtain a copy of the Licence at:
12 * 
13 *    https://joinup.ec.europa.eu/software/page/eupl
14 * 
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 * Licence for the specific language governing permissions and limitations
19 * under the Licence.
20 */
21
22use std::borrow::Cow;
23
24use chrono::{Local, SecondsFormat};
25
26use crate::{socket::TapType, truncate, truncate_n, Priority, NILVALUE, WSPACE};
27
28use super::{SyslogFormatted, SyslogFormatter};
29
30
31
32#[derive(Debug, Clone)]
33pub struct FormatRfc5424;
34
35impl FormatRfc5424
36{
37    #[inline]
38    pub(crate) 
39    fn get_max_msg_length(tap_type: TapType) -> usize
40    {
41        use crate::common;
42
43        match tap_type
44        {
45            TapType::UnPriv | TapType::Priv | TapType::OldLog | TapType::CustomLog => 
46            { 
47                if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
48                {
49                    return common::MAXLINE;
50                }
51                else
52                {
53                    return *common::RFC5424_MAX_DGRAM;
54                };
55            },
56            TapType::NetTcp | TapType::NetTls => 
57                return common::RFC5424_TCP_MAX_PKT_LEN,
58            TapType::NetUdp =>
59                return common::RFC5424_UDP_MAX_PKT_LEN,
60            TapType::LocalFile =>
61                return common::MAXLINE,
62            TapType::None =>   
63                return common::MAXLINE,
64        }
65    }
66}
67
68unsafe impl Send for FormatRfc5424 {}
69
70impl SyslogFormatter for FormatRfc5424
71{
72    fn vsyslog1_format<'f>(tap_type: TapType, pri: Priority, progname: &'f str, pid: &'f str, fmt: &'f str) -> SyslogFormatted<'f>
73    {
74        // get timedate
75        let timedate = 
76            Local::now().to_rfc3339_opts(SecondsFormat::Secs, false);
77
78		let hostname: String =
79            nix::unistd::gethostname()
80                .map_or(NILVALUE.into(), |r| r.to_str().map_or(NILVALUE, |v| v).to_string());
81
82        // message based on RFC 3164
83        let msg_pri = 
84            [
85                "<", pri.bits().to_string().as_str(), ">1"
86            ]
87            .concat();
88
89		// message based on RFC 5424
90        let mut msg_pkt = 
91            [
92                // PRI 
93                Cow::Owned(msg_pri),
94                // timedate
95                Cow::Borrowed(WSPACE), Cow::Owned(timedate), 
96                // hostname
97                Cow::Borrowed(WSPACE), Cow::Owned(hostname),
98                // appname
99                Cow::Borrowed(WSPACE), Cow::Borrowed(progname), 
100                // PID
101                Cow::Borrowed(WSPACE), Cow::Borrowed(pid),
102                // message ID
103                Cow::Borrowed(WSPACE), Cow::Borrowed(NILVALUE), 
104                // structured data
105                Cow::Borrowed(WSPACE), Cow::Borrowed(NILVALUE), 
106                // msg
107                Cow::Borrowed(WSPACE), Cow::Borrowed(WSPACE), // <- msg placeholder
108                /*b"\xEF\xBB\xBF",*/
109            ]
110            .to_vec();
111
112        let msg_len = msg_pkt[..msg_pkt.len()-1].iter().map(|v| v.as_bytes().len()).sum::<usize>();
113
114        // calculate the left message space
115        let msg_space_left = Self::get_max_msg_length(tap_type) - msg_len;
116
117        let msg_payload = truncate_n(fmt, msg_space_left);
118
119        let msg_payload_final = 
120            if msg_payload.ends_with("\n") == true
121            {
122                truncate(msg_payload)
123            }
124            else
125            {
126                msg_payload
127            };
128
129        // set payload
130		msg_pkt[14] = Cow::Borrowed(msg_payload_final);
131
132        let msg_rng = msg_pkt.len();
133
134        return SyslogFormatted{ msg: msg_pkt, stderr_range: 1..msg_rng };
135    }
136}
137