use std::{fmt, marker::PhantomData, sync::{Arc, Mutex}};
use crate::{DefaultLocalSyslogDestination, LogFacility, LogStat, Priority, SyslogDestination, error::SyRes, formatters::{DefaultSyslogFormatter, SyslogFormatter}, sync::{LogItems, SyStream, SyStreamPri, SyStreamSyslogApi, syslog_sync_internal::SyslogSocketLockless}};
pub trait DynSyslog: Send + Sync
{
fn connectlog(&self) -> SyRes<()>;
fn setlogmask(&self, logmask: i32) -> SyRes<i32>;
fn closelog(&self) -> SyRes<()>;
fn syslog(&self, pri: Priority, fmt: String) -> SyRes<()>;
fn change_identity(&self, ident: Option<&str>) -> SyRes<()>;
fn reconnect(&self) -> SyRes<()>;
}
pub trait SyslogType: fmt::Debug
{
type LockItemsBase;
type LockItems;
type LockStreamBase<D: SyslogDestination>;
type LockStream<D: SyslogDestination>;
type MoveLockType;
fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems;
fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D>;
}
#[derive(Debug)]
pub struct Syslog<F = DefaultSyslogFormatter, D = DefaultLocalSyslogDestination, SL = SyShared>
where
F: SyslogFormatter,
D: SyslogDestination,
SL: SyslogType
{
log_items: SL::LockItems,
stream: SL::LockStream<D>,
_p: PhantomData<F>,
_p_not_ss: SL::MoveLockType
}
impl Syslog
{
pub
fn openlog(ident: Option<&str>, logstat: LogStat, facility: LogFacility,
net_tap_prov: DefaultLocalSyslogDestination) -> SyRes<Self>
{
return Ok(
Self
{
log_items:
<SyShared as SyslogType>
::wrap_items(
<SyShared as SyslogType>::LockItemsBase::new(ident, 0xff, logstat, facility)
),
stream:
<SyShared as SyslogType>
::wrap_stream(
<SyShared as SyslogType>::LockStreamBase::<DefaultLocalSyslogDestination>::new(logstat, net_tap_prov)?,
),
_p:
PhantomData,
_p_not_ss:
PhantomData
}
);
}
}
#[cfg(feature = "build_with_thread_local")]
pub mod build_with_thread_local
{
use super::*;
#[derive(Debug)]
pub struct SyThreadLocal;
impl SyslogType for SyThreadLocal
{
type LockItemsBase = LogItems;
type LockItems = Self::LockItemsBase;
type LockStreamBase<D: SyslogDestination> = SyslogSocketLockless<D>;
type LockStream<D: SyslogDestination> = Self::LockStreamBase<D>;
type MoveLockType = PhantomData<*const ()>;
fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems
{
items
}
fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D>
{
stream
}
}
impl<F, D> Syslog<F, D, SyThreadLocal>
where
F: SyslogFormatter,
D: SyslogDestination,
{
pub
fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self>
{
return Ok(
Self
{
log_items:
<SyThreadLocal as SyslogType>
::wrap_items(
<SyThreadLocal as SyslogType>::LockItems::new(ident, 0xff, logstat, facility)
),
stream:
<SyThreadLocal as SyslogType>
::wrap_stream(
<SyThreadLocal as SyslogType>::LockStream::new(logstat, net_tap_prov)?
),
_p:
PhantomData,
_p_not_ss:
PhantomData
}
);
}
}
impl<F, D> Syslog<F, D, SyThreadLocal>
where
F: SyslogFormatter,
D: SyslogDestination,
{
#[inline]
pub
fn connectlog(&mut self) -> SyRes<()>
{
return
self
.stream
.connectlog();
}
#[inline]
pub
fn setlogmask(&mut self, logmask: i32) -> SyRes<i32>
{
return Ok(
self
.log_items
.set_logmask(logmask)
);
}
#[inline]
pub
fn closelog(&mut self) -> SyRes<()>
{
return
self
.stream
.disconnectlog();
}
#[inline]
pub
fn syslog(&mut self, pri: Priority, fmt: F) -> SyRes<()>
{
let Some((formatted_msg, logstat)) =
self.log_items.vsyslog1_msg::<F, D>(pri, &fmt)
else { return Ok(()) };
self.stream.vsyslog1(logstat, formatted_msg)
}
#[inline]
pub
fn change_identity(&mut self, ident: Option<&str>) -> SyRes<()>
{
self.log_items.set_identity(ident);
return Ok(());
}
#[inline]
pub
fn reconnect(&mut self) -> SyRes<()>
{
return
self
.stream
.reconnectlog();
}
#[inline]
pub
fn update_tap_data(&mut self, tap_data: D) -> SyRes<()>
{
return
self
.stream
.update_tap_data(tap_data.clone());
}
}
impl<F, D> Syslog<F, D, SyThreadLocal>
where
F: SyslogFormatter,
D: SyslogDestination,
{
pub
fn get_stream<'t, PRI>(&'t mut self) -> SyStream<'t, PRI, D, F, &'t mut Self>
where PRI: SyStreamPri
{
SyStream
{
s: Some(self),
_p: PhantomData,
_p1: PhantomData,
_p2: PhantomData
}
}
}
impl<F, D> SyStreamSyslogApi<F, D>
for &mut Syslog<F, D, SyThreadLocal>
where
F: SyslogFormatter,
D: SyslogDestination,
{
type SYSLOG<'t> = &'t mut Syslog<F, D, SyThreadLocal>;
fn syslog<'t>(syslog: Self::SYSLOG<'t>, pri: Priority, fmt: F) -> SyRes<()>
{
syslog.syslog(pri, fmt)
}
}
}
#[cfg(feature = "build_with_thread_local")]
pub use self::build_with_thread_local::SyThreadLocal;
#[derive(Debug)]
pub struct SyShared;
impl SyslogType for SyShared
{
type LockItemsBase = LogItems;
type LockItems = Arc<Mutex<Self::LockItemsBase>>;
type LockStreamBase<D: SyslogDestination> = SyslogSocketLockless<D>;
type LockStream<D: SyslogDestination> = Arc<Mutex<Self::LockStreamBase<D>>>;
type MoveLockType = PhantomData<()>;
fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems
{
Arc::new(Mutex::new(items))
}
fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D>
{
Arc::new(Mutex::new(stream))
}
}
impl<F, D> Clone for Syslog<F, D, SyShared>
where
F: SyslogFormatter,
D: SyslogDestination,
{
fn clone(&self) -> Self
{
Self
{
log_items:
self.log_items.clone(),
stream:
self.stream.clone(),
_p:
PhantomData,
_p_not_ss:
PhantomData,
}
}
}
impl<F, D> DynSyslog for Syslog<F, D, SyShared>
where
F: SyslogFormatter,
D: SyslogDestination,
{
#[inline]
fn connectlog(&self) -> SyRes<()>
{
self.connectlog()
}
#[inline]
fn setlogmask(&self, logmask: i32) -> SyRes<i32>
{
self.setlogmask(logmask)
}
#[inline]
fn closelog(&self) -> SyRes<()>
{
self.closelog()
}
fn syslog(&self, pri: Priority, fmt: String) -> SyRes<()>
{
self.syslog(pri, fmt.into())
}
fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
{
self.change_identity(ident)
}
fn reconnect(&self) -> SyRes<()>
{
self.reconnect()
}
}
impl<F, D> Syslog<F, D, SyShared>
where
F: SyslogFormatter,
D: SyslogDestination,
{
pub
fn make_dyn(self) -> Box<dyn DynSyslog>
{
Box::new(self)
}
pub
fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self>
{
return Ok(
Self
{
log_items:
<SyShared as SyslogType>
::wrap_items(
<SyShared as SyslogType>::LockItemsBase::new(ident, 0xff, logstat, facility)
),
stream:
<SyShared as SyslogType>
::wrap_stream(
<SyShared as SyslogType>::LockStreamBase::<D>::new(logstat, net_tap_prov)?,
),
_p:
PhantomData,
_p_not_ss:
PhantomData
}
);
}
pub
fn attach(other: &Syslog<F, D, SyShared>) -> SyRes<Self>
{
Ok(other.clone())
}
}
impl<F, D> Syslog<F, D, SyShared>
where
F: SyslogFormatter,
D: SyslogDestination,
{
pub
fn connectlog(&self) -> SyRes<()>
{
return
self
.stream
.lock()
.unwrap()
.connectlog();
}
pub
fn setlogmask(&self, logmask: i32) -> SyRes<i32>
{
let pri =
self
.log_items
.lock()
.unwrap()
.set_logmask(logmask);
return Ok(pri);
}
pub
fn closelog(&self) -> SyRes<()>
{
return
self
.stream
.lock()
.unwrap()
.disconnectlog();
}
#[inline]
pub
fn syslog(&self, pri: Priority, fmt: F) -> SyRes<()>
{
let Some((formatted_msg, logstat)) =
self.log_items.lock().unwrap().vsyslog1_msg::<F, D>(pri, &fmt)
else { return Ok(()) };
self.stream.lock().unwrap().vsyslog1(logstat, formatted_msg)
}
pub
fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
{
self
.log_items
.lock()
.unwrap()
.set_identity(ident);
return Ok(());
}
pub
fn reconnect(&self) -> SyRes<()>
{
return
self
.stream
.lock()
.unwrap()
.reconnectlog();
}
pub
fn update_tap_data(&self, tap_data: D) -> SyRes<()>
{
return
self
.stream
.lock()
.unwrap()
.update_tap_data(tap_data);
}
}
impl<F, D> Syslog<F, D, SyShared>
where
F: SyslogFormatter,
D: SyslogDestination,
{
pub
fn get_stream<'t, PRI>(&'t self) -> SyStream<'t, PRI, D, F, &'t Self>
where PRI: SyStreamPri
{
SyStream
{
s: Some(self),
_p: PhantomData,
_p1: PhantomData,
_p2: PhantomData
}
}
}
impl<F: SyslogFormatter, D: SyslogDestination> SyStreamSyslogApi<F, D>
for &Syslog<F, D, SyShared>
{
type SYSLOG<'t> = &'t Syslog<F, D, SyShared>;
fn syslog<'t>(syslog: Self::SYSLOG<'t>, pri: Priority, fmt: F) -> SyRes<()>
{
syslog.syslog(pri, fmt)
}
}
#[cfg(feature = "build_with_queue")]
pub mod build_with_queue
{
use std::{sync::{Arc, Mutex, Weak, atomic::{AtomicBool, Ordering}}, thread};
use crate::{DefaultLocalSyslogDestination, SyslogDestination, formatters::{DefaultSyslogFormatter, SyslogFormatter}, map_error, sy_sync_queue::{SyCmd, SyslogInternal, SyslogQueueChanSnd, SyslogQueueChannel, SyslogQueueOneChanRcv}, sync::DefaultQueueAdapter};
use super::*;
#[derive(Debug, Clone)]
pub struct SyQueued<S = DefaultQueueAdapter, F = DefaultSyslogFormatter, D = DefaultLocalSyslogDestination>
where
F: SyslogFormatter,
D: SyslogDestination,
S: SyslogQueueChannel<F, D>,
{
run_control: Weak<AtomicBool>,
pub(crate) tasks: S::ChannelSnd,
thread: Arc<Mutex<Option<thread::JoinHandle<()>>>>,
}
impl<F, DD, S> SyslogType for SyQueued<S, F, DD>
where F: SyslogFormatter, DD: SyslogDestination, S: SyslogQueueChannel<F, DD>
{
type LockItemsBase = ();
type LockItems = Self::LockItemsBase;
type LockStreamBase<D: SyslogDestination> = SyQueued<S, F, DD>;
type LockStream<D: SyslogDestination> = Self::LockStreamBase<D>;
type MoveLockType = PhantomData<()>;
fn wrap_items(items: Self::LockItemsBase) -> Self::LockItems
{
items
}
fn wrap_stream<D: SyslogDestination>(stream: Self::LockStreamBase<D>) -> Self::LockStream<D>
{
stream
}
}
unsafe impl<F, D, S> Send for SyQueued<S, F, D>
where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
{}
impl<F, D, S> Drop for SyQueued<S, F, D>
where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
{
fn drop(&mut self)
{
if let Some(ctrl) = self.run_control.upgrade()
{
ctrl.store(false, Ordering::SeqCst);
if let Err(_e) = self.tasks.q_send_blocking(SyCmd::form_stop())
{
}
let join_handle = self.thread.lock().unwrap().take().unwrap();
let _ = join_handle.join();
}
}
}
impl<F, D, S> Clone for Syslog<F, D, SyQueued<S, F, D>>
where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
{
fn clone(&self) -> Self
{
Self
{
log_items:
self.log_items.clone(),
stream:
self.stream.clone(),
_p:
PhantomData,
_p_not_ss:
PhantomData
}
}
}
impl<F, D, S> DynSyslog for Syslog<F, D, SyQueued<S, F, D>>
where
F: SyslogFormatter,
D: SyslogDestination,
S: SyslogQueueChannel<F, D>
{
#[inline]
fn connectlog(&self) -> SyRes<()>
{
self.connectlog()
}
#[inline]
fn setlogmask(&self, logmask: i32) -> SyRes<i32>
{
self.setlogmask(logmask)
}
#[inline]
fn closelog(&self) -> SyRes<()>
{
self.closelog()
}
fn syslog(&self, pri: Priority, fmt: String) -> SyRes<()>
{
self.syslog(pri, fmt.into())
}
fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
{
self.change_identity(ident)
}
fn reconnect(&self) -> SyRes<()>
{
self.reconnect()
}
}
impl<F, D, S> Syslog<F, D, SyQueued<S, F, D>>
where
F: SyslogFormatter,
D: SyslogDestination,
S: SyslogQueueChannel<F, D>
{
pub
fn make_dyn(self) -> Box<dyn DynSyslog>
{
Box::new(self)
}
pub
fn openlog_with(ident: Option<&str>, logstat: LogStat, facility: LogFacility, net_tap_prov: D) -> SyRes<Self>
{
let log_items =
LogItems::new(ident, 0xff, logstat, facility);
let stream =
SyslogSocketLockless::<D>::new(logstat, net_tap_prov)?;
let (inst, sender, run_ctrl) =
SyslogInternal::<F, D, S>::new(log_items, stream)?;
let thr_name: String = "syslog_queue/0".into();
let thread_hnd =
thread::Builder::new()
.name(thr_name.clone())
.spawn(move || SyslogInternal::<F, D, S>::thread_worker(inst))
.map_err(|e|
map_error!("{} thread spawn failed. {}", thr_name, e)
)?;
let sy_q =
SyQueued
{
run_control:
run_ctrl,
tasks:
sender,
thread:
Arc::new(Mutex::new(Some(thread_hnd))),
};
return Ok(
Self
{
log_items:
(),
stream:
sy_q,
_p:
PhantomData,
_p_not_ss:
PhantomData
}
);
}
}
impl<F, D, S> Syslog<F, D, SyQueued<S, F, D>>
where
F: SyslogFormatter,
D: SyslogDestination,
S: SyslogQueueChannel<F, D>
{
pub
fn connectlog(&self) -> SyRes<()>
{
let (sy_cmd, loopback) =
SyCmd::form_connectlog();
self.stream.tasks.q_send_blocking(sy_cmd)?;
return
loopback
.recv_once_blocking()?;
}
pub
fn setlogmask(&self, logmask: i32) -> SyRes<i32>
{
let (sy_cmd, loopback) =
SyCmd::form_logmask(logmask);
self.stream.tasks.q_send_blocking(sy_cmd)?;
return
loopback
.recv_once_blocking();
}
pub
fn closelog(&self) -> SyRes<()>
{
let (sy_cmd, loopback) =
SyCmd::form_disconnectlog();
self.stream.tasks.q_send_blocking(sy_cmd)?;
return
loopback
.recv_once_blocking()?;
}
pub
fn syslog(&self, pri: Priority, fmt: F) -> SyRes<()>
{
let sy_cmd = SyCmd::form_syslog(pri, fmt);
return self.stream.tasks.q_send_blocking(sy_cmd);
}
pub
fn change_identity(&self, ident: Option<&str>) -> SyRes<()>
{
let sy_cmd =
SyCmd::form_change_ident(ident.map(|v| v.to_string()));
return
self.stream.tasks.q_send_blocking(sy_cmd);
}
pub
fn reconnect(&self) -> SyRes<()>
{
return
self.stream.tasks.q_send_blocking(SyCmd::form_reconnect());
}
pub
fn update_tap_data(&self, tap_data: D) -> SyRes<()>
{
let (tap_data_cmd, loopback) = SyCmd::form_update_tap(tap_data);
self.stream.tasks.q_send_blocking(tap_data_cmd)?;
return
loopback
.recv_once_blocking()?;
}
}
impl<F, D, S> Syslog<F, D, SyQueued<S, F, D>>
where
F: SyslogFormatter,
D: SyslogDestination,
S: SyslogQueueChannel<F, D>
{
pub
fn get_stream<'t, PRI>(&'t self) -> SyStream<'t, PRI, D, F, &'t Self>
where PRI: SyStreamPri
{
SyStream
{
s: Some(self),
_p: PhantomData,
_p1: PhantomData,
_p2: PhantomData
}
}
}
impl<F, D, S> SyStreamSyslogApi<F, D>
for &Syslog<F, D, SyQueued<S, F, D>>
where F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>
{
type SYSLOG<'t> = &'t Syslog<F, D, SyQueued<S, F, D>>;
fn syslog<'t>(syslog: Self::SYSLOG<'t>, pri: Priority, fmt: F) -> SyRes<()>
{
syslog.syslog(pri, fmt)
}
}
#[cfg(feature = "async_enabled")]
pub mod syslog_async_queue
{
use crate::error::SyRes;
use crate::sy_sync_queue::{SyCmd, SyslogQueueChanSnd, SyslogQueueChannel, SyslogQueueOneChanRcv};
use crate::{Priority, Syslog};
use crate::{formatters::SyslogFormatter, SyslogDestination, SyQueued};
use crate::a_sync::syslog_trait::AsyncSyslogQueueApi;
impl<F: SyslogFormatter, D: SyslogDestination, S: SyslogQueueChannel<F, D>> AsyncSyslogQueueApi<F, D>
for Syslog<F, D, SyQueued<S, F, D>>
{
async
fn a_connectlog(&mut self) -> SyRes<()>
{
let (sy_cmd, loopback) =
SyCmd::form_connectlog();
self.stream.tasks.q_send(sy_cmd).await?;
return
loopback
.recv_once()
.await?;
}
async
fn a_setlogmask(&self, logmask: i32) -> SyRes<i32>
{
let (sy_cmd, loopback) =
SyCmd::form_logmask(logmask);
self.stream.tasks.q_send(sy_cmd).await?;
return
loopback
.recv_once()
.await;
}
async
fn a_closelog(&self) -> SyRes<()>
{
let (sy_cmd, loopback) =
SyCmd::form_disconnectlog();
self.stream.tasks.q_send(sy_cmd).await?;
return
loopback
.recv_once()
.await?;
}
#[inline]
async
fn a_syslog(&self, pri: Priority, fmt: F) -> SyRes<()>
{
let sy_cmd = SyCmd::form_syslog(pri, fmt);
return self.stream.tasks.q_send(sy_cmd).await;
}
async
fn a_reconnect(&self) -> SyRes<()>
{
return
self.stream.tasks.q_send(SyCmd::form_reconnect()).await;
}
async
fn a_change_identity(&self, ident: &str) -> SyRes<()>
{
let sy_cmd =
SyCmd::form_change_ident(Some(ident.to_string()));
return
self.stream.tasks.q_send(sy_cmd).await;
}
async
fn a_update_tap_data(&self, new_tap: D) -> SyRes<()>
{
let (tap_data_cmd, loopback) = SyCmd::form_update_tap(new_tap);
self.stream.tasks.q_send(tap_data_cmd).await?;
return
loopback
.recv_once()
.await?;
}
}
}
}
#[cfg(feature = "build_with_queue")]
pub use self::build_with_queue::SyQueued;