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