1use std::marker::PhantomData;
17use std::sync::Arc;
18use std::{str};
19
20use instance_copy_on_write::ICoW;
21
22use crate::formatters::DefaultSyslogFormatter;
23use crate::sync::syslog_stream::SyStreamApi;
24use crate::sync::syslog_sync_internal::{SyslogSocket};
25use crate::sync::{LogItems, SyStream};
26use crate::{formatters::SyslogFormatter, map_error_code};
27use crate::{common::*, SyslogDestination, SyslogLocal};
28use crate::error::SyRes;
29
30use super::syslog_trait::SyslogApi;
31
32
33#[derive(Debug, Clone)]
93pub struct SyncSyslog<F = DefaultSyslogFormatter, D = SyslogLocal>
94where
95 F: SyslogFormatter,
96 D: SyslogDestination,
97{
98 log_items: Arc<ICoW<LogItems>>,
100
101 stream: Arc<SyslogSocket<D>>,
103
104 _p: PhantomData<F>,
105}
106
107unsafe impl<F: SyslogFormatter, D: SyslogDestination> Send for SyncSyslog<F, D>
108{}
109
110impl SyncSyslog
111{
112 pub
135 fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: SyslogLocal) -> SyRes<Self>
136 {
137 return Ok(
138 Self
139 {
140 log_items:
141 Arc::new(
142 ICoW::new(
143 LogItems::new(ident, 0xff, logstat, facility)
144 )
145 ),
146 stream:
147 Arc::new(
148 SyslogSocket::<SyslogLocal>::new(logstat, net_tap_prov)?
149 ),
150 _p:
151 PhantomData,
152 }
153 );
154 }
155}
156
157
158impl<F: SyslogFormatter, D: SyslogDestination> SyncSyslog<F, D>
159{
160 pub
186 fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self>
187 {
188 return Ok(
189 Self
190 {
191 log_items:
192 Arc::new(
193 ICoW::new(
194 LogItems::new(ident, 0xff, logstat, facility)
195 )
196 ),
197 stream:
198 Arc::new(
199 SyslogSocket::<D>::new(logstat, net_tap_prov)?
200 ),
201 _p:
202 PhantomData,
203 }
204 );
205 }
206}
207
208
209impl<F: SyslogFormatter, D: SyslogDestination> SyslogApi<F, D> for SyncSyslog<F, D>
210{
211 fn connectlog(&self) -> SyRes<()>
212 {
213 return
214 self
215 .stream
216 .connectlog();
217 }
218
219 fn setlogmask(&self, logmask: i32) -> SyRes<i32>
220 {
221 let mut transaction =
222 self
223 .log_items
224 .as_ref()
225 .clone();
226 let pri =
231 transaction
232 .set_logmask(logmask);
233
234 transaction
235 .commit()
236 .map_err(|e|
237 map_error_code!(CoWWriteError, "set logmask failed with: {}", e.0)
238 )?;
239
240 return Ok(pri);
241 }
242
243 fn closelog(&self) -> SyRes<()>
244 {
245 return
246 self
247 .stream
248 .disconnectlog();
249 }
250
251 #[inline]
252 fn syslog(&self, pri: Priority, fmt: F)
253 {
254 let Some((formatted_msg, logstat)) =
255 self.log_items.read().vsyslog1_msg::<F, D>(pri, &fmt)
256 else { return };
257
258 self.stream.vsyslog1(logstat, formatted_msg);
259
260 return;
261 }
262
263 fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
270 {
271 let mut clonned =
272 self
273 .log_items
274 .as_ref()
275 .clone();
276 clonned.set_identity(ident);
281
282 clonned
283 .commit()
284 .map_err(|e|
285 map_error_code!(CoWWriteError, "cannot change_identity due to exclusive lock, err: '{}'", e.0)
286 )?;
287
288 return Ok(());
289 }
290
291 fn reconnect(&self) -> SyRes<()>
292 {
293 return
294 self
295 .stream
296 .reconnectlog();
297 }
298
299 fn update_tap_data(&self, tap_data: D) -> SyRes<()>
300 {
301 return
302 self
303 .stream
304 .update_tap_data(tap_data);
305 }
306
307}
308
309impl<'stream, F: SyslogFormatter, D: SyslogDestination> SyStreamApi<'stream, F, D, SyncSyslog<F, D>>
310for SyncSyslog<F, D>
311{
312 fn stream(&'stream self, pri: Priority) -> SyStream<'stream, D, F, SyncSyslog<F, D>>
313 {
314 return
315 SyStream
316 {
317 inner: self,
318 pri: pri,
319 _p: PhantomData,
320 _p1: PhantomData
321 };
322 }
323}
324
325#[cfg(test)]
326mod tests
327{
328 use crate::
329 {
330 error::SyslogErrCode, LogFacility, LogStat, Priority, SyStreamApi, SyncSyslog, SyslogApi, SyslogLocal
331 };
332
333 #[test]
334 fn test_single_message()
335 {
336
337 let log =
338 SyncSyslog::openlog(
339 Some("test1"),
340 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
341 LogFacility::LOG_DAEMON,
342 SyslogLocal::new()
343 );
344
345 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
346
347 let log = log.unwrap();
348
349 let msg1 = format!("test UTF-8 проверка BOM UTF-8");
350 let now = std::time::Instant::now();
351
352 log.syslog(Priority::LOG_DEBUG, msg1.into());
353
354 let dur = now.elapsed();
355 println!("{:?}", dur);
356
357 let msg2 = format!("test UTF-8 きるさお命泉ぶねりよ日子金れっ");
358
359 let now = std::time::Instant::now();
360
361 log.syslog(Priority::LOG_DEBUG, msg2.into());
362
363 let dur = now.elapsed();
364 println!("{:?}", dur);
365
366 let _ = log.closelog();
367
368 return;
369 }
370
371 #[test]
372 fn test_single_stream_test()
373 {
374 use std::fmt::Write;
375
376 let log =
377 SyncSyslog::openlog(
378 Some("test1"),
379 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
380 LogFacility::LOG_DAEMON,
381 SyslogLocal::new());
382
383 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
384
385 let log = log.unwrap();
386
387 write!(log.stream(Priority::LOG_DEBUG), "test123").unwrap();
388
389 }
390
391 #[test]
392 fn test_single_message_withound_nd()
393 {
394
395 let log =
396 SyncSyslog::openlog(
397 Some("test1_nond"),
398 LogStat::LOG_CONS | LogStat::LOG_PID,
399 LogFacility::LOG_DAEMON,
400 SyslogLocal::new());
401
402 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
403
404 let log = log.unwrap();
405
406 let msg1 = format!("test UTF-8 проверка BOM UTF-8");
407 let now = std::time::Instant::now();
408
409 log.syslog(Priority::LOG_DEBUG, msg1.into());
410
411 let dur = now.elapsed();
412 println!("{:?}", dur);
413
414 let msg2 = format!("test UTF-8 きるさお命泉ぶねりよ日子金れっ");
415
416 let now = std::time::Instant::now();
417
418 log.syslog(Priority::LOG_DEBUG, msg2.into());
419
420 let dur = now.elapsed();
421 println!("{:?}", dur);
422
423 let _ = log.closelog();
424
425 return;
426 }
427
428 #[test]
429 fn test_single_message_perror()
430 {
431 let log =
437 SyncSyslog::openlog(
438 Some("test2"),
439 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID | LogStat::LOG_PERROR,
440 LogFacility::LOG_DAEMON,
441 SyslogLocal::new()
442 );
443
444 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
445
446 let log = log.unwrap();
447
448 log.syslog(Priority::LOG_DEBUG, format!("perror test UTF-8 きるさお命泉ぶねりよ日子金れっ проверка BOM").into());
449
450 let _ = log.closelog();
451
452 return;
453 }
454
455 #[test]
456 fn test_multithreading()
457 {
458 use std::sync::Arc;
459 use std::thread;
460 use std::time::{Instant, Duration};
461
462 let log =
463 SyncSyslog::openlog(
464 Some("test3"),
465 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
466 LogFacility::LOG_DAEMON,
467 SyslogLocal::new()
468 );
469
470 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
471
472 let log = Arc::new(log.unwrap());
473 let c1_log = log.clone();
474 let c2_log = log.clone();
475
476 thread::spawn(move|| {
477 for i in 0..5
478 {
479 let fmmt = format!("a message from thread 1 #{}[]", i);
481 let now = Instant::now();
482 c1_log.syslog(Priority::LOG_DEBUG, fmmt.into());
483 let elapsed = now.elapsed();
484 println!("t1: {:?}", elapsed);
485 }
486 });
487
488 thread::spawn(move|| {
489 for i in 0..5
490 {
491 let fmmt = format!("きるさお命泉ぶねりよ日子金れっ {}", i);
493 let now = Instant::now();
494 c2_log.syslog(Priority::LOG_DEBUG, fmmt.into());
495 let elapsed = now.elapsed();
496 println!("t2: {:?}", elapsed);
497 }
498 });
499
500 let now = Instant::now();
501 log.syslog(Priority::LOG_DEBUG, format!("A message from main, きるさお命泉ぶねりよ日子金れっ").into());
502 let elapsed = now.elapsed();
503 println!("main: {:?}", elapsed);
504
505 thread::sleep(Duration::from_secs(2));
506
507 let _ = log.closelog();
508
509 return;
510 }
511
512 #[test]
513 fn test_multithreading_rw()
514 {
515 use std::sync::Arc;
516 use std::thread;
517 use std::time::{Instant, Duration};
518
519 let log =
520 SyncSyslog::openlog(
521 Some("test3"),
522 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
523 LogFacility::LOG_DAEMON,
524 SyslogLocal::new()
525 );
526
527 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
528
529 let log = Arc::new(log.unwrap());
530 let c1_log = log.clone();
531
532 let thread_handler =
533 thread::spawn(move||
534 {
535 std::thread::park();
536 for i in 0..30
537 {
538
539
540 let fmmt = format!("a message from thread 1 #{}[]", i);
541 let now = Instant::now();
542 c1_log.syslog(Priority::LOG_DEBUG, fmmt.into());
543 let elapsed = now.elapsed();
544 println!("t1: {:?}", elapsed);
545 }
546 }
547 );
548
549 let now = Instant::now();
550 log.syslog(Priority::LOG_DEBUG, format!("A message from main, きるさお命泉ぶねりよ日子金れっ").into());
551 let elapsed = now.elapsed();
552 println!("main: {:?}", elapsed);
553
554 thread_handler.thread().unpark();
555
556 for i in 0..3
557 {
558 std::thread::sleep(Duration::from_nanos(999));
559 let identity = format!("identity{}", i);
560 let now = Instant::now();
561 log.change_identity(Some(&identity)).unwrap();
562 let elapsed = now.elapsed();
563 println!("idc: {:?}", elapsed);
564 }
565
566 thread_handler.join().unwrap();
567
568 let _ = log.closelog();
569
570 return;
571 }
572
573 #[test]
574 fn test_multithreading_rw_sock()
575 {
576 use std::sync::Arc;
577 use std::thread;
578 use std::time::{Instant, Duration};
579
580 let log =
581 SyncSyslog::openlog(
582 Some("test3"),
583 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
584 LogFacility::LOG_DAEMON,
585 SyslogLocal::new()
586 );
587
588 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
589
590 let log = Arc::new(log.unwrap());
591 let c1_log = log.clone();
592
593 let thread_handler =
594 thread::spawn(move||
595 {
596 std::thread::park();
597 for i in 0..30
598 {
599
600
601 let fmmt = format!("a message from thread 1 #{}[]", i);
602 let now = Instant::now();
603 c1_log.syslog(Priority::LOG_DEBUG, fmmt.into());
604 let elapsed = now.elapsed();
605 println!("t1: {:?}", elapsed);
606 }
607 }
608 );
609
610 let now = Instant::now();
611 log.syslog(Priority::LOG_DEBUG, format!("A message from main, きるさお命泉ぶねりよ日子金れっ").into());
612 let elapsed = now.elapsed();
613 println!("main: {:?}", elapsed);
614
615 thread_handler.thread().unpark();
616
617 for _ in 0..3
618 {
619 std::thread::sleep(Duration::from_nanos(999));
620 let now = Instant::now();
621 log.update_tap_data(SyslogLocal::new()).unwrap();
622 let elapsed = now.elapsed();
623 println!("idc: {:?}", elapsed);
624 }
625
626 thread_handler.join().unwrap();
627
628 let _ = log.closelog();
629
630 return;
631 }
632
633 #[test]
634 fn test_multithreading_simlock()
635 {
636 use std::sync::Arc;
637 use std::thread;
638 use std::time::Instant;
639
640 let log =
641 SyncSyslog::openlog(
642 Some("test3"),
643 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
644 LogFacility::LOG_DAEMON,
645 SyslogLocal::new()
646 );
647
648 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
649
650 let log = Arc::new(log.unwrap());
651 for _ in 0..5
652 {
653 let c1_log = log.clone();
654
655 let thread_handler =
656 thread::spawn(move ||
657 {
658 std::thread::park();
659 let res = c1_log.update_tap_data(SyslogLocal::new());
660
661 return res;
662 }
663 );
664
665 let now = Instant::now();
666 log.syslog(Priority::LOG_DEBUG, format!("A message from main, きるさお命泉ぶねりよ日子金れっ").into());
667 let elapsed = now.elapsed();
668 println!("main: {:?}", elapsed);
669
670 thread_handler.thread().unpark();
671
672 let res = log.update_tap_data(SyslogLocal::new());
673
674 let res2 = thread_handler.join().unwrap();
675
676 if res.is_ok() == true && res2.is_ok() == true
677 {
678 continue;
679 }
680 else if res.is_err() == true
681 {
682 println!("res err: {}", res.as_ref().err().unwrap());
683 assert_eq!(res.err().unwrap().get_errcode(), SyslogErrCode::CoWAlreadyLocked);
684 }
685 else if res2.is_err() == true
686 {
687 println!("res2 err: {}", res2.as_ref().err().unwrap());
688 assert_eq!(res2.err().unwrap().get_errcode(), SyslogErrCode::CoWAlreadyLocked);
689 }
690
691 return;
692 }
693
694 panic!("faild!");
695 }
696
697 #[test]
698 fn long_msg_test()
699 {
700 let msg =
702 "7赤ざクぽな載覧な改申ほふ取容う主坊酸ヱ司戦ヒソオ力端めゃ間真ル実記キ団需くスルて学回県仁京ぴ熱完かあもく。上ょぜ催5強変却ソヲキ転入ク記事購シリ断衝ぽ玲面たぽつへ様態の善無かー勢加ヨマナキ趣会撮さはこ違42器のレうゆ。稿エスタ己報照アイネル岩撲ムニ半者サアキツ画47込死請誌8策ノ再然ださそ禁断しにた高否リ続最ユケ山芸ロ去群づへ索芭あン掲佳怖斎澤クね。
703 書キマコヒ上広ざばてわ会佐のにりリ学総点フわすか頼野ぜイよば株約ネキヱメ必軽チヲ録使ラ下能ナウコ紀捜れ霊別イ摯療じらどト相3聞めびら情拳ユフエ確経板植えーぜあ。無ど曲注程クタル系新どばくい都面村リと計安ワヱ月見モヌエノ完臨健85定テサコミ貸容ミテタカ写載とかえげ詐訃だみそな。代け設養テヨナ乱54服料ニ止画ら不暮ッ強治ぱンやし供方広づじもあ般判ごくドラ示刊ヱサトキ速事取さふぞ授共西れッ。
704 陸オク康59面くこ惑7伊エノモ候余ロソウ政投ナク転文だけス香両4誕よ数真ひぞぴざ空加ユラ勢隣ゃびよ移72士シヌ図際想カマテ覧費活輸権因ん。東がイ価変や濃恒ヒメネエ学見ょ理供カオムヱ針中わば文63転ヨリホミ礼民ネトマツ速果還ばが転世晴げでんが。犯レト同岸サケ写新ゆぐぱひ人捕けほゅえ的人第いぜ転連ぎど京分株ニムトヒ家及ユフケヌ記定み歩死質をゃいイ都末ワ革量んつ覧打百レいん。
705 下ゃとぞら川株以東ぴそぱ費更ウマヨメ覧論ウスレモ八度ずんとイ発平う果構つ小各ぼス夢国フラ連石はちい雪飲聴ゅいと。門ぱし続消上ト文影投設テユチ設川ルラシケ引押ヤマセメ権書ハテ例発リロソイ環載ぴ企実カマリト店鉄ワソロフ逆子先チルマ楽法どゆね声東女携抜爆んけみ。14報ふラめて怒止に開謙こさ促大ヘチツ遺飯ケ営長コキ価空少ろッひぱ読信ケテウ者育ヒミク代57柱浪フ。
706 ";
707
708 println!("{}", msg.len());
709
710 let log =
711 SyncSyslog::openlog(
712 Some("test4"),
713 LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
714 LogFacility::LOG_DAEMON,
715 SyslogLocal::new()
716 );
717
718 assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
719
720 let log = log.unwrap();
721
722 log.syslog(Priority::LOG_DEBUG, format!("{}", msg).into());
723
724 let _ = log.closelog();
725
726 return;
727 }
728}