syslog-rs

This is NOT an Open Source software! This is Source Available or Sources Disclosed software!! If this is a concern, please don't use this crate.
v 3.0.0
This crate is dual-licensed with MPL-2.0 and EUPL-1.2.
An implementation of the syslog from glibc/libc like it was designed in
in both system libraries. The API is almost compatible with what is in
libc/glibc. Supports both sync and async and custom formatters.
- GNU/Linux RFC3164 (UTF-8 by default)
- *BSD and OSX RFC5424 (BOM UTF-8 by default)
- Tokio async
- Smol async
- TLS over TCP syslog server connection
- TCP/UDP syslog server connection
- Local file writer
Available features:
- feature =
build_async_tokio
or build_async_smol
for asynchronious execution. Cannot be used together.
- feature =
build_async_interface
an experimental feature which allowes to implement async for some
unsupported executor. See /docs/ for info. Can not be used together with build_async_tokio
or build_async_smol
.
- feature =
build_sync
for synchronious code
- feature =
build_with_queue
for synchronious with async processing when using build_sync
only. And when
used with one of the build_async_tokio
or build_async_smol
, can be used to write to syslog server from both sync and async code using sinle connection.
- feature =
build_with_net
enables the TCP/UDP
- feature =
build_ext_tls
enables the TLS over TCP support.
- feature =
build_ext_file
enables the local logging to file (without syslog server).
The use_sync
is acting like the libc's/glibc's functions syslog(), openlog()...
The use_sync_queue
has the same API as libc/glibc but it is different in some ways. It spawns a worker thread which sends messages from the queue (channel) to syslog. If used in conjunction with async can act as a sync/async interfacing by providing the ability to attach the async syslog instance to the sync queue and
use a signle channel to syslog server.
┌───────────────────────────────────────────────────────────────────┐
│build_with_queue │
│ │
│ build_sync │
│ ┌────────────┐ ┌───────────┐ │
│ │ SYNC_QUEUE ┼────► CROSSBEAM ┼────────────────┐ │
│ └────────────┘ │ adapter │ │ │
│ └───────────┘ │ │
│ │ │
│ build_async_tokio ┌───────────▼───────────┐│
│ ┌────────────┐ ┌────────────┐ │ ││
│ ┌────► SYNC_QUEUE ┼───► TOKIO MPSC ┼────► SYSLOG_WORKER THREAD ││
│ │ └────────────┘ │ adapter │ │ ││
│ │ └────────────┘ └───────────▲────▲──────┘│
│ │ │ │ │
│ │ build_async_smol ┌────────────┐ │ │ │
│ │ ┌────────────┐ │ SMOL MPSC │ │ │ │
│ ├────► SYNC_QUEUE ┼───► adapter ┼────────────────┘ │ │
│ │ └────────────┘ └────────────┘ │ │
│ │ │ │
│ │ │ │
│ │ build_async_interface │ │
│ │ ┌────────────┐ ┌────────────┐ │ │
│ ┼────► SYNC_QUEUE ┼───► EXT MPSC ┼─────────────────────┘ │
│ │ └────────────┘ │ adapter │ │
│ │ └────────────┘ │
│ │ ┌──────────────────────┐ │
│ └──┼ AsyncSyslogQueueApi │ │
│ │ trait │ │
│ └──────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘
The use_async_*
is async realization of the use_sync
based on the specific executor.
Available tunables:
- feature = "udp_truncate_1024_bytes"
- feature = "udp_truncate_1440_bytes" DEFAULT
The above is for RFC5424 which controls the syslog message length for forwarding via UDP protocol.
-
feature = "tcp_truncate_1024_bytes"
-
feature = "tcp_truncate_2048_bytes" DEFAULT
-
feature = "tcp_truncate_4096_bytes"
-
feature = "tcp_truncate_max_bytes"
-
feature = "truncate_default" - a shortcut for "udp_truncate_1440_bytes" and "tcp_truncate_2048_bytes"
The above is for RFC5424 which controls the syslog message length for forwarding via TCP protocol.
- feature = "dgram_sysctl_failure_panic"
The above is for *BSD systems only and controls the behaviour of the sysctl error handling. If this is
enabled, the crate will panic is access to sysctl fails. Not enabled by default.
Usage:
For default
syslog-rs = "3.0"
For customization:
syslog-rs = {version = "3.0", default-features = false, features = ["use_sync", "truncate_default"]}
Contributors
Ordered by Relkom s.r.o (c) 2021
Developed by:
Aleksandr Morozov
Examples
See ./examples/ in the repository.
Sync syslog (Local Shared)
use std::{sync::LazyLock, thread};
use std::time::Duration;
use syslog_rs::Syslog;
use syslog_rs::{LogFacility, LogStat, Priority, SyslogLocal};
pub static SYSLOG: LazyLock<Syslog> = LazyLock::new(||
{
Syslog::openlog(
Some("example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON, SyslogLocal::new()
)
.unwrap()
}
);
pub static SYSLOG2: LazyLock<Syslog> = LazyLock::new(||
{
Syslog::openlog(
None,
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON, SyslogLocal::new()
)
.unwrap()
}
);
macro_rules! logdebug
{
($($arg:tt)*) => (
SYSLOG.syslog(Priority::LOG_DEBUG, format!($($arg)*))
)
}
macro_rules! logdebug2
{
($($arg:tt)*) => (
SYSLOG2.syslog(Priority::LOG_DEBUG, format!($($arg)*))
)
}
pub fn main()
{
logdebug2!("test program name!");
logdebug!("test message1!");
SYSLOG.change_identity("example2").unwrap();
logdebug!("test message from new ident");
thread::sleep(Duration::from_micros(10));
return;
}
Async syslog (Local Shared)
use syslog_rs::sy_async::AsyncSyslog;
use tokio::sync::OnceCell;
use tokio::time::{Duration, sleep};
use syslog_rs::{LogFacility, LogStat, Priority, SyslogLocal};
pub static SYSLOG: OnceCell<AsyncSyslog> = OnceCell::const_new();
macro_rules! logdebug
{
($($arg:tt)*) => (
SYSLOG.get().unwrap().syslog(Priority::LOG_DEBUG, format!($($arg)*)).await
)
}
#[tokio::main]
async fn main()
{
let syslog =
AsyncSyslog::openlog(
Some("example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogLocal::new()
)
.await
.unwrap();
SYSLOG.get_or_init(|| async { syslog }).await;
logdebug!("test message async start!");
SYSLOG.get().unwrap().vsyslog(Priority::LOG_DEBUG, "test 2").await;
sleep(Duration::from_micros(10)).await;
SYSLOG.get().unwrap().change_identity("new_identity").await.unwrap();
logdebug!("test message new identity!");
sleep(Duration::from_micros(10)).await;
logdebug!("test 123!");
logdebug!("test 123123! end ");
return;
}
Custom formatter.
use std::{borrow::Cow, sync::OnceLock};
use std::thread;
use std::time::Duration;
use chrono::{Local, SecondsFormat};
use syslog_rs::sy_sync::Syslog;
use syslog_rs::{SyslogFile, NEXTLINE, WSPACE};
use syslog_rs::{common, formatters::{SyslogFormatted, SyslogFormatter}, SyslogShared, TapType};
use syslog_rs::{LogStat, LogFacility, Priority};
pub static SYNC_SYSLOG: OnceLock<Syslog<SyslogFile, SyslogShared<MyFormatter, SyslogFile>>> = OnceLock::new();
macro_rules! logdebug
{
($($arg:tt)*) => (
SYNC_SYSLOG.get().unwrap().syslog(Priority::LOG_DEBUG, format!($($arg)*));
)
}
#[derive(Debug, Clone)]
pub struct MyFormatter();
unsafe impl Send for MyFormatter {}
impl SyslogFormatter for MyFormatter
{
fn vsyslog1_format<'f>(_tap_type: TapType, _max_msg_size: usize, pri: Priority, progname: &'f str, pid: &'f str, fmt: &'f str) -> SyslogFormatted<'f>
{
let timedate = Local::now().to_rfc3339_opts(SecondsFormat::Secs, false);
let msg_payload_final =
if fmt.ends_with("\n") == true
{
common::truncate(fmt)
}
else
{
fmt
};
let msg_pkt =
[
Cow::Owned(pri.to_string()), Cow::Borrowed(WSPACE), Cow::Borrowed("MYFORMATTER"),
Cow::Borrowed(WSPACE), Cow::Owned(timedate),
Cow::Borrowed(WSPACE), Cow::Borrowed(progname),
Cow::Borrowed(WSPACE), Cow::Borrowed(pid),
Cow::Borrowed(WSPACE), Cow::Borrowed(msg_payload_final), Cow::Borrowed(NEXTLINE)
]
.to_vec();
let msg_rng = msg_pkt.len();
return SyslogFormatted::new( msg_pkt, 0..msg_rng );
}
}
pub fn main()
{
let syslog =
Syslog
::<SyslogFile, SyslogShared<MyFormatter, SyslogFile>>
::openlog_with(
Some("example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogFile::new("/tmp/myformatter.log")
).unwrap();
SYNC_SYSLOG.get_or_init(|| syslog);
logdebug!("test message!");
SYNC_SYSLOG.get().unwrap().change_identity("another").unwrap();
logdebug!("test message new!");
thread::sleep(Duration::from_micros(10));
return;
}
Formatter select
use std::sync::OnceLock;
use std::thread;
use std::time::Duration;
use syslog_rs::sy_sync::Syslog;
#[cfg(target_os = "linux")]
use syslog_rs::{formatters::{FormatRfc3146}, SyslogLocal, SyslogShared};
#[cfg(not(target_os = "linux"))]
use syslog_rs::{formatters::{FormatRfc5424}, SyslogLocal, SyslogShared};
use syslog_rs::{LogStat, LogFacility, Priority};
#[cfg(target_os = "linux")]
pub static SYNC_SYSLOG: OnceLock<Syslog<SyslogLocal, SyslogShared<FormatRfc3146>>> = OnceLock::new();
#[cfg(not(target_os = "linux"))]
pub static SYNC_SYSLOG: OnceLock<Syslog<SyslogLocal, SyslogShared<FormatRfc5424>>> = OnceLock::new();
macro_rules! logdebug
{
($($arg:tt)*) => (
SYNC_SYSLOG.get().unwrap().syslog(Priority::LOG_DEBUG, format!($($arg)*));
)
}
pub fn main()
{
let syslog =
Syslog::<_>::openlog_with(
Some("formatter_sel"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogLocal::new()
).unwrap();
SYNC_SYSLOG.get_or_init(|| syslog);
logdebug!("test message!");
thread::sleep(Duration::from_micros(10));
return;
}
SYNC and ASYNC to same "tap" i.e same connection
Either build_async_tokio
or build_async_smol
and build_with_queue
should be enabled. Example below requires also feature build_ext_file
to be enabled.
use std::sync::OnceLock;
use std::thread;
use std::time::Duration;
use syslog_rs::formatters::DefaultSyslogFormatterFile;
use syslog_rs::sy_sync::Syslog;
use syslog_rs::sync::DefaultQueueAdapter;
use syslog_rs::{LogFacility, LogStat, Priority, SyslogFile, SyslogQueue};
use syslog_rs::AsyncSyslogQueueApi;
use tokio::sync::{mpsc};
use tokio::{runtime, task};
pub static SYSLOG: OnceLock<Syslog<SyslogFile, SyslogQueue<DefaultQueueAdapter, DefaultSyslogFormatterFile, SyslogFile>>> = OnceLock::new();
macro_rules! logdebug
{
($($arg:tt)*) => (
SYSLOG.get().as_ref().unwrap().syslog(Priority::LOG_DEBUG, format!($($arg)*))
)
}
macro_rules! alogdebug
{
($($arg:tt)*) => (
SYSLOG.get().as_ref().unwrap().a_syslog(Priority::LOG_DEBUG, format!($($arg)*)).await
)
}
pub fn main()
{
SYSLOG.get_or_init(move || {
Syslog::<SyslogFile, SyslogQueue<_, DefaultSyslogFormatterFile, SyslogFile>>::openlog_with(
Some("example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogFile::new("/tmp/example_logtofile.txt")
)
.unwrap()
});
logdebug!("test message logtofile!");
thread::sleep(Duration::from_micros(10));
let runtime =
runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
runtime.block_on(async
{
let s =
task::spawn_blocking(move ||
{
for i in 0..10
{
logdebug!("blocking thread message no: '{}'", i);
thread::sleep(Duration::from_micros(300));
}
return;
}
);
for i in 0..10
{
alogdebug!("async thread message no: '{}'", i);
tokio::time::sleep(Duration::from_micros(304)).await;
}
s.await.unwrap();
let (tx, mut rx) = mpsc::channel::<u64>(1);
task::spawn_blocking(move ||
{
SYSLOG.get().unwrap().update_tap(SyslogFile::new("/tmp/example_logtofile2.txt")).unwrap();
tx.blocking_send(0).unwrap();
for i in 0..10
{
logdebug!("blocking NEW thread message no: '{}'", i);
thread::sleep(Duration::from_micros(300));
}
return;
}
);
rx.recv().await;
for i in 0..10
{
alogdebug!("async NEW thread message no: '{}'", i);
tokio::time::sleep(Duration::from_micros(304)).await;
}
}
);
logdebug!("test message logtofile!");
return;
}
Exampe UDP
This example requires the feature build_ext_net
to be enabled.
use std::{sync::LazyLock, thread};
use std::time::Duration;
use syslog_rs::formatters::DefaultSyslogFormatter;
use syslog_rs::sy_sync::Syslog;
use syslog_rs::{LogFacility, LogStat, Priority, SyslogNetUdp, SyslogShared};
pub static SYSLOG: LazyLock<Syslog<SyslogNetUdp, SyslogShared<DefaultSyslogFormatter, SyslogNetUdp>>> = LazyLock::new(||
{
Syslog::<SyslogNetUdp, SyslogShared<DefaultSyslogFormatter, SyslogNetUdp>>::openlog_with(
Some("example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogNetUdp::new("127.0.0.1:7777", None).unwrap()
)
.unwrap()
}
);
macro_rules! logdebug
{
($($arg:tt)*) => (
SYSLOG.syslog(Priority::LOG_DEBUG, format!($($arg)*))
)
}
pub fn main()
{
logdebug!("test message!");
thread::sleep(Duration::from_micros(10));
return;
}
TLS
This exampel requires the feature build_ext_tls
to be enabled.
use std::{sync::LazyLock, thread};
use std::time::Duration;
use syslog_rs::formatters::DefaultSyslogFormatter;
use syslog_rs::sy_sync::Syslog;
use syslog_rs::{LogFacility, LogStat, Priority, SyslogShared, SyslogTls};
pub const CERT_INLINE: &'static [u8] = b"cert...";
pub static SYSLOG: LazyLock<Syslog<SyslogTls, SyslogShared<DefaultSyslogFormatter, SyslogTls>>> = LazyLock::new(||
{
Syslog::<SyslogTls, SyslogShared<DefaultSyslogFormatter, SyslogTls>>::openlog_with(
Some("example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogTls::new("127.0.0.1:514", None, "domain.tld", CERT_INLINE.to_vec(), None).unwrap()
)
.unwrap()
}
);
macro_rules! logdebug
{
($($arg:tt)*) => (
SYSLOG.syslog(Priority::LOG_DEBUG, format!($($arg)*))
)
}
pub fn main()
{
logdebug!("test message!");
thread::sleep(Duration::from_micros(10));
return;
}
SMOL
use std::time::Duration;
use smol::{io, Timer};
use smol::lock::OnceCell;
use syslog_rs::sy_async::AsyncSyslog;
use syslog_rs::{LogFacility, LogStat, Priority, SyslogLocal};
pub static SYSLOG: OnceCell<AsyncSyslog> = OnceCell::new();
macro_rules! logdebug
{
($($arg:tt)*) => (
SYSLOG.get().unwrap().syslog(Priority::LOG_DEBUG, format!($($arg)*)).await
)
}
fn main() -> io::Result<()>
{
smol::block_on(
async
{
let syslog =
AsyncSyslog::openlog(
Some("smol_example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
SyslogLocal::new()
)
.await
.unwrap();
SYSLOG.get_or_init(|| async { syslog }).await;
logdebug!("SMOL test message async start!");
SYSLOG.get().unwrap().vsyslog(Priority::LOG_DEBUG, "SMOL test 2").await;
Timer::after(Duration::from_micros(10)).await;
SYSLOG.get().unwrap().change_identity("SMOL_new_identity").await;
logdebug!("SMOL test message new identity!");
Timer::after(Duration::from_micros(10)).await;
logdebug!("SMOL test 123!");
logdebug!("SMOL test 123123! end ");
Ok(())
}
)
}
External async executor
From the crate version 3, the crate can be provided with custom implementation of the async props like sockets or other things. In order to achieve this
some traits should be implemented in the program which uses this crate and enables the build_async_interface
. The build-in async exec like tokio or smol
can not be enabled together.
See example file.
extern crate syslog_rs;
use std::fmt;
use std::io::ErrorKind;
use std::net::Shutdown;
use std::time::Duration;
use std::{borrow::Cow, io::IoSlice};
use syslog_rs::a_sync::AsyncMutexGuard;
use syslog_rs::formatters::DefaultSyslogFormatter;
use syslog_rs::nix::errno::Errno;
use syslog_rs::nix::libc;
use syslog_rs::error::SyslogError;
use syslog_rs::{common, throw_error_errno, throw_error_os, AsyncSyslog, AsyncSyslogTap, AsyncTap, LogFacility, LogStat, Priority, SyslogDestMsg, SyslogLocal, TapType, PATH_CONSOLE, PATH_LOG, PATH_LOG_PRIV, PATH_OLDLOG, PATH_OSX};
use syslog_rs::{a_sync::{syslog_async_internal::{AsyncSyslogInternal, AsyncSyslogInternalIO}, AsyncMutex}, error::SyRes, formatters::SyslogFormatter, map_error_os, AsyncSyslogDestination};
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use tokio::net::UnixDatagram;
use tokio::sync::MutexGuard;
use tokio::time::sleep;
use tokio::{io::AsyncWrite, sync::Mutex};
#[derive(Debug)]
pub struct OurAsyncSyslogIO;
impl OurAsyncSyslogIO
{
pub(crate) async
fn async_send_to_fd<W>(mut file_fd: W, msg: &[Cow<'_, str>], newline: &str) -> SyRes<usize>
where W: AsyncWrite + Unpin
{
let mut iov_list: Vec<IoSlice<'_>> = Vec::with_capacity(msg.len() + 1);
msg.iter().for_each(|v| iov_list.push(IoSlice::new(v.as_bytes())));
iov_list.push(IoSlice::new(newline.as_bytes()));
return
file_fd
.write_vectored(&iov_list)
.await
.map_err(|e|
map_error_os!(e, "async_send_to_fd() writev() failed")
);
}
}
impl AsyncSyslogInternalIO for OurAsyncSyslogIO
{
#[inline]
async
fn send_to_stderr(logstat: LogStat, msg: &[Cow<'_, str>])
{
if logstat.intersects(LogStat::LOG_PERROR) == true
{
let stderr_lock = tokio::io::stderr();
let newline = "\n";
let _ = Self::async_send_to_fd(stderr_lock, msg, newline).await;
}
}
#[inline]
async
fn send_to_syscons(logstat: LogStat, msg_payload: &[Cow<'_, str>])
{
if logstat.intersects(LogStat::LOG_CONS)
{
let syscons =
File
::options()
.create(false)
.read(false)
.write(true)
.custom_flags(libc::O_NONBLOCK | libc::O_CLOEXEC)
.open(*PATH_CONSOLE)
.await;
if let Ok(file) = syscons
{
let newline = "\n";
let _ = Self::async_send_to_fd(file, msg_payload, newline);
}
}
}
async
fn sleep_micro(us: u64)
{
sleep(Duration::from_micros(us)).await;
}
}
#[derive(Debug)]
struct MutexOveride<T: Sized>(Mutex<T>);
#[derive(Debug)]
struct MutexGuardNative<'a, T>(MutexGuard<'a, T>);
impl<'a, T> MutexGuardNative<'a, T>
{
fn new(g: MutexGuard<'a, T>) -> Self
{
return Self(g);
}
}
impl<F: SyslogFormatter + Send, D: AsyncSyslogDestination> AsyncMutex<F, D, AsyncSyslogInternal<F, D, OurAsyncSyslogIO>>
for MutexOveride<AsyncSyslogInternal<F, D, OurAsyncSyslogIO>>
{
type MutxGuard<'mux> = MutexGuardNative<'mux, AsyncSyslogInternal<F, D, OurAsyncSyslogIO>>;
fn a_new(v: AsyncSyslogInternal<F, D, OurAsyncSyslogIO>) -> Self
{
return Self(Mutex::new(v));
}
async
fn a_lock<'mux>(&'mux self) -> Self::MutxGuard<'mux>
{
return MutexGuardNative::new(self.0.lock().await);
}
}
impl<'mux, F: SyslogFormatter + Send, D: AsyncSyslogDestination> AsyncMutexGuard<'mux, F, D, AsyncSyslogInternal<F, D, OurAsyncSyslogIO>>
for MutexGuardNative<'mux, AsyncSyslogInternal<F, D, OurAsyncSyslogIO>>
{
fn guard(&self) -> &AsyncSyslogInternal<F, D, OurAsyncSyslogIO>
{
return &self.0;
}
fn guard_mut(&mut self) -> &mut AsyncSyslogInternal<F, D, OurAsyncSyslogIO>
{
return &mut self.0;
}
}
#[derive(Debug, Clone)]
struct NativeSyslogLocal(SyslogLocal);
impl NativeSyslogLocal
{
fn new(s: SyslogLocal) -> Self
{
return Self(s);
}
}
impl fmt::Display for NativeSyslogLocal
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.0)
}
}
impl AsyncSyslogDestination for NativeSyslogLocal
{
type SocketTap = AsyncTap::<tokio::net::UnixDatagram, Self>;
}
impl SyslogDestMsg for NativeSyslogLocal
{
fn get_max_msg_len(&self) -> usize
{
if *common::RFC5424_MAX_DGRAM >= common::MAXLINE
{
return common::MAXLINE;
}
else
{
return *common::RFC5424_MAX_DGRAM;
};
}
}
impl AsyncSyslogTap<NativeSyslogLocal> for AsyncTap<UnixDatagram, NativeSyslogLocal>
{
fn new(req_tap: NativeSyslogLocal) -> SyRes<Self>
{
return Self::new(req_tap);
}
async
fn connectlog(&mut self) -> SyRes<()>
{
let sock =
UnixDatagram
::unbound()
.map_err(|e|
map_error_os!(e, "unbounded unix datagram initialization failure: {}", e)
)?;
let tap_type =
if self.get_tap_data().0.get_use_alternative() == false && self.get_tap_data().0.get_custom_remote_path().is_some() == true
{
if let Err(e) = sock.connect(self.get_tap_data().0.get_custom_remote_path().as_ref().unwrap())
{
throw_error_os!(e, "failed to open connection to syslog server at '{}'",
self.get_tap_data().0.get_custom_remote_path().as_ref().unwrap().display());
}
else
{
TapType::CustomLog
}
}
else if self.get_tap_data().0.get_custom_remote_path().is_some() == true &&
sock.connect(self.get_tap_data().0.get_custom_remote_path().as_ref().unwrap()).is_ok() == true
{
TapType::CustomLog
}
else if let Ok(_) = sock.connect(PATH_LOG_PRIV)
{
TapType::Priv
}
else if let Ok(_) = sock.connect(PATH_LOG)
{
TapType::UnPriv
}
else if let Ok(_) = sock.connect(PATH_OLDLOG)
{
TapType::OldLog
}
else if let Ok(_) = sock.connect(PATH_OSX)
{
TapType::Priv
}
else
{
throw_error_errno!(Errno::last(), "failed to open connection to syslog server");
};
self.set_sock(sock);
self.set_cur_tap_type(tap_type);
return Ok(());
}
async
fn send(&mut self, msg: &[u8]) -> std::io::Result<usize>
{
let sock =
self
.get_sock_mut()
.ok_or_else(||
std::io::Error::new(ErrorKind::NotConnected, "no connection")
)?;
return sock.send(msg).await;
}
async
fn disconnectlog(&mut self) -> std::io::Result<()>
{
match self.take_sock()
{
Some(s) =>
{
self.set_cur_tap_type(TapType::None);
s.shutdown(Shutdown::Both)
},
None =>
{
self.set_cur_tap_type(TapType::None);
Ok(())
}
}
}
fn is_connected(&self) -> bool
{
return self.get_sock().is_some();
}
fn get_type(&self) -> TapType
{
return self.get_tap_type();
}
fn get_max_msg_size(&self) -> usize
{
return self.get_tap_data().get_max_msg_len();
}
fn update_tap_data(&mut self, tap_data: NativeSyslogLocal)
{
self.update_tap_data(tap_data);
}
}
#[tokio::main]
async
fn main()
{
let syslog =
AsyncSyslog
::<NativeSyslogLocal, DefaultSyslogFormatter, OurAsyncSyslogIO, MutexOveride<_>>
::openlog_with(
Some("example_cust"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON,
NativeSyslogLocal::new(SyslogLocal::new())
)
.await
.unwrap();
syslog.vsyslog(Priority::LOG_DEBUG, "test custom async exec in example").await;
println!("Hello, world!");
}
</details>
Benchmarking
The test spawns 2 threads and one main thread. All 3 threads are sending messages to syslog. The time measurment in the tables are approximations.
Results of the tests in syslog_*.rs files in Debug mode (AMD Ryzen 5 7600X 6-Core Processor):
use_sync (sys mutex) |
use_sync_queue |
build_with_async |
main: 87.31µs |
main: 12.74µs |
main: 94.849µs |
t1: 170.809µs |
t2: 1.77µs |
t2: 12.339µs |
t2: 69.529µs |
t1: 4.49µs |
t1: 7.2µs |
t1: 6.87µs |
t2: 630ns |
t1: 16.32µs |
t2: 5.8µs |
t1: 320ns |
t2: 6.26µs |
t1: 5.7µs |
t2: 1.13µs |
t2: 14.74µs |
t2: 5.46µs |
t1: 280ns |
t1: 6.7µs |
t1: 5.83µs |
t1: 950ns |
t1: 8.73µs |
t2: 7.239µs |
t2: 750ns |
t2: 5.37µs |
t1: 5.8µs |
t1: 720ns |
t2: 8.02µs |
t2: 5.38µs |
t2: 700ns |
t1: 5.34µs |