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