#syslog

syslog-rs

A native Rust implementation of the glibc/libc syslog

18 releases

0.7.1 Oct 20, 2024
0.6.0 Feb 5, 2024
0.5.1 Dec 9, 2023
0.5.0 Apr 2, 2023
0.2.1 Jun 12, 2021

#142 in Asynchronous

Download history 16/week @ 2024-09-23 4/week @ 2024-09-30 360/week @ 2024-10-14 32/week @ 2024-10-21

400 downloads per month

MPL-2.0 license

165KB
3.5K SLoC

syslog-rs

This crate is still under development. v 0.7.1

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.

Available features:

  • feature = "use_async" for asynchronious code
  • feature = "use_sync" for synchronious code
  • feature = "use_sync_queue" for synchronious with async processing
  • feature = "build_with_net" enables the TCP/UDP and extended interface

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 is different in some ways. Also, it spawns a worker thread which sends messages from the queue to syslog.

The use_async is async realization of the use_sync. Untested, probably requires further dev.

All 3 features can be used simpltaniously.

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"

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.

!!! use_async is using tokio mutex to achieve the synchronization. On the large async queues, when many tasks are spawned, the syslog becomes a performace bottleneck because syslog server may be busy, and syslog() is slow, and calling syslog() will lock other tasks until the lock will be released. Maybe it is good idea to have for example for each tokio thread a sibgle instance of the syslog.

Usage:

For customization: syslog-rs = {version = "0.7", default-features = false, features = ["use_sync"]}

Supports

  • GNU/Linux RFC3164 (UTF-8 by default)
  • *BSD and OSX RFC5424 (BOM UTF-8 by default)

Contributors

Ordered by Relkom s.r.o (c) 2021

Developed by: Aleksandr Morozov

Example

#[macro_use] extern crate syslog_rs;

use std::{sync::LazyLock, thread};
use std::time::Duration;
use syslog_rs::sy_sync::{Syslog, SyslogStd};
use syslog_rs::{LogStat, LogFacility, Priority};


pub static SYSLOG: LazyLock<Syslog> = LazyLock::new(|| 
    {
        Syslog::openlog(
           Some("example"), 
            LogStat::LOG_CONS | LogStat::LOG_NDELAY | LogStat::LOG_PID, 
            LogFacility::LOG_DAEMON
        )
        .unwrap()
    }
);

macro_rules! logdebug 
{
    ($($arg:tt)*) => (
        SYSLOG.syslog(Priority::LOG_DEBUG, format!($($arg)*))
    )
}



fn main()
{
    
    logdebug!("test message!");

    thread::sleep(Duration::from_micros(10));

    return;
}
use tokio::time::{Duration, sleep};

use syslog_rs::sy_async::{AsyncSyslog, AsyncSyslogStd, AsyncSyslogExt};
use syslog_rs::{LogStat, LogFacility, Priority};


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
        ).await.unwrap();


    SYSLOG.get_or_init(|| async { syslog }).await;


    logdebug!("test message!");
    
    SYSLOG.get().unwrap().vsyslog(Priority::LOG_DEBUG, "test 2").await;

    sleep(Duration::from_micros(10)).await;

    SYSLOG.get().unwrap().change_identity("new_identity").await;

    logdebug!("test message new identity!");

    sleep(Duration::from_micros(10)).await;

    return;
}

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 use_async
main: 81.101µs main: 12.74µs main: 67.549µs
t1: 91.02µs t2: 1.77µs t2: 44.779µs
t2: 129.919µs t1: 4.49µs t1: 5.76µs
t1: 31.32µs t2: 630ns t1: 7.74µs
t2: 9.09µs t1: 320ns t2: 4.58µs
t1: 10.82µs t2: 1.13µs t2: 13.77µs
t2: 7.23µs t1: 280ns t1: 5.62µs
t1: 11.68µs t1: 950ns t1: 6.55µs
t2: 7.239µs t2: 750ns t2: 4.47µs
t1: 11.57µs t1: 720ns t2: 7.22µs
t2: 6.61µs t2: 700ns t1: 4.43µs

Dependencies

~5–15MB
~165K SLoC