logger2 0.1.5

A modern, feature-rich replacement for the classic `logger` CLI: syslog (local/remote, RFC3164 & RFC5424), truecolor hex output, emoji, JSON, and a fully configurable TOML config file.
Documentation
pub mod format;
pub mod transport;

use crate::config::Protocol;
use crate::error::Result;
use crate::level::Priority;
use std::path::Path;
use std::time::Duration;

/// Describes where and how a syslog message should be delivered.
pub struct Destination<'a> {
    pub server: Option<&'a str>,
    pub port: u16,
    pub protocol: Protocol,
    pub local_socket: &'a Path,
    pub rfc5424: bool,
    pub octet_count: bool,
    pub connect_timeout: Duration,
}

/// Builds the wire-format message and delivers it to the configured
/// destination (local socket, or remote UDP/TCP).
pub struct SyslogMessage<'a> {
    pub priority: Priority,
    pub hostname: &'a str,
    pub tag: &'a str,
    pub pid: Option<u32>,
    pub message: &'a str,
    pub structured_data: &'a [(String, String)],
}

pub fn deliver(dest: &Destination, msg: &SyslogMessage) -> Result<String> {
    let body = if dest.rfc5424 {
        format::rfc5424(
            msg.priority,
            msg.hostname,
            msg.tag,
            msg.pid,
            None,
            msg.structured_data,
            msg.message,
        )
    } else {
        format::rfc3164(msg.priority, msg.hostname, msg.tag, msg.pid, msg.message)
    };

    match dest.server {
        Some(server) => match dest.protocol {
            Protocol::Udp => transport::send_udp(server, dest.port, &body)?,
            Protocol::Tcp => {
                let framed = if dest.octet_count {
                    format::octet_count_frame(&body)
                } else {
                    format::newline_frame(&body)
                };
                transport::send_tcp(server, dest.port, &framed, dest.connect_timeout)?
            }
        },
        None => transport::send_local(dest.local_socket, &body)?,
    }

    Ok(body)
}