use std::sync::atomic::{AtomicBool, Ordering};
use crossbeam::utils::Backoff;
use super::common::*;
use super::syslog_sync_internal::SyncSyslogInternal;
use super::error::{SyRes};
pub struct Syslog
{
lock: AtomicBool,
inner: SyncSyslogInternal,
}
unsafe impl Send for Syslog {}
unsafe impl Sync for Syslog {}
impl Drop for Syslog
{
fn drop(&mut self)
{
self.inner.disconnectlog();
}
}
impl Syslog
{
pub fn openlog(
ident: Option<&str>,
logstat: LogStat,
facility: LogFacility) -> SyRes<Self>
{
let ret =
Self
{
lock: AtomicBool::new(false),
inner: SyncSyslogInternal::new(ident, logstat, facility),
};
if logstat.contains(LogStat::LOG_NDELAY) == true
{
ret.inner.connectlog()?;
}
return Ok(ret);
}
pub fn setlogmask(&self, logmask: i32) -> i32
{
let backoff = Backoff::new();
while self.lock.swap(true, Ordering::Acquire) == true
{
backoff.snooze();
}
let pri = self.inner.set_logmask(logmask);
self.lock.store(false, Ordering::Release);
return pri;
}
pub fn closelog(&self)
{
let backoff = Backoff::new();
while self.lock.swap(true, Ordering::Acquire) == true
{
backoff.snooze();
}
self.inner.disconnectlog();
self.lock.store(false, Ordering::Release);
}
pub fn syslog(&self, pri: Priority, fmt: String)
{
self.vsyslog(pri, fmt);
}
pub fn vsyslog<S: AsRef<str>>(&self, pri: Priority, fmt: S)
{
let backoff = Backoff::new();
while self.lock.swap(true, Ordering::Acquire) == true
{
backoff.snooze();
}
self.inner.vsyslog1(pri.bits(), fmt);
self.lock.store(false, Ordering::Release);
}
pub fn change_identity<I: AsRef<str>>(&self, ident: I)
{
let backoff = Backoff::new();
while self.lock.swap(true, Ordering::Acquire) == true
{
backoff.snooze();
}
self.inner.set_logtag(ident);
self.lock.store(false, Ordering::Release);
}
}
#[test]
fn test_single_message()
{
let log =
Syslog::openlog(
Some("test1"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON);
assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
let log = log.unwrap();
log.syslog(Priority::LOG_DEBUG, format!("test_set_logmask() проверка BOM"));
log.closelog();
return;
}
#[test]
fn test_multithreading()
{
use std::sync::Arc;
use std::thread;
use std::time::{Instant, Duration};
let log =
Syslog::openlog(
Some("test1"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON);
assert_eq!(log.is_ok(), true, "{}", log.err().unwrap());
let log = Arc::new(log.unwrap());
let c1_log = log.clone();
let c2_log = log.clone();
thread::spawn(move|| {
for i in 0..5
{
thread::sleep(Duration::from_nanos(200));
let now = Instant::now();
c1_log.syslog(Priority::LOG_DEBUG, format!("a message from thread 1 #{}[]", i));
let elapsed = now.elapsed();
println!("t1: {:?}", elapsed);
}
});
thread::spawn(move|| {
for i in 0..5
{
thread::sleep(Duration::from_nanos(201));
let now = Instant::now();
c2_log.syslog(Priority::LOG_DEBUG, format!("сообщение от треда 2 №{}ХЪ", i));
let elapsed = now.elapsed();
println!("t2: {:?}", elapsed);
}
});
let now = Instant::now();
log.syslog(Priority::LOG_DEBUG, format!("A message from main, сообщение от главнюка"));
let elapsed = now.elapsed();
println!("main: {:?}", elapsed);
thread::sleep(Duration::from_secs(2));
log.closelog();
return;
}