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