syslog_rs/sync/syslog_threadlocal.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. The MIT License (MIT)
12 *
13 * 3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
14 */
15
16use std::{marker::PhantomData};
17
18use crate::{
19 LogFacility, LogStat, Priority, SyslogDestination, error::SyRes,
20 formatters::{DefaultSyslogFormatter, SyslogFormatter},
21 sync::
22 {
23 LogItems, SyStream, SyStreamPri, syslog_stream::SyStreamSyslogApi,
24 syslog_sync_internal::SyslogSocketLockless, DefaultLocalSyslogDestination
25 },
26};
27
28
29/// A threal local syslog which is completely lockless! It can be used in signle threaded
30/// applications or with the [thread_local] functionality.
31///
32/// ```ignore
33/// thread_local!
34/// {
35/// // Could add pub to make it public to whatever Foo already is public to.
36/// static SYSLOG: RefCell<SingleSyslog> =
37/// RefCell::new(SingleSyslog::openlog_with(Some("test"), LogStat::LOG_PID ,
38/// LogFacility::LOG_DAEMON, SyslogLocal::new()).unwrap());
39/// }
40/// ```
41///
42/// A stream is availble via [SyStreamApi].
43///
44/// ```ignore
45/// let _ = write!(SYSLOG.stream(Priority::LOG_DEBUG), "test {} 123 stream test ", d);
46/// ```
47///
48/// The instances will be completly separated and have own FD.
49///
50/// # Generics
51///
52/// * `D` - a [SyslogDestination] instance which is either:
53/// [SyslogLocal], [crate::syslog_provider::SyslogFile], [crate::syslog_provider::SyslogNet],
54/// [crate::syslog_provider::SyslogTls]. By default a `SyslogLocal` is selected.
55///
56/// * `F` - a [SyslogFormatter] which sets the instance which would
57/// format the message.
58///
59#[derive(Debug)]
60pub struct SingleSyslog<F = DefaultSyslogFormatter, D = DefaultLocalSyslogDestination>
61where
62 F: SyslogFormatter,
63 D: SyslogDestination,
64{
65 /// An identification i.e program name, thread name
66 log_items: LogItems,
67
68 /// A stream (unixdatagram, udp, tcp)
69 stream: SyslogSocketLockless<D>,
70
71 _p: PhantomData<F>,
72
73 _p_not_ss: PhantomData<*const ()>
74}
75
76impl SingleSyslog
77{
78 /// Opens a default connection to the local syslog server with default formatter.
79 ///
80 /// In order to access the syslog API, use the [SyslogApi].
81 ///
82 /// # Arguments
83 ///
84 /// * `ident` - A program name which will appear on the logs. If none, will be determined
85 /// automatically.
86 ///
87 /// * `logstat` - [LogStat] an instance config.
88 ///
89 /// * `facility` - [LogFacility] a syslog facility.
90 ///
91 /// * `net_tap_prov` - a [SyslogLocal] instance with configuration.
92 ///
93 /// # Returns
94 ///
95 /// A [SyRes] is returned ([Result]) with:
96 ///
97 /// * [Result::Ok] - with instance
98 ///
99 /// * [Result::Err] - with error description.
100 pub
101 fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: DefaultLocalSyslogDestination) -> SyRes<Self>
102 {
103 let log_items =
104 LogItems::new(ident, 0xff, logstat, facility);
105
106 let stream =
107 SyslogSocketLockless::<DefaultLocalSyslogDestination>::new(logstat, net_tap_prov)?;
108
109 return Ok(
110 Self
111 {
112 log_items,
113 stream,
114 _p:
115 PhantomData,
116 _p_not_ss:
117 PhantomData
118 }
119 );
120 }
121}
122
123impl<F, D> SingleSyslog<F, D>
124where F: SyslogFormatter, D: SyslogDestination
125{
126 /// Opens a default connection to the local syslog server with default formatter.
127 ///
128 /// # Arguments
129 ///
130 /// * `ident` - A program name which will appear on the logs. If none, will be determined
131 /// automatically.
132 ///
133 /// * `logstat` - [LogStat] an instance config.
134 ///
135 /// * `facility` - [LogFacility] a syslog facility.
136 ///
137 /// * `net_tap_prov` - a [SyslogLocal] instance with configuration.
138 ///
139 /// # Returns
140 ///
141 /// A [SyRes] is returned ([Result]) with:
142 ///
143 /// * [Result::Ok] - with instance
144 ///
145 /// * [Result::Err] - with error description.
146 pub
147 fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self>
148 {
149 let log_items =
150 LogItems::new(ident, 0xff, logstat, facility);
151
152 let stream =
153 SyslogSocketLockless::<D>::new(logstat, net_tap_prov)?;
154
155 return Ok(
156 Self
157 {
158 log_items,
159 stream,
160 _p:
161 PhantomData,
162 _p_not_ss:
163 PhantomData
164 }
165 );
166 }
167}
168
169impl<F, D> SingleSyslog<F, D>
170where F: SyslogFormatter, D: SyslogDestination
171{
172 /// Connects the current instance to the syslog server (destination).
173 #[inline]
174 pub
175 fn connectlog(&mut self) -> SyRes<()>
176 {
177 return
178 self
179 .stream
180 .connectlog();
181 }
182
183 /// Sets the logmask to filter out the syslog calls.
184 ///
185 /// See macroses [LOG_MASK] and [LOG_UPTO] to generate mask
186 ///
187 /// # Example
188 ///
189 /// LOG_MASK!(Priority::LOG_EMERG) | LOG_MASK!(Priority::LOG_ERROR)
190 ///
191 /// or
192 ///
193 /// ~(LOG_MASK!(Priority::LOG_INFO))
194 /// LOG_UPTO!(Priority::LOG_ERROR)
195 #[inline]
196 pub
197 fn setlogmask(&mut self, logmask: i32) -> SyRes<i32>
198 {
199 return Ok(
200 self
201 .log_items
202 .set_logmask(logmask)
203 );
204 }
205
206 /// Closes connection to the syslog server (destination).
207 #[inline]
208 pub
209 fn closelog(&mut self) -> SyRes<()>
210 {
211 return
212 self
213 .stream
214 .disconnectlog();
215 }
216
217 /// Similar to libc, syslog() sends data to syslog server.
218 ///
219 /// # Arguments
220 ///
221 /// * `pri` - a priority [Priority]
222 ///
223 /// * `fmt` - a formatter [SyslogFormatter] message. In C exists a functions with
224 /// variable argumets amount. In Rust you should create your
225 /// own macros like format!() or use format!()]. The [String] and ref `'static`
226 /// [str] can be passed directly.
227 ///
228 /// # Returns
229 ///
230 /// A [SyRes] is returned which may describe an error.
231 #[inline]
232 pub
233 fn syslog(&mut self, pri: Priority, fmt: F) -> SyRes<()>
234 {
235 let Some((formatted_msg, logstat)) =
236 self.log_items.vsyslog1_msg::<F, D>(pri, &fmt)
237 else { return Ok(()) };
238
239 self.stream.vsyslog1(logstat, formatted_msg)
240 }
241
242 /// This function can be used to update the facility name, for example
243 /// after fork().
244 ///
245 /// # Arguments
246 ///
247 /// * `ident` - an [Option] optional new identity (up to 48 UTF8 chars)
248 /// If set to [Option::None] would request the program name from OS.
249 #[inline]
250 pub
251 fn change_identity(&mut self, ident: Option<&str>) -> SyRes<()>
252 {
253 self.log_items.set_identity(ident);
254
255 return Ok(());
256 }
257
258 /// Re-opens the connection to the syslog server. Can be used to
259 /// rotate logs(handle SIGHUP).
260 ///
261 /// # Returns
262 ///
263 /// A [Result] is retured as [SyRes].
264 ///
265 /// * [Result::Ok] - with empty inner type.
266 ///
267 /// * [Result::Err] - an error code and description
268 #[inline]
269 pub
270 fn reconnect(&mut self) -> SyRes<()>
271 {
272 return
273 self
274 .stream
275 .reconnectlog();
276 }
277
278 /// Updates the instance's socket. `tap_data` [TapTypeData] should be of
279 /// the same variant (type) as current.
280 #[inline]
281 pub
282 fn update_tap_data(&mut self, tap_data: D) -> SyRes<()>
283 {
284 return
285 self
286 .stream
287 .update_tap_data(tap_data.clone());
288 }
289}
290
291impl<F, D> SingleSyslog<F, D>
292where F: SyslogFormatter, D: SyslogDestination
293{
294 /// Returns the streamable [SyStream] instance which can be used with [write!].
295 ///
296 /// It implements both [std::fmt::Write] and [std::io::Write].
297 ///
298 /// # Example
299 ///
300 /// ```ignore
301 /// let log =
302 /// SingleSyslog::openlog(
303 /// Some("test1"),
304 /// LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
305 /// LogFacility::LOG_DAEMON,
306 /// SyslogLocal::new()
307 /// ).unwrap();
308 ///
309 /// write!(log.get_stream::<SyStreamPriDebug>(), "test stream singlesyslog {}", i).unwrap();
310 /// ```
311 pub
312 fn get_stream<'t, PRI>(&'t mut self) -> SyStream<'t, PRI, D, F, &'t mut Self>
313 where PRI: SyStreamPri
314 {
315 SyStream
316 {
317 s: Some(self),
318 _p: PhantomData,
319 _p1: PhantomData,
320 _p2: PhantomData
321 }
322 }
323}
324
325
326impl<F: SyslogFormatter, D: SyslogDestination> SyStreamSyslogApi<F, D>
327for &mut SingleSyslog<F, D>
328{
329 type SYSLOG<'t> = &'t mut SingleSyslog<F, D>;
330
331 fn syslog<'t>(syslog: Self::SYSLOG<'t>, pri: Priority, fmt: F) -> SyRes<()>
332 {
333 syslog.syslog(pri, fmt)
334 }
335}
336
337