1use std::marker::PhantomData;
18use std::{fmt, thread};
19use std::sync::{Arc, Mutex, Weak};
20use std::sync::atomic::{AtomicBool, Ordering};
21
22use crate::formatters::{DefaultSyslogFormatter, SyslogFormatter};
23use crate::sync::syslog_sync_internal::SyslogSocketLockless;
24use crate::sync::{LogItems, SyStream};
25use crate::sync::DefaultQueueAdapter;
26
27use crate::{map_error, SyStreamApi, SyslogDestination};
28
29#[cfg(target_family = "unix")]
30use crate::SyslogLocal;
31
32#[cfg(target_family = "windows")]
33use crate::WindowsEvent;
34
35#[cfg(target_family = "unix")]
36pub type DefaultLocalSyslogDestination = SyslogLocal;
37#[cfg(target_family = "windows")]
38pub type DefaultLocalSyslogDestination = WindowsEvent;
39
40use crate::common::*;
41use crate::error::SyRes;
42
43use super::syslog_trait::SyslogApi;
44
45
46pub enum SyCmd<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>>
48{
49 Syslog
51 {
52 pri: Priority,
53 msg: F
54 },
55
56 Logmask
58 {
59 logmask: i32,
60 loopback: S::OneShotChannelSnd<i32>,
61 },
62
63 ChangeIdentity
65 {
66 identity: Option<String>,
67 },
68
69 UpdateTap
71 {
72 tap_type: D,loopback: S::OneShotChannelSnd<SyRes<()>>,
74 },
75
76 ConnectLog
77 {
78 loopback: S::OneShotChannelSnd<SyRes<()>>
79 },
80
81 DisconnectLog
82 {
83 loopback: S::OneShotChannelSnd<SyRes<()>>
84 },
85
86 Reconnect,
88
89 #[allow(unused)]
91 Stop,
92}
93
94
95impl<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>> SyCmd<F, D, S>
96{
97 pub(crate)
99 fn form_syslog(pri: Priority, msg: F) -> Self
100 {
101 return
102 Self::Syslog
103 {
104 pri, msg
105 };
106 }
107
108 pub(crate)
109 fn form_connectlog() -> (Self, S::OneShotChannelRcv<SyRes<()>>)
110 {
111 let (tx, rx) = S::create_oneshot_channel::<SyRes<()>>();
112
113 return
114 (Self::ConnectLog{ loopback: tx }, rx);
115 }
116
117 pub(crate)
118 fn form_disconnectlog() -> (Self, S::OneShotChannelRcv<SyRes<()>>)
119 {
120 let (tx, rx) = S::create_oneshot_channel::<SyRes<()>>();
121
122 return
123 (Self::DisconnectLog{ loopback: tx }, rx);
124 }
125
126 pub(crate)
132 fn form_logmask(logmask: i32) -> (Self, S::OneShotChannelRcv<i32>)
133 {
134 let (tx, rx) = S::create_oneshot_channel::<i32>();
135
136 return
137 (Self::Logmask{ logmask, loopback: tx }, rx);
138 }
139
140 pub(crate)
143 fn form_change_ident(identity: Option<String>) -> Self
144 {
145 return
146 Self::ChangeIdentity
147 {
148 identity: identity
149 };
150 }
151
152 pub(crate)
156 fn form_update_tap(new_tap_type: D) -> (Self, S::OneShotChannelRcv<SyRes<()>>)
157 {
158 let (tx, rx) = S::create_oneshot_channel::<SyRes<()>>();
159
160 return (
161 Self::UpdateTap
162 {
163 tap_type: new_tap_type,
164 loopback: tx
165 },
166 rx
167 );
168 }
169
170 pub(crate)
173 fn form_reconnect() -> Self
174 {
175 return Self::Reconnect;
176 }
177
178 #[allow(unused)]
183 pub(crate)
184 fn form_stop() -> Self
185 {
186 return Self::Stop;
187 }
188}
189
190struct SyslogInternal<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>>
192{
193 run_flag: Arc<AtomicBool>,
195
196 tasks: S::ChannelRcv,
198
199 log_items: LogItems,
201
202 socket: SyslogSocketLockless<D>,
204}
205
206
207
208impl<F, D, S> SyslogInternal<F, D, S>
209where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
210{
211 fn new(log_items: LogItems, socket: SyslogSocketLockless<D>) -> SyRes<(Self, S::ChannelSnd, Weak<AtomicBool>)>
212 {
213 let run_flag: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));
215 let run_control = Arc::downgrade(&run_flag);
216
217 let (sender, receiver) = S::create_channel();
219
220 let mut inst =
222 SyslogInternal
223 {
224 run_flag: run_flag,
225 tasks: receiver,
226 log_items: log_items,
227 socket: socket
228 };
229
230 if inst.log_items.logstat.contains(LogStat::LOG_NDELAY) == true
231 {
232 inst.socket.connectlog()?;
233 }
234
235 return Ok((inst, sender, run_control));
236 }
237
238 fn thread_worker(mut self)
239 {
240 loop
241 {
242 if self.run_flag.load(Ordering::Relaxed) == false
244 {
245 break;
247 }
248
249 match self.tasks.q_recv_blocking()
250 {
251 Some(task) =>
252 {
253 match task
254 {
255 SyCmd::Syslog{ pri, msg } =>
256 {
257 let Some(formatted) = self.log_items.vsyslog1_msg::<F, D>(pri, &msg)
258 else { continue };
259
260 self.socket.vsyslog1(formatted.1, formatted.0);
261 },
262 SyCmd::Logmask{ logmask, loopback } =>
263 {
264 let pri = self.log_items.set_logmask(logmask);
265
266 let _ = loopback.send_once_blocking(pri);
267 },
268 SyCmd::ChangeIdentity{ identity } =>
269 {
270 self.log_items.set_identity(identity.as_ref().map(|v| v.as_str()));
271 },
272
273 SyCmd::UpdateTap{ tap_type, loopback } =>
274 {
275 let res = self.socket.update_tap_data(tap_type);
276
277 if let Err(Err(e)) = loopback.send_once_blocking(res)
278 {
279 self.log_items.logstat.send_to_stderr(&e.to_string());
280 }
281 },
282
283 SyCmd::ConnectLog{ loopback} =>
284 {
285 if let Err(Err(e)) = loopback.send_once_blocking(self.socket.connectlog())
286 {
287 self.log_items.logstat.send_to_stderr(&e.to_string());
288 }
289 },
290
291 SyCmd::DisconnectLog{ loopback} =>
292 {
293 if let Err(Err(e)) = loopback.send_once_blocking(self.socket.disconnectlog())
294 {
295 self.log_items.logstat.send_to_stderr(&e.to_string());
296 }
297 },
298
299 SyCmd::Reconnect =>
300 {
301 if let Err(e) = self.socket.disconnectlog()
302 {
303 self.log_items.logstat.send_to_stderr(&e.to_string());
304 }
305
306 if let Err(e) = self.socket.connectlog()
307 {
308 self.log_items.logstat.send_to_stderr(&e.to_string());
309 }
310 },
311 SyCmd::Stop =>
312 {
313 break;
315 }
316 }
317 },
318 None =>
319 {
320 break;
321 }
322 } } return;
327 }
328}
329
330pub trait SyslogQueueChanRcv<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>>: fmt::Debug + Send
333{
334 fn q_recv_blocking(&mut self) -> Option<SyCmd<F, D, S>>;
336}
337
338#[allow(async_fn_in_trait)]
341pub trait SyslogQueueChanSnd<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>>: fmt::Debug + Clone
342{
343 fn q_send_blocking(&self, msg: SyCmd<F, D, S>) -> SyRes<()>;
345
346 async fn q_send(&self, _msg: SyCmd<F, D, S>) -> SyRes<()>
348 {
349 crate::throw_error!("async is not availabe here");
350 }
351}
352
353#[allow(async_fn_in_trait)]
356pub trait SyslogQueueOneChanRcv<C>
357{
358 fn recv_once_blocking(self) -> SyRes<C>;
360
361 async fn recv_once(self) -> SyRes<C> where Self: Sized
364 {
365 crate::throw_error!("async is not availabe here");
366 }
367}
368
369pub trait SyslogQueueOneChanSnd<C: Send>: fmt::Debug + Send
372{
373 fn send_once_blocking(self, data: C) -> Result<(), C>;
375}
376
377pub trait SyslogQueueChannel<F: SyslogFormatter, D: SyslogDestination>: fmt::Debug + Send + Clone + 'static
381{
382 const ADAPTER_NAME: &'static str;
383
384 type ChannelSnd: SyslogQueueChanSnd<F, D, Self>;
386
387 type ChannelRcv: SyslogQueueChanRcv<F, D, Self>;
389
390 type OneShotChannelSnd<C: Send + fmt::Debug>: SyslogQueueOneChanSnd<C>;
392
393 type OneShotChannelRcv<C>: SyslogQueueOneChanRcv<C>;
395
396 fn create_channel() -> (Self::ChannelSnd, Self::ChannelRcv);
398
399 fn create_oneshot_channel<C: Send + fmt::Debug>() -> (Self::OneShotChannelSnd<C>, Self::OneShotChannelRcv<C>);
401}
402
403
404
405#[derive(Debug, Clone)]
470pub struct QueuedSyslog<S = DefaultQueueAdapter, F = DefaultSyslogFormatter, D = DefaultLocalSyslogDestination>
471where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
472{
473 run_control: Weak<AtomicBool>,
475
476 pub(crate) tasks: S::ChannelSnd,thread: Arc<Mutex<Option<thread::JoinHandle<()>>>>,
481
482 _p: PhantomData<F>,
484
485 _p2: PhantomData<D>,
487}
488
489
490unsafe impl<F, D, S> Send for QueuedSyslog<S, F, D>
491where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
492{}
493
494
495impl<F, D, S> Drop for QueuedSyslog<S, F, D>
496where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
497{
498 fn drop(&mut self)
499 {
500 if let Some(ctrl) = self.run_control.upgrade()
501 {
502 ctrl.store(false, Ordering::SeqCst);
503
504 if let Err(_e) = self.tasks.q_send_blocking(SyCmd::form_stop())
505 {
506
507 }
508
509 let join_handle = self.thread.lock().unwrap().take().unwrap();
510
511 let _ = join_handle.join();
512 }
513 }
514}
515
516impl QueuedSyslog
517{
518 pub
540 fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: DefaultLocalSyslogDestination) -> SyRes<Self>
541 {
542 let log_items =
545 LogItems::new(ident, 0xff, logstat, facility);
546
547 let stream =
548 SyslogSocketLockless::<DefaultLocalSyslogDestination>::new(logstat, net_tap_prov)?;
549
550 let (inst, sender, run_ctrl) =
551 SyslogInternal
552 ::<DefaultSyslogFormatter, DefaultLocalSyslogDestination, DefaultQueueAdapter>
553 ::new(log_items, stream)?;
554
555
556 let thr_name: String = "syslog_queue/0".into();
557
558 let thread_hnd =
560 thread::Builder::new()
561 .name(thr_name.clone())
562 .spawn(move ||
563 SyslogInternal
564 ::<DefaultSyslogFormatter, DefaultLocalSyslogDestination, DefaultQueueAdapter>
565 ::thread_worker(inst)
566 )
567 .map_err(|e|
568 map_error!("{} thread spawn failed. {}", thr_name, e)
569 )?;
570
571 let ret =
573 Self
574 {
575 run_control: run_ctrl,
576 tasks: sender,
577 thread: Arc::new(Mutex::new(Some(thread_hnd))),
578 _p: PhantomData,
579 _p2: PhantomData
580 };
581
582 return Ok(ret);
583 }
584}
585
586impl<F, D, S> QueuedSyslog<S, F, D>
587where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
588{
589 pub
611 fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<QueuedSyslog<S, F, D>>
612 {
613 let log_items =
616 LogItems::new(ident, 0xff, logstat, facility);
617
618 let stream =
619 SyslogSocketLockless::<D>::new(logstat, net_tap_prov)?;
620
621 let (inst, sender, run_ctrl) =
622 SyslogInternal::<F, D, S>::new(log_items, stream)?;
623
624
625 let thr_name: String = "syslog_queue/0".into();
626
627 let thread_hnd =
629 thread::Builder::new()
630 .name(thr_name.clone())
631 .spawn(move || SyslogInternal::<F, D, S>::thread_worker(inst))
632 .map_err(|e|
633 map_error!("{} thread spawn failed. {}", thr_name, e)
634 )?;
635
636 let ret =
638 Self
639 {
640 run_control: run_ctrl,
641 tasks: sender,
642 thread: Arc::new(Mutex::new(Some(thread_hnd))),
643 _p: PhantomData::<F>,
644 _p2: PhantomData::<D>,
645 };
646
647 return Ok(ret);
648 }
649}
650
651
652impl<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>> SyslogApi<F, D>
653for QueuedSyslog<S, F, D>
654{
655 fn connectlog(&self) -> SyRes<()>
656 {
657 let (sy_cmd, loopback) =
658 SyCmd::form_connectlog();
659
660 self.tasks.q_send_blocking(sy_cmd)?;
661
662 return
663 loopback
664 .recv_once_blocking()?;
665 }
666
667 fn setlogmask(&self, logmask: i32) -> SyRes<i32>
668 {
669 let (sy_cmd, loopback) =
670 SyCmd::form_logmask(logmask);
671
672 self.tasks.q_send_blocking(sy_cmd)?;
673
674 return
675 loopback
676 .recv_once_blocking();
677 }
678
679 fn closelog(&self) -> SyRes<()>
680 {
681 let (sy_cmd, loopback) =
682 SyCmd::form_disconnectlog();
683
684 self.tasks.q_send_blocking(sy_cmd)?;
686
687 return
688 loopback
689 .recv_once_blocking()?;
690 }
691
692 fn syslog(&self, pri: Priority, fmt: F)
693 {
694 let sy_cmd = SyCmd::form_syslog(pri, fmt);
700
701 let _ = self.tasks.q_send_blocking(sy_cmd);
702 return;
705 }
706
707 fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
708 {
709 let sy_cmd =
710 SyCmd::form_change_ident(ident.map(|v| v.to_string()));
711
712 return
713 self.tasks.q_send_blocking(sy_cmd);
714 }
715
716 fn reconnect(&self) -> SyRes<()>
717 {
718 return
719 self.tasks.q_send_blocking(SyCmd::form_reconnect());
720 }
721
722 fn update_tap_data(&self, tap_data: D) -> SyRes<()>
723 {
724 let (tap_data_cmd, loopback) = SyCmd::form_update_tap(tap_data);
725
726 self.tasks.q_send_blocking(tap_data_cmd)?;
727
728 return
729 loopback
730 .recv_once_blocking()?;
731 }
732}
733
734
735impl<'stream, F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>> SyStreamApi<'stream, F, D, QueuedSyslog<S, F, D>>
736for QueuedSyslog<S, F, D>
737{
738 fn stream(&'stream self, pri: Priority) -> SyStream<'stream, D, F, QueuedSyslog<S, F, D>>
739 {
740 return
741 SyStream
742 {
743 inner: self,
744 pri: pri,
745 _p: PhantomData,
746 _p1: PhantomData
747 };
748 }
749}
750
751#[cfg(all(feature = "build_with_queue", feature = "async_enabled"))]
753pub mod syslog_async_queue
754{
755 use crate::error::SyRes;
756 use crate::sy_sync_queue::{SyCmd, SyslogQueueChanSnd, SyslogQueueChannel, SyslogQueueOneChanRcv};
757 use crate::Priority;
758 use crate::{formatters::SyslogFormatter, SyslogDestination, QueuedSyslog};
759 use crate::a_sync::syslog_trait::AsyncSyslogQueueApi;
760
761 impl<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>> AsyncSyslogQueueApi<F, D>
762 for QueuedSyslog<S, F, D>
763 {
764 async
765 fn a_connectlog(&mut self) -> SyRes<()>
766 {
767 let (sy_cmd, loopback) =
768 SyCmd::form_connectlog();
769
770 self.tasks.q_send(sy_cmd).await?;
771
772 return
773 loopback
774 .recv_once()
775 .await?;
776 }
777
778 async
795 fn a_setlogmask(&self, logmask: i32) -> SyRes<i32>
796 {
797 let (sy_cmd, loopback) =
798 SyCmd::form_logmask(logmask);
799
800 self.tasks.q_send(sy_cmd).await?;
801
802 return
803 loopback
804 .recv_once()
805 .await;
806 }
807
808 async
810 fn a_closelog(&self) -> SyRes<()>
811 {
812 let (sy_cmd, loopback) =
813 SyCmd::form_disconnectlog();
814
815 self.tasks.q_send(sy_cmd).await?;
817
818 return
819 loopback
820 .recv_once()
821 .await?;
822 }
823
824 #[inline]
833 async
834 fn a_syslog(&self, pri: Priority, fmt: F)
835 {
836 let sy_cmd = SyCmd::form_syslog(pri, fmt);
837
838 let _ = self.tasks.q_send(sy_cmd).await;
839
840 return;
841 }
842
843
844 async
854 fn a_reconnect(&self) -> SyRes<()>
855 {
856 return
857 self.tasks.q_send(SyCmd::form_reconnect()).await;
858 }
859
860 async
861 fn a_change_identity(&self, ident: &str) -> SyRes<()>
862 {
863 let sy_cmd =
864 SyCmd::form_change_ident(Some(ident.to_string()));
865
866 return
867 self.tasks.q_send(sy_cmd).await;
868 }
869
870 async
890 fn a_update_tap_data(&self, new_tap: D) -> SyRes<()>
891 {
892 let (tap_data_cmd, loopback) = SyCmd::form_update_tap(new_tap);
893
894 self.tasks.q_send(tap_data_cmd).await?;
895
896 return
897 loopback
898 .recv_once()
899 .await?;
900 }
901 }
902}
903
904
905
906#[cfg(all(feature = "build_with_queue", not(feature = "async_enabled")))]
907#[cfg(test)]
908mod test_queue_sync
909{
910 use crate::{formatters::DefaultSyslogFormatter, sync::{crossbeam_queue_adapter::DefaultQueueAdapter}, LogFacility, LogStat, Priority, SyslogApi, QueuedSyslog};
911
912 use super::DefaultLocalSyslogDestination;
913
914 #[cfg(target_family = "unix")]
915 use crate::SyslogLocal;
916
917 #[cfg(target_family = "windows")]
918 use crate::WindowsEvent;
919
920 #[test]
921 fn test_queue_single_message()
922 {
923 #[cfg(target_family = "unix")]
924 let syslog_provider =
925 SyslogLocal::new();
926
927 #[cfg(target_family = "windows")]
928 let syslog_provider =
929 WindowsEvent::new();
930
931 let log =
932 QueuedSyslog
933 ::<DefaultQueueAdapter, DefaultSyslogFormatter, DefaultLocalSyslogDestination>
934 ::openlog_with(
935 Some("queue_single_message"),
936 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
937 LogFacility::LOG_DAEMON,
938 syslog_provider
939 );
940
941 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
942
943 let log = log.unwrap();
944
945 let msg1 = format!("test UTF-8 проверка BOM UTF-8");
946 let now = std::time::Instant::now();
947
948 log.syslog(Priority::LOG_DEBUG, msg1.into());
949
950 let dur = now.elapsed();
951 println!("{:?}", dur);
952
953 let msg2 = format!("test UTF-8 きるさお命泉ぶねりよ日子金れっ");
954
955 let now = std::time::Instant::now();
956
957 log.syslog(Priority::LOG_DEBUG, msg2.into());
958
959 let dur = now.elapsed();
960 println!("{:?}", dur);
961
962 let _ = log.closelog();
963
964 return;
965 }
966}
967
968#[cfg(all(feature = "build_with_queue", feature = "async_embedded"))]
969#[cfg(test)]
970mod tests_queue
971{
972 use crate::{formatters::DefaultSyslogFormatter, sync::DefaultQueueAdapter, LogFacility, LogStat, Priority, QueuedSyslog, SyslogApi};
973
974 use super::DefaultLocalSyslogDestination;
975
976 #[cfg(target_family = "unix")]
977 use crate::SyslogLocal;
978
979 #[cfg(target_family = "windows")]
980 use crate::WindowsEvent;
981
982 #[test]
983 fn test_multithreading()
984 {
985 use std::sync::Arc;
986 use std::thread;
987 use std::time::{Instant, Duration};
988 use crate::LOG_MASK;
989
990 #[cfg(target_family = "unix")]
991 let syslog_provider =
992 SyslogLocal::new();
993
994 #[cfg(target_family = "windows")]
995 let syslog_provider =
996 WindowsEvent::new();
997
998
999 let log =
1000 QueuedSyslog
1001 ::<DefaultQueueAdapter, DefaultSyslogFormatter, DefaultLocalSyslogDestination>
1002 ::openlog_with(
1003 Some("test5"),
1004 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
1005 LogFacility::LOG_DAEMON, syslog_provider
1006 );
1007
1008 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
1009
1010 let log = Arc::new(log.unwrap());
1011 let c1_log = log.clone();
1012 let c2_log = log.clone();
1013
1014 thread::spawn(move|| {
1015 for i in 0..5
1016 {
1017 thread::sleep(Duration::from_nanos(200));
1018 let now = Instant::now();
1019 c1_log.syslog(Priority::LOG_DEBUG, format!("a message from thread 1 #{}[]", i).into());
1020 let elapsed = now.elapsed();
1021 println!("t1: {:?}", elapsed);
1022 }
1023 });
1024
1025 thread::spawn(move|| {
1026 for i in 0..5
1027 {
1028 thread::sleep(Duration::from_nanos(201));
1029 let now = Instant::now();
1030 c2_log.syslog(Priority::LOG_DEBUG, format!("きるさお命泉ぶねりよ日子金れっ {}", i).into());
1031 let elapsed = now.elapsed();
1032 println!("t2: {:?}", elapsed);
1033 }
1034 });
1035
1036 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
1037
1038 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1039 assert_eq!(res.unwrap(), 0xff, "should be 0xff");
1040
1041 let now = Instant::now();
1042 log.syslog(Priority::LOG_DEBUG, format!("A message from main, сообщение от главнюка").into());
1043 let elapsed = now.elapsed();
1044 println!("main: {:?}", elapsed);
1045
1046 thread::sleep(Duration::from_secs(2));
1047
1048 let _ = log.closelog();
1049
1050 thread::sleep(Duration::from_millis(500));
1051
1052 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
1053
1054 assert_eq!(res.is_ok(), true);
1055
1056 return;
1057 }
1058
1059 #[cfg(feature = "build_ext_file")]
1060 #[test]
1061 fn test_file_multithreading()
1062 {
1063 use std::sync::Arc;
1064 use std::thread;
1065 use std::time::{Instant, Duration};
1066 use crate::formatters::DefaultSyslogFormatterFile;
1067 use crate::{SyslogFile, LOG_MASK};
1068
1069 let log =
1070 QueuedSyslog
1071 ::<DefaultQueueAdapter, DefaultSyslogFormatterFile, SyslogFile>
1072 ::openlog_with(
1073 Some("test2"),
1074 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
1075 LogFacility::LOG_DAEMON,
1076 SyslogFile::new("/tmp/syslog_rs_test2.log")
1077 );
1078
1079
1080 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
1081
1082 let log = Arc::new(log.unwrap());
1083 let c1_log = log.clone();
1084 let c2_log = log.clone();
1085
1086 thread::spawn(move|| {
1087 for i in 0..5
1088 {
1089 thread::sleep(Duration::from_nanos(200));
1090 let now = Instant::now();
1091 c1_log.syslog(Priority::LOG_ALERT, format!("a message from thread 1 #{}[]", i).into());
1092 let elapsed = now.elapsed();
1093 println!("t1: {:?}", elapsed);
1094 }
1095 });
1096
1097 thread::spawn(move|| {
1098 for i in 0..5
1099 {
1100 thread::sleep(Duration::from_nanos(201));
1101 let now = Instant::now();
1102 c2_log.syslog(Priority::LOG_DEBUG, format!("きるさお命泉ぶねりよ日子金れっ {}", i).into());
1103 let elapsed = now.elapsed();
1104 println!("t2: {:?}", elapsed);
1105 }
1106 });
1107
1108 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
1109
1110 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1111 assert_eq!(res.unwrap(), 0xff, "should be 0xff");
1112
1113 let now = Instant::now();
1114 log.syslog(Priority::LOG_DEBUG, format!("A message from main, きるさお命泉ぶねりよ日子金れっ").into());
1115 let elapsed = now.elapsed();
1116 println!("main: {:?}", elapsed);
1117
1118 thread::sleep(Duration::from_secs(2));
1119
1120 let _ = log.closelog();
1121
1122 thread::sleep(Duration::from_millis(500));
1123
1124 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
1125
1126 assert_eq!(res.is_ok(), true);
1127
1128 return;
1129 }
1130}