1use std::{fmt::{self, Arguments, Write}, marker::PhantomData};
23
24use crate::{error::SyRes, formatters::{DefaultSyslogFormatter, SyslogFormatter}, sy_sync_queue::SyslogQueueAdapter, syslog_provider::*, LogFacility, LogStat, Priority};
25
26#[cfg(feature = "use_sync_queue")]
27use crate::sy_sync_queue::SyslogQueue;
28
29
30use super::syslog_sync_shared::SyslogShared;
31use super::{syslog_stream::SyslogStream, syslog_trait::SyslogApi};
32
33
34#[derive(Debug)]
47pub struct Syslog<D = SyslogLocal, F = DefaultSyslogFormatter, S = SyslogShared<F>>
48 (S, PhantomData<F>, PhantomData<D>)
49where D: SyslogDestination, F: SyslogFormatter, S: SyslogApi;
50
51impl Syslog
52{
53 pub
75 fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility, dest: SyslogLocal) -> SyRes<Self>
76 {
77 let net_tap = dest.init()?;
78
79 let syslog = SyslogShared::<DefaultSyslogFormatter>::openlog(ident, logstat, facility, net_tap)?;
80
81 return Ok(Self(syslog, PhantomData::<DefaultSyslogFormatter>, PhantomData::<SyslogLocal>));
82 }
83}
84
85#[cfg(feature = "use_sync")]
86impl<D: SyslogDestination, F: SyslogFormatter> Syslog<D, F, SyslogShared<F>>
87{
88 pub
112 fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, dest: D) -> SyRes<Syslog<D, F, SyslogShared<F>>>
113 {
114 let net_tap = dest.init()?;
115
116 let syslog = SyslogShared::<F>::openlog(ident, logstat, facility, net_tap)?;
117
118 return Ok(Self(syslog, PhantomData::<F>, PhantomData::<D>));
119 }
120
121 pub
138 fn setlogmask(&self, logmask: i32) -> SyRes<i32>
139 {
140 return self.0.setlogmask(logmask);
141 }
142
143 pub
147 fn change_identity(&self, ident: &str) -> SyRes<()>
148 {
149 return self.0.change_identity(ident);
150 }
151
152 pub
154 fn closelog(&self) -> SyRes<()>
155 {
156 return self.0.closelog();
157 }
158
159 #[inline]
167 pub
168 fn syslog(&self, pri: Priority, fmt: String)
169 {
170 self.0.syslog(pri, fmt);
171 }
172
173 #[inline]
175 pub
176 fn vsyslog<M: AsRef<str>>(&self, pri: Priority, fmt: M)
177 {
178 self.0.vsyslog(pri, fmt);
179 }
180
181 pub
191 fn reconnect(&self) -> SyRes<()>
192 {
193 return self.0.reconnect();
194 }
195
196 pub
216 fn update_tap(&self, new_tap: D) -> SyRes<()>
217 {
218 return self.0.update_tap_data(new_tap.init()?);
219 }
220
221 pub
225 fn make_stream(&self, pri: Priority) -> Box<dyn SyslogStream>
226 {
227 let inst =
228 StreamableSyslog
229 {
230 inner: self.0.clone(),
231 pri: pri,
232 _p: PhantomData::<F>,
233 };
234
235 return Box::new(inst);
236 }
237}
238
239#[cfg(feature = "use_sync_queue")]
240impl<D: SyslogDestination, F: SyslogFormatter> Syslog<D, F, SyslogQueue<F>>
241{
242 pub
266 fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, dest: D) -> SyRes<Syslog<D, F, SyslogQueue<F>>>
267 {
268 let net_tap = dest.init()?;
269
270 let syslog = SyslogQueue::<F>::openlog(ident, logstat, facility, net_tap)?;
271
272 return Ok(Self(syslog, PhantomData::<F>, PhantomData::<D>));
273 }
274
275 pub
292 fn setlogmask(&self, logmask: i32) -> SyRes<i32>
293 {
294 return self.0.setlogmask(logmask);
295 }
296
297 pub
299 fn closelog(&self) -> SyRes<()>
300 {
301 return self.0.closelog();
302 }
303
304 #[inline]
312 pub
313 fn syslog(&self, pri: Priority, fmt: String)
314 {
315 self.0.syslog(pri, fmt);
316 }
317
318 #[inline]
320 pub
321 fn vsyslog<M: AsRef<str>>(&self, pri: Priority, fmt: M)
322 {
323 self.0.vsyslog(pri, fmt);
324 }
325
326 pub
336 fn reconnect(&self) -> SyRes<()>
337 {
338 return self.0.reconnect();
339 }
340
341 pub
361 fn update_tap(&self, new_tap: D) -> SyRes<()>
362 {
363 return self.0.update_tap_data(new_tap.init()?);
364 }
365
366 pub
370 fn make_stream(&self, pri: Priority) -> Box<dyn SyslogStream>
371 {
372 let inst =
373 StreamableSyslog
374 {
375 inner: self.0.clone(),
376 pri: pri,
377 _p: PhantomData::<F>,
378 };
379
380 return Box::new(inst);
381 }
382}
383
384#[cfg(all(feature = "use_sync_queue", feature = "use_async"))]
385impl<D: SyslogDestination, F: SyslogFormatter> Syslog<D, F, SyslogQueue<F>>
386{
387 pub
388 fn make_adapter(&self) -> SyslogQueueAdapter
389 {
390 return self.0.make_adapter();
391 }
392}
393
394#[cfg(feature = "build_with_net")]
395impl<F: SyslogFormatter, S: SyslogApi> Syslog<SyslogNet, F, S>
396{
397
398}
399
400#[cfg(feature = "build_with_file")]
401impl<F: SyslogFormatter, S: SyslogApi> Syslog<SyslogFile, F, S>
402{
403
404}
405
406impl<F: SyslogFormatter, S: SyslogApi> Syslog<SyslogLocal, F, S>
407{
408
409}
410
411#[cfg(feature = "build_with_tls")]
412impl<F: SyslogFormatter, S: SyslogApi> Syslog<SyslogTls, F, S>
413{
414
415}
416
417
418struct StreamableSyslog<F: SyslogFormatter, S: SyslogApi>
424{
425 inner: S,
427
428 pri: Priority,
430
431 _p: PhantomData<F>
432}
433
434impl<F: SyslogFormatter, S: SyslogApi> SyslogStream for StreamableSyslog<F, S>
435{
436 fn update_pri(&mut self, new_pri: Priority) -> Priority
438 {
439 let prev = self.pri;
440 self.pri = new_pri;
441
442 return prev;
443 }
444}
445
446impl<F: SyslogFormatter, S: SyslogApi> Write for StreamableSyslog<F, S>
447{
448 fn write_str(&mut self, s: &str) -> fmt::Result
449 {
450 self.inner.vsyslog(self.pri, s);
451
452 return Ok(());
453 }
454
455 fn write_fmt(self: &mut Self, args: Arguments<'_>) -> fmt::Result
456 {
457 if let Some(s) = args.as_str()
458 {
459 return self.write_str(s);
460 }
461 else
462 {
463 return self.write_str(&args.to_string());
464 }
465 }
466}
467
468#[cfg(feature = "use_sync")]
482#[cfg(test)]
483mod tests_shared
484{
485 use super::*;
486
487 #[test]
488 fn test_single_message()
489 {
490
491
492 let log =
493 Syslog::openlog(
494 Some("test1"),
495 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
496 LogFacility::LOG_DAEMON,
497 SyslogLocal::new());
498
499 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
500
501 let log = log.unwrap();
502
503 let now = std::time::Instant::now();
504
505 log.syslog(Priority::LOG_DEBUG, format!("test UTF-8 проверка BOM UTF-8"));
506
507 let dur = now.elapsed();
508 println!("{:?}", dur);
509
510 let now = std::time::Instant::now();
511
512 log.syslog(Priority::LOG_DEBUG, format!("test UTF-8 きるさお命泉ぶねりよ日子金れっ"));
513
514 let dur = now.elapsed();
515 println!("{:?}", dur);
516
517 let _ = log.closelog();
518
519 return;
520 }
521
522 #[test]
523 fn test_single_message_perror()
524 {
525 let log =
531 Syslog::openlog(
532 Some("test1"),
533 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID | LogStat::LOG_PERROR,
534 LogFacility::LOG_DAEMON,
535 SyslogLocal::new()
536 );
537
538 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
539
540 let log = log.unwrap();
541
542 log.syslog(Priority::LOG_DEBUG, format!("test UTF-8 きるさお命泉ぶねりよ日子金れっ проверка BOM"));
543
544 let _ = log.closelog();
545
546 return;
547 }
548
549 #[test]
550 fn test_multithreading()
551 {
552 use std::sync::Arc;
553 use std::thread;
554 use std::time::{Instant, Duration};
555
556 let log =
557 Syslog::openlog(
558 Some("test1"),
559 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
560 LogFacility::LOG_DAEMON,
561 SyslogLocal::new()
562 );
563
564 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
565
566 let log = Arc::new(log.unwrap());
567 let c1_log = log.clone();
568 let c2_log = log.clone();
569
570 thread::spawn(move|| {
571 for i in 0..5
572 {
573 thread::sleep(Duration::from_nanos(200));
574 let now = Instant::now();
575 c1_log.syslog(Priority::LOG_DEBUG, format!("a message from thread 1 #{}[]", i));
576 let elapsed = now.elapsed();
577 println!("t1: {:?}", elapsed);
578 }
579 });
580
581 thread::spawn(move|| {
582 for i in 0..5
583 {
584 thread::sleep(Duration::from_nanos(201));
585 let now = Instant::now();
586 c2_log.syslog(Priority::LOG_DEBUG, format!("きるさお命泉ぶねりよ日子金れっ {}", i));
587 let elapsed = now.elapsed();
588 println!("t2: {:?}", elapsed);
589 }
590 });
591
592 let now = Instant::now();
593 log.syslog(Priority::LOG_DEBUG, format!("A message from main, きるさお命泉ぶねりよ日子金れっ"));
594 let elapsed = now.elapsed();
595 println!("main: {:?}", elapsed);
596
597 thread::sleep(Duration::from_secs(2));
598
599 let _ = log.closelog();
600
601 return;
602 }
603
604 #[test]
605 fn long_msg_test()
606 {
607 let msg =
609 "7赤ざクぽな載覧な改申ほふ取容う主坊酸ヱ司戦ヒソオ力端めゃ間真ル実記キ団需くスルて学回県仁京ぴ熱完かあもく。上ょぜ催5強変却ソヲキ転入ク記事購シリ断衝ぽ玲面たぽつへ様態の善無かー勢加ヨマナキ趣会撮さはこ違42器のレうゆ。稿エスタ己報照アイネル岩撲ムニ半者サアキツ画47込死請誌8策ノ再然ださそ禁断しにた高否リ続最ユケ山芸ロ去群づへ索芭あン掲佳怖斎澤クね。
610 書キマコヒ上広ざばてわ会佐のにりリ学総点フわすか頼野ぜイよば株約ネキヱメ必軽チヲ録使ラ下能ナウコ紀捜れ霊別イ摯療じらどト相3聞めびら情拳ユフエ確経板植えーぜあ。無ど曲注程クタル系新どばくい都面村リと計安ワヱ月見モヌエノ完臨健85定テサコミ貸容ミテタカ写載とかえげ詐訃だみそな。代け設養テヨナ乱54服料ニ止画ら不暮ッ強治ぱンやし供方広づじもあ般判ごくドラ示刊ヱサトキ速事取さふぞ授共西れッ。
611 陸オク康59面くこ惑7伊エノモ候余ロソウ政投ナク転文だけス香両4誕よ数真ひぞぴざ空加ユラ勢隣ゃびよ移72士シヌ図際想カマテ覧費活輸権因ん。東がイ価変や濃恒ヒメネエ学見ょ理供カオムヱ針中わば文63転ヨリホミ礼民ネトマツ速果還ばが転世晴げでんが。犯レト同岸サケ写新ゆぐぱひ人捕けほゅえ的人第いぜ転連ぎど京分株ニムトヒ家及ユフケヌ記定み歩死質をゃいイ都末ワ革量んつ覧打百レいん。
612 下ゃとぞら川株以東ぴそぱ費更ウマヨメ覧論ウスレモ八度ずんとイ発平う果構つ小各ぼス夢国フラ連石はちい雪飲聴ゅいと。門ぱし続消上ト文影投設テユチ設川ルラシケ引押ヤマセメ権書ハテ例発リロソイ環載ぴ企実カマリト店鉄ワソロフ逆子先チルマ楽法どゆね声東女携抜爆んけみ。14報ふラめて怒止に開謙こさ促大ヘチツ遺飯ケ営長コキ価空少ろッひぱ読信ケテウ者育ヒミク代57柱浪フ。
613 ";
614
615 println!("{}", msg.len());
616
617 let log =
618 Syslog::openlog(
619 Some("test1"),
620 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
621 LogFacility::LOG_DAEMON,
622 SyslogLocal::new()
623 );
624
625 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
626
627 let log = log.unwrap();
628
629 log.syslog(Priority::LOG_DEBUG, format!("{}", msg));
630
631 let _ = log.closelog();
632
633 return;
634 }
635}
636
637#[cfg(feature = "use_sync_queue")]
638#[cfg(test)]
639mod tests_queue
640{
641 use crate::{formatters::DefaultSyslogFormatter, sy_sync::Syslog, LogFacility, LogStat, Priority, SyslogLocal, SyslogQueue};
642
643
644 #[test]
645 fn test_multithreading()
646 {
647 use std::sync::Arc;
648 use std::thread;
649 use std::time::{Instant, Duration};
650 use crate::LOG_MASK;
651
652 let log =
653 Syslog
654 ::<SyslogLocal, DefaultSyslogFormatter, SyslogQueue<_>>
655 ::openlog_with(
656 Some("test1"),
657 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
658 LogFacility::LOG_DAEMON, SyslogLocal::new()
659 );
660
661 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
662
663 let log = Arc::new(log.unwrap());
664 let c1_log = log.clone();
665 let c2_log = log.clone();
666
667 thread::spawn(move|| {
668 for i in 0..5
669 {
670 thread::sleep(Duration::from_nanos(200));
671 let now = Instant::now();
672 c1_log.syslog(Priority::LOG_DEBUG, format!("a message from thread 1 #{}[]", i));
673 let elapsed = now.elapsed();
674 println!("t1: {:?}", elapsed);
675 }
676 });
677
678 thread::spawn(move|| {
679 for i in 0..5
680 {
681 thread::sleep(Duration::from_nanos(201));
682 let now = Instant::now();
683 c2_log.syslog(Priority::LOG_DEBUG, format!("きるさお命泉ぶねりよ日子金れっ {}", i));
684 let elapsed = now.elapsed();
685 println!("t2: {:?}", elapsed);
686 }
687 });
688
689 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
690
691 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
692 assert_eq!(res.unwrap(), 0xff, "should be 0xff");
693
694 let now = Instant::now();
695 log.syslog(Priority::LOG_DEBUG, format!("A message from main, сообщение от главнюка"));
696 let elapsed = now.elapsed();
697 println!("main: {:?}", elapsed);
698
699 thread::sleep(Duration::from_secs(2));
700
701 let _ = log.closelog();
702
703 thread::sleep(Duration::from_millis(500));
704
705 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
706
707 assert_eq!(res.is_ok(), true);
708
709 return;
710 }
711
712 #[cfg(feature = "build_with_file")]
713 #[test]
714 fn test_file_multithreading()
715 {
716 use std::sync::Arc;
717 use std::thread;
718 use std::time::{Instant, Duration};
719 use crate::formatters::DefaultSyslogFormatterFile;
720 use crate::{SyslogFile, SyslogQueue, LOG_MASK};
721
722 let log =
723 Syslog
724 ::<SyslogFile, DefaultSyslogFormatterFile, SyslogQueue<_>>
725 ::openlog_with(
726 Some("test2"),
727 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
728 LogFacility::LOG_DAEMON,
729 SyslogFile::new("/tmp/syslog_rs_test2.log")
730 );
731
732
733 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
734
735 let log = Arc::new(log.unwrap());
736 let c1_log = log.clone();
737 let c2_log = log.clone();
738
739 thread::spawn(move|| {
740 for i in 0..5
741 {
742 thread::sleep(Duration::from_nanos(200));
743 let now = Instant::now();
744 c1_log.syslog(Priority::LOG_ALERT, format!("a message from thread 1 #{}[]", i));
745 let elapsed = now.elapsed();
746 println!("t1: {:?}", elapsed);
747 }
748 });
749
750 thread::spawn(move|| {
751 for i in 0..5
752 {
753 thread::sleep(Duration::from_nanos(201));
754 let now = Instant::now();
755 c2_log.syslog(Priority::LOG_DEBUG, format!("きるさお命泉ぶねりよ日子金れっ {}", i));
756 let elapsed = now.elapsed();
757 println!("t2: {:?}", elapsed);
758 }
759 });
760
761 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
762
763 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
764 assert_eq!(res.unwrap(), 0xff, "should be 0xff");
765
766 let now = Instant::now();
767 log.syslog(Priority::LOG_DEBUG, format!("A message from main, きるさお命泉ぶねりよ日子金れっ"));
768 let elapsed = now.elapsed();
769 println!("main: {:?}", elapsed);
770
771 thread::sleep(Duration::from_secs(2));
772
773 let _ = log.closelog();
774
775 thread::sleep(Duration::from_millis(500));
776
777 let res = log.setlogmask(!LOG_MASK!(Priority::LOG_ERR));
778
779 assert_eq!(res.is_ok(), true);
780
781 return;
782 }
783
784}
785
786