syslog_rs/sync/
syslog_sync_shared.rs

1/*-
2 * syslog-rs - a syslog client translated from libc to rust
3 * 
4 * Copyright 2025 Aleksandr Morozov
5 * 
6 * The syslog-rs crate can be redistributed and/or modified
7 * under the terms of either of the following licenses:
8 *
9 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
10 *                     
11 *   2. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
12 */
13
14use std::marker::PhantomData;
15use std::{str, sync::Arc};
16
17
18use std::sync::Mutex;
19
20use crate::formatters::DefaultSyslogFormatter;
21use crate::{formatters::SyslogFormatter, map_error_code};
22use crate::{common::*, SyslogDestination, SyslogLocal};
23use crate::error::SyRes;
24
25use super::{syslog_trait::SyslogApi, StreamableSyslog, syslog_sync_internal::SyncSyslogInternal, StreamableSyslogApi, SyslogStream};
26
27
28/// A single instance shared between all threads. A [Mutex] is used to 
29/// guard the instance.
30/// 
31/// For this isntance a [SyslogApi] and [StreamableSyslogApi] are implemented.
32/// 
33/// # Generics
34/// 
35/// * `F` - a [SyslogFormatter] which sets the instance which would 
36///     format the message.
37/// 
38/// * `D` - a [SyslogDestination] instance which is either:
39///     [SyslogLocal], [SyslogFile], [SyslogNet], [SyslogTls]. By
40///     default a `SyslogLocal` is selected.
41#[derive(Debug, Clone)]
42pub struct SyslogShared<F: SyslogFormatter = DefaultSyslogFormatter, D: SyslogDestination = SyslogLocal>
43{   
44    /// A giantly locked syslog data
45    inner: Arc<Mutex<SyncSyslogInternal<F, D>>>,
46}
47
48unsafe impl<F: SyslogFormatter, D: SyslogDestination> Send for SyslogShared<F, D> {}
49unsafe impl<F: SyslogFormatter, D: SyslogDestination> Sync for SyslogShared<F, D> {}
50
51impl SyslogShared
52{
53    /// Opens a default connection to the local syslog server with default formatter.
54    /// 
55    /// In order to access the syslog API, use the [SyslogApi].
56    /// 
57    /// # Arguments
58    /// 
59    /// * `ident` - A program name which will appear on the logs. If none, will be determined
60    ///     automatically.
61    /// 
62    /// * `logstat` - [LogStat] an instance config.
63    /// 
64    /// * `facility` - [LogFacility] a syslog facility.
65    /// 
66    /// * `net_tap_prov` - a [SyslogLocal] instance with configuration.
67    /// 
68    /// # Returns
69    /// 
70    /// A [SyRes] is returned ([Result]) with: 
71    /// 
72    /// * [Result::Ok] - with instance
73    /// 
74    /// * [Result::Err] - with error description.
75    pub 
76    fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: SyslogLocal) -> SyRes<Self> 
77    {
78        let mut syslog = 
79            SyncSyslogInternal::<DefaultSyslogFormatter, SyslogLocal>::new(ident, logstat, facility, net_tap_prov)?;
80       
81        if logstat.contains(LogStat::LOG_NDELAY) == true
82        {
83            syslog.connectlog()?;
84        }
85
86        return Ok( 
87            Self
88            {
89                inner: Arc::new(Mutex::new(syslog)),
90            }
91        );
92    }
93}
94
95impl<F: SyslogFormatter, D: SyslogDestination> SyslogShared<F, D>
96{
97    /// Opens a special connection to the destination syslog server with specific formatter.
98    /// 
99    /// All struct generic should be specified before calling this function.
100    /// 
101    /// In order to access the syslog API, use the [SyslogApi].
102    /// 
103    /// # Arguments
104    /// 
105    /// * `ident` - A program name which will appear on the logs. If none, will be determined
106    ///     automatically.
107    /// 
108    /// * `logstat` - [LogStat] an instance config.
109    /// 
110    /// * `facility` - [LogFacility] a syslog facility.
111    /// 
112    /// * `net_tap_prov` - a destination server. A specific `D` instance which contains infomation 
113    ///     about the destination server. See `syslog_provider.rs`.
114    /// 
115    /// # Returns
116    /// 
117    /// A [SyRes] is returned ([Result]) with: 
118    /// 
119    /// * [Result::Ok] - with instance
120    /// 
121    /// * [Result::Err] - with error description.
122    pub 
123    fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<SyslogShared<F, D>> 
124    {
125        let mut syslog = 
126            SyncSyslogInternal::<F, D>::new(ident, logstat, facility, net_tap_prov)?;
127       
128        if logstat.contains(LogStat::LOG_NDELAY) == true
129        {
130            syslog.connectlog()?;
131        }
132
133        return Ok( 
134            Self
135            {
136                inner: Arc::new(Mutex::new(syslog)),
137            }
138        );
139    }
140}
141
142impl<F: SyslogFormatter, D: SyslogDestination> StreamableSyslogApi<D, F, SyslogShared<F, D>> 
143for SyslogShared<F, D>
144{
145    fn make_stream(&self, pri: Priority) -> Box<dyn SyslogStream> 
146    {
147        let inst = 
148            StreamableSyslog
149            {
150                inner: self.clone(),
151                pri: pri,
152                _p: PhantomData::<F>,
153                _p1: PhantomData::<D>,
154
155            };
156
157        return Box::new(inst);
158    }
159}
160
161
162impl<F: SyslogFormatter, D: SyslogDestination> SyslogApi<F, D> for SyslogShared<F, D>
163{
164    fn connectlog(&self) -> SyRes<()>
165    {
166        return 
167            self
168                .inner
169                .lock()
170                .map_err(|e| 
171                    map_error_code!(MutexPoisoned, "{}", e)
172                )?
173                .connectlog();
174    }
175
176    fn setlogmask(&self, logmask: i32) -> SyRes<i32> 
177    {
178        let pri = 
179            self
180                .inner
181                .lock()
182                .map_err(|e| 
183                    map_error_code!(MutexPoisoned, "{}", e)
184                )?
185                .set_logmask(logmask);
186
187        return Ok(pri);
188    }
189
190    fn closelog(&self) -> SyRes<()> 
191    {
192        return 
193            self
194                .inner
195                .lock()
196                .map_err(|e| 
197                    map_error_code!(MutexPoisoned, "{}", e)
198                )?
199                .disconnectlog();
200    }
201
202    #[inline]
203    fn syslog(&self, pri: Priority, fmt: F) 
204    {
205        if let Ok(mut inner) = self.inner.lock()
206        {
207            inner.vsyslog1(pri, &fmt)
208        }
209
210        return;
211    }
212
213    /// This function can be used to update the facility name, for example
214    /// after fork().
215    /// 
216    /// # Arguments
217    /// 
218    /// * `ident` - a new identity (up to 48 UTF8 chars)
219    fn change_identity(&self, ident: &str) -> SyRes<()>
220    {
221        self
222            .inner
223            .lock()
224            .map_err(|e| 
225                map_error_code!(MutexPoisoned, "{}", e)
226            )?
227            .set_logtag(ident, true);
228
229        return Ok(());
230    }
231
232    fn reconnect(&self) -> SyRes<()>
233    {
234        let mut lock = 
235            self
236                .inner
237                .lock()
238                .map_err(|e| 
239                    map_error_code!(MutexPoisoned, "{}", e)
240                )?;
241
242        
243        lock.disconnectlog()?;
244
245        lock.connectlog()?;
246            
247        return Ok(());
248    }
249
250    fn update_tap_data(&self, tap_data: D) -> SyRes<()>
251    {
252        let mut lock = 
253            self
254                .inner
255                .lock()
256                .map_err(|e| 
257                    map_error_code!(MutexPoisoned, "{}", e)
258                )?;
259
260        return lock.update_tap_data(tap_data);
261    }
262
263}
264