# 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.
### Temporary Issues tracker: [A public crate's Issues Tracker](https://gitlab.com/4neko/syslog-rs).
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.
```text
┌───────────────────────────────────────────────────────────────────┐
│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)
<details>
<summary>Example</summary>
```rust
use std::{sync::LazyLock, thread};
use std::time::Duration;
use syslog_rs::Syslog;
use syslog_rs::{LogFacility, LogStat, Priority, SyslogLocal};
Syslog::openlog(
Some("example"),
LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID,
LogFacility::LOG_DAEMON, SyslogLocal::new()
)
.unwrap()
}
);
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;
}
```
</details>
### Async syslog (Local Shared)
<details>
<summary>Example</summary>
```rust
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;
}
```
</details>
### Custom formatter.
<details>
<summary>Example</summary>
```rust
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;
}
```
</details>
### Formatter select
<details>
<summary>Example</summary>
```rust
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;
}
```
</details>
### 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.
<details>
<summary>Example</summary>
```rust
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;
}
```
</details>
### Exampe UDP
This example requires the feature `build_ext_net` to be enabled.
<details>
<summary>Example</summary>
```rust
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};
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()
{
// netcat -ul 7777
logdebug!("test message!");
thread::sleep(Duration::from_micros(10));
return;
}
```
</details>
### TLS
This exampel requires the feature `build_ext_tls` to be enabled.
<details>
<summary>Example</summary>
```rust
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...";
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;
}
```
</details>
### SMOL
<details>
<summary>Example</summary>
```rust
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(())
}
)
}
```
</details>
### 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.
<details>
<summary>Example</summary>
```rust
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};
/// Implemeting the custom IO and thread control things which is needed by the crate.
#[derive(Debug)]
pub struct OurAsyncSyslogIO;
impl OurAsyncSyslogIO
{
/// Sends to the FD i.e file of stderr, stdout or any which
/// implements [Write] `write_vectored` in async manner
///
/// # Arguments
///
/// * `file_fd` - mutable consume of the container FD.
///
/// * `msg` - a reference on array of data
///
/// * `newline` - a new line string ref i.e "\n" or "\r\n"
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;
}
}
/// Implementing the mutex realization for out executor.
#[derive(Debug)]
struct MutexOveride<T: Sized>(Mutex<T>);
/// Also the mutex guard.
#[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;
}
}
/// Implementing the sylog provider (in this example a SyslogLocal will be wrapped into our struct
/// because it is not possible to implement foreign traits for foreign structs.
#[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)
}
}
/// A async destination where the type of the tap i.e socket is declared.
impl AsyncSyslogDestination for NativeSyslogLocal
{
type SocketTap = AsyncTap::<tokio::net::UnixDatagram, Self>;
}
/// A maximum message size.
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;
};
}
}
/// Implementing a [AsyncSyslogTap] for the previously created [NativeSyslogLocal] for the
/// [AsyncTap] - socket.
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
{
// failed to open socket
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()
{
// provide everything which was created to the AsyncSyslog.
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 |
|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 |