Skip to main content

syslog_rs/sync/
syslog_sync.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::{fmt, marker::PhantomData, sync::{Arc, Mutex}};
17
18use crate::
19{
20    DefaultLocalSyslogDestination, LogFacility, LogStat, Priority, SyslogDestination, error::SyRes, 
21    formatters::{DefaultSyslogFormatter, SyslogFormatter}, 
22    sync::{LogItems, SyStream, SyStreamPri, SyStreamSyslogApi, syslog_sync_internal::SyslogSocketLockless}
23};
24
25/// A public trait which defines the public interface for the `dyn` syslog instance.
26pub trait DynSyslog: Send + Sync
27{
28    /// Connects the current instance to the syslog server (destination).
29    fn connectlog(&self) -> SyRes<()>;
30
31    /// Sets the logmask to filter out the syslog calls.
32    /// 
33    /// See macroses [LOG_MASK] and [LOG_UPTO] to generate mask
34    ///
35    /// # Example
36    ///
37    /// LOG_MASK!(Priority::LOG_EMERG) | LOG_MASK!(Priority::LOG_ERROR)
38    ///
39    /// or
40    ///
41    /// ~(LOG_MASK!(Priority::LOG_INFO))
42    /// LOG_UPTO!(Priority::LOG_ERROR)
43    fn setlogmask(&self, logmask: i32) -> SyRes<i32>;
44
45    /// Closes connection to the syslog server (destination).
46    fn closelog(&self) -> SyRes<()>;
47
48    /// Similar to libc, syslog() sends data to syslog server.
49    /// 
50    /// # Arguments
51    ///
52    /// * `pri` - a priority [Priority]
53    ///
54    /// * `fmt` - a formatter string which should be sent to syslog/file.
55    /// 
56    /// # Returns 
57    /// 
58    /// A [SyRes] is returned which may describe an error.
59    fn syslog(&self, pri: Priority, fmt: String) -> SyRes<()>;
60
61    /// This function can be used to update the facility name, for example
62    /// after fork().
63    /// 
64    /// # Arguments
65    /// 
66    /// * `ident` - an [Option] optional new identity (up to 48 UTF8 chars)
67    ///     If set to [Option::None] would request the program name from OS.
68    fn change_identity(&self, ident: Option<&str>) -> SyRes<()>;
69
70    /// Updates the instance's socket. `tap_data` [TapTypeData] should be of
71    /// the same variant (type) as current.
72    fn reconnect(&self) -> SyRes<()>;
73}
74
75/// A public trait which defines the public interface for the `dyn` syslog instance.
76pub trait MutDynSyslog
77{
78    /// Connects the current instance to the syslog server (destination).
79    fn connectlog(&mut self) -> SyRes<()>;
80
81    /// Sets the logmask to filter out the syslog calls.
82    /// 
83    /// See macroses [LOG_MASK] and [LOG_UPTO] to generate mask
84    ///
85    /// # Example
86    ///
87    /// LOG_MASK!(Priority::LOG_EMERG) | LOG_MASK!(Priority::LOG_ERROR)
88    ///
89    /// or
90    ///
91    /// ~(LOG_MASK!(Priority::LOG_INFO))
92    /// LOG_UPTO!(Priority::LOG_ERROR)
93    fn setlogmask(&mut self, logmask: i32) -> SyRes<i32>;
94
95    /// Closes connection to the syslog server (destination).
96    fn closelog(&mut self) -> SyRes<()>;
97
98    /// Similar to libc, syslog() sends data to syslog server.
99    /// 
100    /// # Arguments
101    ///
102    /// * `pri` - a priority [Priority]
103    ///
104    /// * `fmt` - a formatter string which should be sent to syslog/file.
105    /// 
106    /// # Returns 
107    /// 
108    /// A [SyRes] is returned which may describe an error.
109    fn syslog(&mut self, pri: Priority, fmt: String) -> SyRes<()>;
110
111    /// This function can be used to update the facility name, for example
112    /// after fork().
113    /// 
114    /// # Arguments
115    /// 
116    /// * `ident` - an [Option] optional new identity (up to 48 UTF8 chars)
117    ///     If set to [Option::None] would request the program name from OS.
118    fn change_identity(&mut self, ident: Option<&str>) -> SyRes<()>;
119
120    /// Updates the instance's socket. `tap_data` [TapTypeData] should be of
121    /// the same variant (type) as current.
122    fn reconnect(&mut self) -> SyRes<()>;
123}
124
125/// Exposed only to allow constraint on the generic type. Should not be implemented on the
126/// user's side.
127pub trait SyslogType: fmt::Debug
128{
129    type LockItemsBase;
130
131    type LockItems;
132
133    type LockStreamBase<D: SyslogDestination>;
134
135    type LockStream<D: SyslogDestination>;
136
137    type MoveLockType;
138
139    fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems;
140    fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D>;
141}
142
143/// A main sync syslog client instance.
144/// 
145/// # Generics
146/// 
147/// * `F` - a syslog message formatter. See dir `src/formatters` for available or define one 
148///     yourself. A default is [DefaultSyslogFormatter].
149/// 
150/// * `D` - a destination server/file. See file `src/syslog_provider.rs` for available 
151///     transports. A default is [DefaultLocalSyslogDestination].
152/// 
153/// * `SL` - a client type. Sets the mechanism how the resources are shared. There are 3 types
154///     of syslog. See info below. Default is [SyShared].
155/// 
156/// # Client types
157/// 
158/// * [SyShared] - is a single FD descriptor which is protected by Mutex. This type can be 
159///     clonned, moved between threads.
160/// 
161/// * [SyThreadLocal] - is a thread local/lockless type which should be used only in the 
162///     single thread applications or with [std::thread_local] only! Can be enabled with
163///     feature `build_with_thread_local`.
164/// 
165/// * [SyQueued] - is a buffering/fast type which uses a separate thread to access the 
166///     socket's/file's FD. This type can be clonned, moved between threads. Can be
167///     enabled with feature `build_with_queue`. Also, it can be used to use the same 
168///     connection/file from async and sync code, see `examples/example_sync_async.rs`.
169/// 
170/// Feature `build_with_queue` without any async features uses a `crossbeam` MPSC. If
171/// any feature which enables `async` i.e `build_async_tokio`, `build_async_smol`, 
172/// `build_async_interface`, the MPSC provider will be switch to either Smoll's, Tokio's,
173/// or which you will define.
174/// 
175/// # Examples
176/// 
177/// Full default:
178/// 
179/// ```ignore
180/// pub static SYSLOG: LazyLock<Syslog> = LazyLock::new(|| 
181/// {
182///     #[cfg(target_family = "unix")]
183///     let syslog_provider = 
184///         SyslogLocal::new();
185/// 
186///     #[cfg(target_family = "windows")]   
187///     let syslog_provider = 
188///         WindowsEvent::new();
189/// 
190///     Syslog::openlog(
191///         Some("example"), 
192///         LogStat::LOG_CONS | LogStat::LOG_PID, 
193///         LogFacility::LOG_DAEMON,
194///         syslog_provider
195///     )
196///     .unwrap()
197/// }
198/// );
199/// ```
200/// 
201/// Custom i.e queued
202/// 
203/// ```ignore
204/// pub static SYSLOG: LazyLock<Syslog<DefaultSyslogFormatter, DefaultLocalSyslogDestination, SyQueued<DefaultQueueAdapter, DefaultSyslogFormatter, DefaultLocalSyslogDestination>>> = 
205/// LazyLock::new(|| 
206///     {
207///         #[cfg(target_family = "unix")]
208///        let syslog_provider = 
209///             SyslogLocal::new();
210/// 
211///         #[cfg(target_family = "windows")]   
212///         let syslog_provider = 
213///             WindowsEvent::new();
214/// 
215///         Syslog
216///             ::<_, _, SyQueued<DefaultQueueAdapter, _, _>>
217///             ::openlog_with(
218///                 Some("example_sync_queue"), 
219///                 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
220///                 LogFacility::LOG_DAEMON,
221///                 syslog_provider
222///             )
223///             .unwrap()
224///     }
225///  );
226/// ```
227/// 
228#[derive(Debug)]
229pub struct Syslog<F = DefaultSyslogFormatter, D = DefaultLocalSyslogDestination, SL = SyShared>
230where 
231    F: SyslogFormatter, 
232    D: SyslogDestination,
233    SL: SyslogType
234{   
235    /// An identification i.e program name, thread name
236    log_items: SL::LockItems,
237
238    /// A stream (unixdatagram, udp, tcp)
239    stream: SL::LockStream<D>,
240
241    _p: PhantomData<F>,
242
243    _p_not_ss: SL::MoveLockType
244}
245
246impl Syslog
247{
248    /// Opens a default connection to the local syslog server with default formatter.
249    /// 
250    /// In order to access the syslog API, use the [SyslogApi].
251    /// 
252    /// # Arguments
253    /// 
254    /// * `ident` - A program name which will appear on the logs. If none, will be determined
255    ///     automatically.
256    /// 
257    /// * `logstat` - [LogStat] an instance config.
258    /// 
259    /// * `facility` - [LogFacility] a syslog facility.
260    /// 
261    /// * `net_tap_prov` - a [SyslogLocal] instance with configuration.
262    /// 
263    /// # Returns
264    /// 
265    /// A [SyRes] is returned ([Result]) with: 
266    /// 
267    /// * [Result::Ok] - with instance
268    /// 
269    /// * [Result::Err] - with error description.
270    pub 
271    fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility, 
272        net_tap_prov: DefaultLocalSyslogDestination) -> SyRes<Self> 
273    {
274        return Ok( 
275            Self
276            {
277                log_items: 
278                    <SyShared as SyslogType>
279                        ::wrap_items(
280                            <SyShared as SyslogType>::LockItemsBase::new(ident, 0xff, logstat, facility)
281                        ),
282                stream: 
283                    <SyShared as SyslogType>
284                        ::wrap_stream(
285                            <SyShared as SyslogType>::LockStreamBase::<DefaultLocalSyslogDestination>::new(logstat, net_tap_prov)?,
286                        ),
287                _p: 
288                    PhantomData,
289                _p_not_ss: 
290                    PhantomData
291            }
292        );
293    }
294}
295
296#[cfg(feature = "build_with_thread_local")]
297pub mod build_with_thread_local
298{
299    use super::*;
300
301    /// A threal local syslog which is completely lockless! It can be used in signle threaded
302    /// applications or with the [thread_local] functionality.
303    /// 
304    /// ```ignore
305    /// thread_local! 
306    /// {
307    ///     // Could add pub to make it public to whatever Foo already is public to.
308    ///     static SYSLOG: RefCell<Syslog<DefaultSyslogFormatter, SyslogLocal, SyThreadLocal>> = 
309    ///         RefCell::new(
310    ///             Syslog
311    ///                 ::<_, _, SyThreadLocal>
312    ////                ::openlog_with(Some("test"), LogStat::LOG_PID, LogFacility::LOG_DAEMON, SyslogLocal::new())
313    ///                     .unwrap()
314    ///         );
315    /// }
316    /// ```
317    /// 
318    /// A stream is availble via [SyStreamApi].
319    /// 
320    /// ```ignore
321    /// let _ = write!(SYSLOG.stream(Priority::LOG_DEBUG), "test {} 123 stream test ", d);
322    /// ```
323    /// 
324    /// The instances will be completly separated and have own FD.
325    /// 
326    /// # Generics
327    /// 
328    /// * `D` - a [SyslogDestination] instance which is either:
329    ///     [SyslogLocal], [crate::syslog_provider::SyslogFile], [crate::syslog_provider::SyslogNet], 
330    ///     [crate::syslog_provider::SyslogTls]. By default a `SyslogLocal` is selected.
331    /// 
332    /// * `F` - a [SyslogFormatter] which sets the instance which would 
333    ///     format the message.
334    /// 
335    #[derive(Debug)]
336    pub struct SyThreadLocal;
337
338    impl SyslogType for SyThreadLocal
339    {
340        type LockItemsBase = LogItems;
341        type LockItems = Self::LockItemsBase;
342
343        type LockStreamBase<D: SyslogDestination> = SyslogSocketLockless<D>;
344        type LockStream<D: SyslogDestination> = Self::LockStreamBase<D>;
345        
346        type MoveLockType = PhantomData<*const ()>;
347
348        fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems 
349        {
350            items
351        }
352
353        fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D> 
354        {
355            stream
356        }
357    }
358
359    impl<F, D> MutDynSyslog for Syslog<F, D, SyThreadLocal>
360    where 
361        F: SyslogFormatter,
362        D: SyslogDestination,
363    {
364        #[inline]
365        fn connectlog(&mut self) -> SyRes<()> 
366        {
367            self.connectlog()
368        }
369
370        #[inline]
371        fn setlogmask(&mut self, logmask: i32) -> SyRes<i32> 
372        {
373            self.setlogmask(logmask)
374        }
375
376        #[inline]
377        fn closelog(&mut self) -> SyRes<()>
378        {
379            self.closelog()
380        }
381        
382        fn syslog(&mut self, pri: Priority, fmt: String) -> SyRes<()> 
383        {
384            self.syslog(pri, fmt.into())
385        }
386        
387        fn change_identity(&mut self, ident: Option<&str>) -> SyRes<()> 
388        {
389            self.change_identity(ident)
390        }
391        
392        fn reconnect(&mut self) -> SyRes<()> 
393        {
394            self.reconnect()
395        }
396    }
397
398    impl<F, D> Syslog<F, D, SyThreadLocal>
399    where 
400        F: SyslogFormatter,
401        D: SyslogDestination,
402    {
403        pub 
404        fn make_dyn(self) -> Box<dyn MutDynSyslog>
405        {
406            Box::new(self)
407        }
408
409        /// Opens a default connection to the local syslog server with default formatter.
410        /// 
411        /// # Arguments
412        /// 
413        /// * `ident` - A program name which will appear on the logs. If none, will be determined
414        ///     automatically.
415        /// 
416        /// * `logstat` - [LogStat] an instance config.
417        /// 
418        /// * `facility` - [LogFacility] a syslog facility.
419        /// 
420        /// * `net_tap_prov` - a [SyslogLocal] instance with configuration.
421        /// 
422        /// # Returns
423        /// 
424        /// A [SyRes] is returned ([Result]) with: 
425        /// 
426        /// * [Result::Ok] - with instance
427        /// 
428        /// * [Result::Err] - with error description.
429        pub 
430        fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self> 
431        {
432            return Ok(
433                Self
434                {
435                    log_items:
436                        <SyThreadLocal as SyslogType>
437                            ::wrap_items(
438                                <SyThreadLocal as SyslogType>::LockItems::new(ident, 0xff, logstat, facility)
439                            ),
440                    stream:
441                        <SyThreadLocal as SyslogType>
442                            ::wrap_stream(
443                                <SyThreadLocal as SyslogType>::LockStream::new(logstat, net_tap_prov)?
444                            ),
445                    _p: 
446                        PhantomData,
447                    _p_not_ss: 
448                        PhantomData
449                }
450            );
451        }
452    }
453
454    impl<F, D> Syslog<F, D, SyThreadLocal>
455    where 
456        F: SyslogFormatter,
457        D: SyslogDestination,
458    {
459        /// Connects the current instance to the syslog server (destination).
460        #[inline]
461        pub 
462        fn connectlog(&mut self) -> SyRes<()>
463        {
464            return 
465                self
466                    .stream
467                    .connectlog();
468        }
469
470        /// Sets the logmask to filter out the syslog calls.
471        /// 
472        /// See macroses [LOG_MASK] and [LOG_UPTO] to generate mask
473        ///
474        /// # Example
475        ///
476        /// LOG_MASK!(Priority::LOG_EMERG) | LOG_MASK!(Priority::LOG_ERROR)
477        ///
478        /// or
479        ///
480        /// ~(LOG_MASK!(Priority::LOG_INFO))
481        /// LOG_UPTO!(Priority::LOG_ERROR)
482        #[inline]
483        pub 
484        fn setlogmask(&mut self, logmask: i32) -> SyRes<i32>
485        {
486            return Ok(
487                self
488                    .log_items
489                    .set_logmask(logmask)
490            );
491        }
492
493        /// Closes connection to the syslog server (destination).
494        #[inline]
495        pub 
496        fn closelog(&mut self) -> SyRes<()> 
497        {
498            return 
499                self
500                    .stream
501                    .disconnectlog();
502        }
503
504        /// Similar to libc, syslog() sends data to syslog server.
505        /// 
506        /// # Arguments
507        ///
508        /// * `pri` - a priority [Priority]
509        ///
510        /// * `fmt` - a formatter [SyslogFormatter] message. In C exists a functions with
511        ///     variable argumets amount. In Rust you should create your
512        ///     own macros like format!() or use format!()]. The [String] and ref `'static` 
513        ///     [str] can be passed directly.
514        /// 
515        /// # Returns 
516        /// 
517        /// A [SyRes] is returned which may describe an error.
518        #[inline]
519        pub 
520        fn syslog(&mut self, pri: Priority, fmt: F) -> SyRes<()>
521        {
522            let Some((formatted_msg, logstat)) = 
523                self.log_items.vsyslog1_msg::<F, D>(pri, &fmt)
524                else { return Ok(()) };
525
526            self.stream.vsyslog1(logstat, formatted_msg)
527        }
528
529        /// This function can be used to update the facility name, for example
530        /// after fork().
531        /// 
532        /// # Arguments
533        /// 
534        /// * `ident` - an [Option] optional new identity (up to 48 UTF8 chars)
535        ///     If set to [Option::None] would request the program name from OS.
536        #[inline]
537        pub 
538        fn change_identity(&mut self, ident: Option<&str>) -> SyRes<()>
539        {
540            self.log_items.set_identity(ident);
541
542            return Ok(());
543        }
544
545        /// Re-opens the connection to the syslog server. Can be used to 
546        /// rotate logs(handle SIGHUP).
547        /// 
548        /// # Returns
549        /// 
550        /// A [Result] is retured as [SyRes].
551        /// 
552        /// * [Result::Ok] - with empty inner type.
553        /// 
554        /// * [Result::Err] - an error code and description 
555        #[inline]
556        pub 
557        fn reconnect(&mut self) -> SyRes<()>
558        {
559            return
560                self
561                    .stream
562                    .reconnectlog();
563        }
564
565        /// Updates the instance's socket. `tap_data` [TapTypeData] should be of
566        /// the same variant (type) as current.
567        #[inline]
568        pub 
569        fn update_tap_data(&mut self, tap_data: D) -> SyRes<()>
570        {
571            return 
572                self
573                    .stream
574                    .update_tap_data(tap_data.clone());
575        }
576    }
577
578    impl<F, D> Syslog<F, D, SyThreadLocal>
579    where 
580        F: SyslogFormatter,
581        D: SyslogDestination,
582    {
583        /// Returns the streamable [SyStream] instance which can be used with [write!].
584        /// 
585        /// It implements both [std::fmt::Write] and [std::io::Write].
586        /// 
587        /// # Example
588        /// 
589        /// ```ignore
590        /// let log = 
591        ///     SingleSyslog::openlog(
592        ///         Some("test1"), 
593        ///         LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
594        ///         LogFacility::LOG_DAEMON,
595        ///         SyslogLocal::new()
596        ///     ).unwrap();
597        /// 
598        /// write!(log.get_stream::<SyStreamPriDebug>(), "test stream singlesyslog {}", i).unwrap();
599        /// ```
600        pub 
601        fn get_stream<'t, PRI>(&'t mut self) -> SyStream<'t, PRI, D, F, &'t mut Self>
602        where PRI: SyStreamPri
603        {
604            SyStream
605            {
606                s: Some(self),
607                _p: PhantomData,
608                _p1: PhantomData,
609                _p2: PhantomData
610            }
611        }
612    }
613
614    impl<F, D> SyStreamSyslogApi<F, D>  
615    for &mut Syslog<F, D, SyThreadLocal>
616    where 
617        F: SyslogFormatter,
618        D: SyslogDestination,
619    {
620        type SYSLOG<'t> = &'t mut Syslog<F, D, SyThreadLocal>;
621
622        fn syslog<'t>(syslog: Self::SYSLOG<'t>, pri: Priority, fmt: F) -> SyRes<()>
623        {
624            syslog.syslog(pri, fmt)
625        }
626    }
627}
628
629#[cfg(feature = "build_with_thread_local")]
630pub use self::build_with_thread_local::SyThreadLocal;
631
632// ---- SYSLOG SHARED
633
634/// A `sync`, shared instance of the syslog client which is shared between many
635/// threads. Previously a mutex was used, but since the v5.0.0 a CoW experimental
636/// approach is used. The `CoW` creates clones of the instance without holding
637/// a long mutex locks. When writing, the instance does not hold a long lock on
638/// updated item. Only exclusive lock locks the readers, because the instance is
639/// updated and not usable anyway.
640/// 
641/// If the program has fixed amount of threads, probably the `syslog_threadlocal`
642/// will be better alternative. It has the same functionality, but avoids 
643/// any sync locks by working in current thread.
644/// 
645/// # Traits
646/// 
647/// For this isntance a [SyslogApi] and [SyStreamApi] are implemented.
648/// 
649/// # Examples
650/// 
651/// ```ignore
652/// let log = 
653///     Syslog::openlog(
654///         Some("test1"), 
655///         LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
656///         LogFacility::LOG_DAEMON,
657///         SyslogLocal::new()
658///     );
659/// ```
660/// 
661/// ```ignore
662/// let log = 
663///     Syslog
664///         ::<DefaultSyslogFormatter, SyslogLocal, SyShared>
665///         ::openlog_with(
666///             Some("test1"), 
667///             LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
668///             LogFacility::LOG_DAEMON,
669///             SyslogLocal::new()
670///         );
671/// ```
672/// 
673/// ```ignore
674/// pub static SYSLOG3: LazyLock<Syslog<DefaultSyslogFormatter, SyslogLocal, SyShared>> = 
675///     LazyLock::new(|| 
676///         {
677///             Syslog
678///                 ::<DefaultSyslogFormatter, SyslogLocal, SyShared>
679///                 ::openlog_with(
680///                     Some("test1"), 
681///                     LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
682///                     LogFacility::LOG_DAEMON,
683///                     SyslogLocal::new()
684///                 )
685///                 .unwrap()
686///         }
687///     );
688/// ```
689/// # Streaming
690/// 
691/// A stream is availble via [SyStreamApi].
692/// 
693/// ```ignore
694/// let _ = write!(SYSLOG.stream(Priority::LOG_DEBUG), "test {} 123 stream test ", d);
695/// ```
696/// 
697/// # Generics
698/// 
699/// * `F` - a [SyslogFormatter] which sets the instance which would 
700///     format the message.
701/// 
702/// * `D` - a [SyslogDestination] instance which is either:
703///     [SyslogLocal], [SyslogFile], [SyslogNet], [SyslogTls]. By
704///     default a `SyslogLocal` is selected.
705#[derive(Debug)]
706pub struct SyShared;
707
708impl SyslogType for SyShared
709{
710    type LockItemsBase = LogItems;
711    type LockItems = Arc<Mutex<Self::LockItemsBase>>;
712
713    type LockStreamBase<D: SyslogDestination> = SyslogSocketLockless<D>;
714    type LockStream<D: SyslogDestination> = Arc<Mutex<Self::LockStreamBase<D>>>;
715
716    type MoveLockType = PhantomData<()>;
717
718    fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems 
719    {
720        Arc::new(Mutex::new(items))
721    }
722
723    fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D> 
724    {
725        Arc::new(Mutex::new(stream))
726    }
727}
728
729impl<F, D> Clone for Syslog<F, D, SyShared>
730where 
731    F: SyslogFormatter,
732    D: SyslogDestination,
733{
734    fn clone(&self) -> Self 
735    {
736        Self 
737        { 
738            log_items: 
739                self.log_items.clone(), 
740            stream: 
741                self.stream.clone(), 
742            _p: 
743                PhantomData, 
744            _p_not_ss: 
745                PhantomData,
746        }
747    }
748}
749
750impl<F, D> DynSyslog for Syslog<F, D, SyShared>
751where 
752    F: SyslogFormatter,
753    D: SyslogDestination,
754{
755    #[inline]
756    fn connectlog(&self) -> SyRes<()> 
757    {
758        self.connectlog()
759    }
760
761    #[inline]
762    fn setlogmask(&self, logmask: i32) -> SyRes<i32> 
763    {
764        self.setlogmask(logmask)
765    }
766
767    #[inline]
768    fn closelog(&self) -> SyRes<()>
769    {
770        self.closelog()
771    }
772    
773    fn syslog(&self, pri: Priority, fmt: String) -> SyRes<()> 
774    {
775        self.syslog(pri, fmt.into())
776    }
777    
778    fn change_identity(&self, ident: Option<&str>) -> SyRes<()> 
779    {
780        self.change_identity(ident)
781    }
782    
783    fn reconnect(&self) -> SyRes<()> 
784    {
785        self.reconnect()
786    }
787}
788
789
790impl<F, D> Syslog<F, D, SyShared>
791where 
792    F: SyslogFormatter,
793    D: SyslogDestination,
794{
795    pub 
796    fn make_dyn(self) -> Box<dyn DynSyslog + Send + Sync>
797    {
798        Box::new(self)
799    }
800
801    /// Opens a special connection to the destination syslog server with specific formatter.
802    /// 
803    /// All struct generic should be specified before calling this function.
804    /// 
805    /// In order to access the syslog API, use the [SyslogApi].
806    /// 
807    /// # Arguments
808    /// 
809    /// * `ident` - A program name which will appear on the logs. If none, will be determined
810    ///     automatically.
811    /// 
812    /// * `logstat` - [LogStat] an instance config.
813    /// 
814    /// * `facility` - [LogFacility] a syslog facility.
815    /// 
816    /// * `net_tap_prov` - a destination server. A specific `D` instance which contains infomation 
817    ///     about the destination server. See `syslog_provider.rs`.
818    /// 
819    /// # Returns
820    /// 
821    /// A [SyRes] is returned ([Result]) with: 
822    /// 
823    /// * [Result::Ok] - with instance
824    /// 
825    /// * [Result::Err] - with error description.
826    pub 
827    fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self> 
828    {
829        return Ok( 
830            Self
831            {
832                log_items: 
833                    <SyShared as SyslogType>
834                        ::wrap_items(
835                            <SyShared as SyslogType>::LockItemsBase::new(ident, 0xff, logstat, facility)
836                        ),
837                stream: 
838                    <SyShared as SyslogType>
839                        ::wrap_stream(
840                            <SyShared as SyslogType>::LockStreamBase::<D>::new(logstat, net_tap_prov)?,
841                        ),
842                _p: 
843                    PhantomData,
844                _p_not_ss:
845                    PhantomData
846            }
847        );
848    }
849
850    /// Just initializes the instance from other instance. For example, in the crate which uses
851    /// this type of logging. 
852    /// 
853    /// Will work only if `F` and `D` are same.
854    pub 
855    fn attach(other: &Syslog<F, D, SyShared>) -> SyRes<Self>
856    {
857        Ok(other.clone())
858    }
859}
860
861impl<F, D> Syslog<F, D, SyShared>
862where 
863    F: SyslogFormatter,
864    D: SyslogDestination,
865{
866    /// Connects the current instance to the syslog server (destination).
867    pub 
868    fn connectlog(&self) -> SyRes<()>
869    {
870        return 
871            self
872                .stream
873                .lock()
874                .unwrap()
875                .connectlog();
876    }
877
878    /// Sets the logmask to filter out the syslog calls.
879    /// 
880    /// See macroses [LOG_MASK] and [LOG_UPTO] to generate mask
881    ///
882    /// # Example
883    ///
884    /// LOG_MASK!(Priority::LOG_EMERG) | LOG_MASK!(Priority::LOG_ERROR)
885    ///
886    /// or
887    ///
888    /// ~(LOG_MASK!(Priority::LOG_INFO))
889    /// LOG_UPTO!(Priority::LOG_ERROR)
890    pub 
891    fn setlogmask(&self, logmask: i32) -> SyRes<i32> 
892    {
893        let pri = 
894            self
895                .log_items
896                .lock()
897                .unwrap()
898                .set_logmask(logmask);
899
900        return Ok(pri);
901    }
902
903    /// Closes connection to the syslog server (destination).
904    pub 
905    fn closelog(&self) -> SyRes<()> 
906    {
907        return 
908            self
909                .stream
910                .lock()
911                .unwrap()
912                .disconnectlog();
913    }
914
915    /// Similar to libc, syslog() sends data to syslog server.
916    /// 
917    /// # Arguments
918    ///
919    /// * `pri` - a priority [Priority]
920    ///
921    /// * `fmt` - a formatter [SyslogFormatter] message. In C exists a functions with
922    ///     variable argumets amount. In Rust you should create your
923    ///     own macros like format!() or use format!()]. The [String] and ref `'static` 
924    ///     [str] can be passed directly.
925    /// 
926    /// # Returns 
927    /// 
928    /// A [SyRes] is returned which may describe an error.
929    #[inline]
930    pub 
931    fn syslog(&self, pri: Priority, fmt: F) -> SyRes<()>
932    {
933        let Some((formatted_msg, logstat)) = 
934            self.log_items.lock().unwrap().vsyslog1_msg::<F, D>(pri, &fmt)
935        else { return Ok(()) };
936
937        self.stream.lock().unwrap().vsyslog1(logstat, formatted_msg)
938    }
939
940    /// This function can be used to update the facility name, for example
941    /// after fork().
942    /// 
943    /// # Arguments
944    /// 
945    /// * `ident` - an [Option] optional new identity (up to 48 UTF8 chars)
946    ///     If set to [Option::None] would request the program name from OS.
947    pub 
948    fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
949    {
950        self
951            .log_items
952            .lock()
953            .unwrap()
954            .set_identity(ident);
955
956        return Ok(());
957    }
958
959    /// Re-opens the connection to the syslog server. Can be used to 
960    /// rotate logs(handle SIGHUP).
961    /// 
962    /// # Returns
963    /// 
964    /// A [Result] is retured as [SyRes].
965    /// 
966    /// * [Result::Ok] - with empty inner type.
967    /// 
968    /// * [Result::Err] - an error code and description 
969    pub 
970    fn reconnect(&self) -> SyRes<()>
971    {
972        return
973            self
974                .stream
975                .lock()
976                .unwrap()
977                .reconnectlog();
978    }
979
980    /// Updates the instance's socket. `tap_data` [TapTypeData] should be of
981    /// the same variant (type) as current.
982    pub 
983    fn update_tap_data(&self, tap_data: D) -> SyRes<()>
984    {
985        return
986            self
987                .stream
988                .lock()
989                .unwrap()
990                .update_tap_data(tap_data);
991    }
992}
993
994impl<F, D> Syslog<F, D, SyShared>
995where 
996    F: SyslogFormatter,
997    D: SyslogDestination,
998{
999    /// Returns the streamable [SyStream] instance which can be used with [write!].
1000    /// 
1001    /// It implements both [std::fmt::Write] and [std::io::Write].
1002    /// 
1003    /// # Example
1004    /// 
1005    /// ```ignore
1006    /// let log = 
1007    ///     SingleSyslog::openlog(
1008    ///         Some("test1"), 
1009    ///         LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
1010    ///         LogFacility::LOG_DAEMON,
1011    ///         SyslogLocal::new()
1012    ///     ).unwrap();
1013    /// 
1014    /// write!(log.get_stream::<SyStreamPriDebug>(), "test stream singlesyslog {}", i).unwrap();
1015    /// ```
1016    pub 
1017    fn get_stream<'t, PRI>(&'t self) -> SyStream<'t, PRI, D, F, &'t Self>
1018    where PRI: SyStreamPri
1019    {
1020        SyStream
1021        {
1022            s: Some(self),
1023            _p: PhantomData,
1024            _p1: PhantomData,
1025            _p2: PhantomData
1026        }
1027    }
1028}
1029
1030impl<F: SyslogFormatter, D: SyslogDestination> SyStreamSyslogApi<F, D>  
1031for &Syslog<F, D, SyShared>
1032{
1033    type SYSLOG<'t> = &'t Syslog<F, D, SyShared>;
1034
1035    fn syslog<'t>(syslog: Self::SYSLOG<'t>, pri: Priority, fmt: F) -> SyRes<()>
1036    {
1037        syslog.syslog(pri, fmt)
1038    }
1039}
1040
1041// --- QUEUE
1042
1043
1044#[cfg(feature = "build_with_queue")]
1045pub mod build_with_queue
1046{
1047    use std::{sync::{Arc, Mutex, Weak, atomic::{AtomicBool, Ordering}}, thread};
1048
1049    use crate::{DefaultLocalSyslogDestination, SyslogDestination, formatters::{DefaultSyslogFormatter, SyslogFormatter}, map_error, sy_sync_queue::{SyCmd, SyslogInternal, SyslogQueueChanSnd, SyslogQueueChannel, SyslogQueueOneChanRcv}, sync::DefaultQueueAdapter};
1050
1051    use super::*;
1052
1053    /// A queued syslog client which uses a separate thread to send messages to upstream.
1054    /// 
1055    /// # Generics
1056    /// 
1057    /// * `F` - a syslog message formatter. See dir `src/formatters` for available or define one 
1058    ///     yourself. A default is [DefaultSyslogFormatter].
1059    /// 
1060    /// * `D` - a destination server/file. See file `src/syslog_provider.rs` for available 
1061    ///     transports. A default is [DefaultLocalSyslogDestination].
1062    /// 
1063    /// * `S` - a queue mechanism. A default is [DefaultLocalSyslogDestination]. If you don't
1064    ///     need any special queue mechanism, use the default.
1065    #[derive(Debug, Clone)]
1066    pub struct SyQueued<S = DefaultQueueAdapter, F = DefaultSyslogFormatter, D = DefaultLocalSyslogDestination>
1067    where 
1068        F: SyslogFormatter, 
1069        D: SyslogDestination,
1070        S: SyslogQueueChannel<F, D>,
1071
1072    {
1073        /// Control flag
1074        run_control: Weak<AtomicBool>,
1075
1076        /// commands channel
1077        pub(crate) tasks: S::ChannelSnd,
1078
1079        /// process thread
1080        thread: Arc<Mutex<Option<thread::JoinHandle<()>>>>,
1081    }
1082
1083    impl<F, DD, S> SyslogType for SyQueued<S, F, DD>
1084    where F: SyslogFormatter, DD: SyslogDestination, S: SyslogQueueChannel<F, DD>
1085    {
1086        type LockItemsBase = ();
1087        type LockItems = Self::LockItemsBase;
1088
1089        type LockStreamBase<D: SyslogDestination> = SyQueued<S, F, DD>;
1090        type LockStream<D: SyslogDestination> = Self::LockStreamBase<D>;
1091
1092        type MoveLockType = PhantomData<()>;
1093
1094        fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems 
1095        {
1096            items
1097        }
1098
1099        fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D> 
1100        {
1101            stream
1102        }
1103    }
1104
1105    unsafe impl<F, D, S> Send for SyQueued<S, F, D> 
1106    where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
1107    {}
1108
1109    impl<F, D, S> Drop for SyQueued<S, F, D>
1110    where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
1111    {
1112        fn drop(&mut self) 
1113        {
1114            if let Some(ctrl) = self.run_control.upgrade()
1115            {   
1116                ctrl.store(false, Ordering::SeqCst);
1117
1118                if let Err(_e) = self.tasks.q_send_blocking(SyCmd::form_stop())
1119                {
1120
1121                }
1122
1123                let join_handle = self.thread.lock().unwrap().take().unwrap();
1124
1125                let _ = join_handle.join();
1126            }
1127        }
1128    }
1129
1130    impl<F, D, S> Clone for Syslog<F, D, SyQueued<S, F, D>>
1131    where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
1132    {
1133        fn clone(&self) -> Self 
1134        {
1135            Self 
1136            { 
1137                log_items: 
1138                    self.log_items.clone(), 
1139                stream: 
1140                    self.stream.clone(), 
1141                _p: 
1142                    PhantomData, 
1143                _p_not_ss: 
1144                    PhantomData
1145            }
1146        }
1147    }
1148
1149    impl<F, D, S> DynSyslog for Syslog<F, D, SyQueued<S, F, D>>
1150    where 
1151        F: SyslogFormatter,
1152        D: SyslogDestination,
1153        S: SyslogQueueChannel<F, D>
1154    {
1155        #[inline]
1156        fn connectlog(&self) -> SyRes<()> 
1157        {
1158            self.connectlog()
1159        }
1160
1161        #[inline]
1162        fn setlogmask(&self, logmask: i32) -> SyRes<i32> 
1163        {
1164            self.setlogmask(logmask)
1165        }
1166
1167        #[inline]
1168        fn closelog(&self) -> SyRes<()>
1169        {
1170            self.closelog()
1171        }
1172        
1173        fn syslog(&self, pri: Priority, fmt: String) -> SyRes<()> 
1174        {
1175            self.syslog(pri, fmt.into())
1176        }
1177        
1178        fn change_identity(&self, ident: Option<&str>) -> SyRes<()> 
1179        {
1180            self.change_identity(ident)
1181        }
1182        
1183        fn reconnect(&self) -> SyRes<()> 
1184        {
1185            self.reconnect()
1186        }
1187    }
1188
1189    impl<F, D, S> Syslog<F, D, SyQueued<S, F, D>>
1190    where 
1191        F: SyslogFormatter,
1192        D: SyslogDestination,
1193        S: SyslogQueueChannel<F, D>
1194    {
1195        /// Converts the current instance into dyncamic object. See [DynSyslog] for the interface.
1196        pub 
1197        fn make_dyn(self) -> Box<dyn DynSyslog + Send + Sync>
1198        {
1199            Box::new(self)
1200        }
1201
1202        /// Opens a default connection to the local syslog server with default formatter with
1203        /// provided generics.
1204        /// 
1205        /// # Arguments
1206        /// 
1207        /// * `ident` - A program name which will appear on the logs. If none, will be determined
1208        ///     automatically.
1209        /// 
1210        /// * `logstat` - [LogStat] an instance config.
1211        /// 
1212        /// * `facility` - [LogFacility] a syslog facility.
1213        /// 
1214        /// * `net_tap_prov` - a [SyslogLocal] instance with configuration.
1215        /// 
1216        /// # Returns
1217        /// 
1218        /// A [SyRes] is returned ([Result]) with: 
1219        /// 
1220        /// * [Result::Ok] - with instance
1221        /// 
1222        /// * [Result::Err] - with error description.
1223        pub 
1224        fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self>
1225        {
1226            // creating internal syslog struct
1227
1228            let log_items = 
1229                LogItems::new(ident, 0xff, logstat, facility);
1230
1231            let stream = 
1232                SyslogSocketLockless::<D>::new(logstat, net_tap_prov)?;
1233
1234            let (inst, sender, run_ctrl) = 
1235                SyslogInternal::<F, D, S>::new(log_items, stream)?;
1236            
1237            
1238            let thr_name: String = "syslog_queue/0".into();
1239
1240            // initiate a thread
1241            let thread_hnd = 
1242                thread::Builder::new()
1243                    .name(thr_name.clone())
1244                    .spawn(move || SyslogInternal::<F, D, S>::thread_worker(inst))
1245                    .map_err(|e| 
1246                        map_error!("{} thread spawn failed. {}", thr_name, e)
1247                    )?;
1248
1249            let sy_q = 
1250                SyQueued
1251                {
1252                    run_control: 
1253                        run_ctrl,
1254                    tasks: 
1255                        sender,
1256                    thread: 
1257                        Arc::new(Mutex::new(Some(thread_hnd))),
1258                };
1259            
1260            return Ok( 
1261                Self
1262                {
1263                    log_items: 
1264                        (),
1265                    stream: 
1266                        sy_q,
1267                    _p: 
1268                        PhantomData,
1269                    _p_not_ss:
1270                        PhantomData
1271                }
1272            );
1273        }
1274    }
1275
1276    impl<F, D, S> Syslog<F, D, SyQueued<S, F, D>>
1277    where 
1278        F: SyslogFormatter,
1279        D: SyslogDestination,
1280        S: SyslogQueueChannel<F, D>
1281    {
1282        /// Connects the current instance to the syslog server (destination).
1283        pub 
1284        fn connectlog(&self) -> SyRes<()>
1285        {
1286            let (sy_cmd, loopback) = 
1287                SyCmd::form_connectlog();
1288
1289            self.stream.tasks.q_send_blocking(sy_cmd)?;
1290
1291            return 
1292                loopback
1293                    .recv_once_blocking()?;
1294        }
1295
1296        /// Sets the logmask to filter out the syslog calls.
1297        /// 
1298        /// See macroses [LOG_MASK] and [LOG_UPTO] to generate mask
1299        ///
1300        /// # Example
1301        ///
1302        /// LOG_MASK!(Priority::LOG_EMERG) | LOG_MASK!(Priority::LOG_ERROR)
1303        ///
1304        /// or
1305        ///
1306        /// ~(LOG_MASK!(Priority::LOG_INFO))
1307        /// LOG_UPTO!(Priority::LOG_ERROR)
1308        pub 
1309        fn setlogmask(&self, logmask: i32) -> SyRes<i32> 
1310        {
1311            let (sy_cmd, loopback) = 
1312                SyCmd::form_logmask(logmask);
1313
1314            self.stream.tasks.q_send_blocking(sy_cmd)?;
1315
1316            return 
1317                loopback
1318                    .recv_once_blocking();
1319        }
1320
1321        /// Closes connection to the syslog server (destination).
1322        pub 
1323        fn closelog(&self) -> SyRes<()> 
1324        {
1325            let (sy_cmd, loopback) = 
1326                SyCmd::form_disconnectlog();
1327
1328            // send stop
1329            self.stream.tasks.q_send_blocking(sy_cmd)?;
1330
1331            return 
1332                loopback
1333                    .recv_once_blocking()?;
1334        }
1335
1336        /// Similar to libc, syslog() sends data to syslog server.
1337        /// 
1338        /// # Arguments
1339        ///
1340        /// * `pri` - a priority [Priority]
1341        ///
1342        /// * `fmt` - a formatter [SyslogFormatter] message. In C exists a functions with
1343        ///     variable argumets amount. In Rust you should create your
1344        ///     own macros like format!() or use format!()]. The [String] and ref `'static` 
1345        ///     [str] can be passed directly.
1346        /// 
1347        /// # Returns 
1348        /// 
1349        /// A [SyRes] is returned which may describe an error.
1350        pub 
1351        fn syslog(&self, pri: Priority, fmt: F) -> SyRes<()>
1352        {
1353            // even if the thread is in a process of termination, there is
1354            // no need to sync access to the run_control field as even if
1355            // syslog thread will terminate before someone push something on the
1356            // queue, it will be left in the queue until the end of program's time.
1357            
1358            let sy_cmd = SyCmd::form_syslog(pri, fmt);
1359
1360            return self.stream.tasks.q_send_blocking(sy_cmd);
1361        }
1362
1363        /// This function can be used to update the facility name, for example
1364        /// after fork().
1365        /// 
1366        /// # Arguments
1367        /// 
1368        /// * `ident` - an [Option] optional new identity (up to 48 UTF8 chars)
1369        ///     If set to [Option::None] would request the program name from OS.
1370        pub 
1371        fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
1372        {
1373            let sy_cmd = 
1374                SyCmd::form_change_ident(ident.map(|v| v.to_string()));
1375
1376            return 
1377                self.stream.tasks.q_send_blocking(sy_cmd);
1378        }
1379
1380        /// Re-opens the connection to the syslog server. Can be used to 
1381        /// rotate logs(handle SIGHUP).
1382        /// 
1383        /// # Returns
1384        /// 
1385        /// A [Result] is retured as [SyRes].
1386        /// 
1387        /// * [Result::Ok] - with empty inner type.
1388        /// 
1389        /// * [Result::Err] - an error code and description 
1390        pub 
1391        fn reconnect(&self) -> SyRes<()>
1392        {
1393            return 
1394                self.stream.tasks.q_send_blocking(SyCmd::form_reconnect());
1395        }
1396
1397        /// Updates the instance's socket. `tap_data` [TapTypeData] should be of
1398        /// the same variant (type) as current.
1399        pub 
1400        fn update_tap_data(&self, tap_data: D) -> SyRes<()>
1401        {
1402            let (tap_data_cmd, loopback) = SyCmd::form_update_tap(tap_data);
1403
1404            self.stream.tasks.q_send_blocking(tap_data_cmd)?;
1405
1406            return 
1407                loopback
1408                    .recv_once_blocking()?;
1409        }
1410    }
1411
1412    impl<F, D, S> Syslog<F, D, SyQueued<S, F, D>>
1413    where 
1414        F: SyslogFormatter,
1415        D: SyslogDestination,
1416        S: SyslogQueueChannel<F, D>
1417    {
1418        /// Returns the streamable [SyStream] instance which can be used with [write!].
1419        /// 
1420        /// It implements both [std::fmt::Write] and [std::io::Write].
1421        /// 
1422        /// # Example
1423        /// 
1424        /// ```ignore
1425        /// let log = 
1426        ///     SingleSyslog::openlog(
1427        ///         Some("test1"), 
1428        ///         LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
1429        ///         LogFacility::LOG_DAEMON,
1430        ///         SyslogLocal::new()
1431        ///     ).unwrap();
1432        /// 
1433        /// write!(log.get_stream::<SyStreamPriDebug>(), "test stream singlesyslog {}", i).unwrap();
1434        /// ```
1435        pub 
1436        fn get_stream<'t, PRI>(&'t self) -> SyStream<'t, PRI, D, F, &'t Self>
1437        where PRI: SyStreamPri
1438        {
1439            SyStream
1440            {
1441                s: Some(self),
1442                _p: PhantomData,
1443                _p1: PhantomData,
1444                _p2: PhantomData
1445            }
1446        }
1447    }
1448
1449    impl<F, D, S> SyStreamSyslogApi<F, D>  
1450    for &Syslog<F, D, SyQueued<S, F, D>>
1451    where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
1452    {
1453        type SYSLOG<'t> = &'t Syslog<F, D, SyQueued<S, F, D>>;
1454
1455        fn syslog<'t>(syslog: Self::SYSLOG<'t>, pri: Priority, fmt: F) -> SyRes<()>
1456        {
1457            syslog.syslog(pri, fmt)
1458        }
1459    }
1460
1461
1462    /// A queued implementation for ASYNC.
1463    #[cfg(feature = "async_enabled")]
1464    pub mod syslog_async_queue
1465    {
1466        use crate::error::SyRes;
1467        use crate::sy_sync_queue::{SyCmd, SyslogQueueChanSnd, SyslogQueueChannel, SyslogQueueOneChanRcv};
1468        use crate::{Priority, Syslog};
1469        use crate::{formatters::SyslogFormatter, SyslogDestination, SyQueued};
1470        use crate::a_sync::syslog_trait::AsyncSyslogQueueApi;
1471
1472        impl<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>> AsyncSyslogQueueApi<F, D> 
1473        for Syslog<F, D, SyQueued<S, F, D>>
1474        {
1475            async 
1476            fn a_connectlog(&mut self) -> SyRes<()> 
1477            {
1478                let (sy_cmd, loopback) = 
1479                    SyCmd::form_connectlog();
1480
1481                self.stream.tasks.q_send(sy_cmd).await?;
1482
1483                return 
1484                    loopback
1485                        .recv_once()
1486                        .await?;
1487            }
1488
1489            /// Sets the logmask to filter out the syslog calls. This function behaves 
1490            /// differently as it behaves in syslog_sync.rs or syslog_async.rs.
1491            /// It may return an error if: syslog thread had exit and some thread calls
1492            /// this function. Or something happened with channel. 
1493            /// This function blocks until the previous mask is received.
1494            /// 
1495            /// See macroses [LOG_MASK] and [LOG_UPTO] to generate mask
1496            ///
1497            /// # Example
1498            ///
1499            /// LOG_MASK!(Priority::LOG_EMERG) | LOG_MASK!(Priority::LOG_ERROR)
1500            ///
1501            /// or
1502            ///
1503            /// ~(LOG_MASK!(Priority::LOG_INFO))
1504            /// LOG_UPTO!(Priority::LOG_ERROR) 
1505            async 
1506            fn a_setlogmask(&self, logmask: i32) -> SyRes<i32>
1507            {
1508                let (sy_cmd, loopback) = 
1509                    SyCmd::form_logmask(logmask);
1510
1511                self.stream.tasks.q_send(sy_cmd).await?;
1512
1513                return 
1514                    loopback
1515                        .recv_once()
1516                        .await;
1517            }
1518
1519            /// Closes connection to the syslog server
1520            async 
1521            fn a_closelog(&self) -> SyRes<()>
1522            {
1523                let (sy_cmd, loopback) = 
1524                    SyCmd::form_disconnectlog();
1525
1526                // send stop
1527                self.stream.tasks.q_send(sy_cmd).await?;
1528
1529                return 
1530                    loopback
1531                        .recv_once()
1532                        .await?;
1533            }
1534
1535            /// Similar to libc, syslog() sends data to syslog server, but asynchroniously.
1536            /// 
1537            /// # Arguments
1538            ///
1539            /// * `pri` - a priority [Priority]
1540            ///
1541            /// * `fmt` - a program's message to be sent as payload. The message is encoded with the
1542            ///     [SyslogFormatter] and may be different for different formatters.
1543            #[inline]
1544            async 
1545            fn a_syslog(&self, pri: Priority, fmt: F) -> SyRes<()>
1546            {
1547                let sy_cmd = SyCmd::form_syslog(pri, fmt);
1548
1549                return self.stream.tasks.q_send(sy_cmd).await;
1550            }
1551
1552
1553            /// Performs the reconnection to the syslog server or file re-open.
1554            /// 
1555            /// # Returns
1556            /// 
1557            /// A [Result] is retured as [SyRes].
1558            /// 
1559            /// * [Result::Ok] - with empty inner type.
1560            /// 
1561            /// * [Result::Err] - an error code and description
1562            async 
1563            fn a_reconnect(&self) -> SyRes<()>
1564            {
1565                return 
1566                    self.stream.tasks.q_send(SyCmd::form_reconnect()).await;
1567            }
1568
1569            async 
1570            fn a_change_identity(&self, ident: &str) -> SyRes<()> 
1571            {
1572                let sy_cmd = 
1573                    SyCmd::form_change_ident(Some(ident.to_string()));
1574
1575                return 
1576                    self.stream.tasks.q_send(sy_cmd).await;
1577            }
1578
1579            /// Updates the inner instance destionation i.e path to file
1580            /// or server address. The type of destination can not be changed.
1581            /// 
1582            /// This function disconnects from syslog server if previously was 
1583            /// connected (and reconnects if was connected previously).
1584            /// 
1585            /// # Arguments 
1586            /// 
1587            /// * `new_tap` - a consumed instance of type `D` [SyslogDestination]
1588            /// 
1589            /// # Returns 
1590            /// 
1591            /// A [SyRes] is returned. An error may be returned if:
1592            /// 
1593            /// * connection to server was failed
1594            /// 
1595            /// * incorrect type
1596            /// 
1597            /// * disconnect frm server failed
1598            async 
1599            fn a_update_tap_data(&self, new_tap: D) -> SyRes<()>
1600            {
1601                let (tap_data_cmd, loopback) = SyCmd::form_update_tap(new_tap);
1602
1603                self.stream.tasks.q_send(tap_data_cmd).await?;
1604
1605                return 
1606                    loopback
1607                        .recv_once()
1608                        .await?;
1609            }
1610        }
1611    }
1612}
1613
1614#[cfg(feature = "build_with_queue")]
1615pub use self::build_with_queue::SyQueued;