use crate::level::Priority;
use chrono::Local;
pub fn rfc3164(priority: Priority, hostname: &str, tag: &str, pid: Option<u32>, message: &str) -> String {
let now = Local::now();
let timestamp = now.format("%b %e %H:%M:%S");
let tag_field = match pid {
Some(p) => format!("{}[{}]", tag, p),
None => tag.to_string(),
};
format!(
"<{}>{} {} {}: {}",
priority.pri(),
timestamp,
hostname,
tag_field,
message
)
}
pub fn rfc5424(
priority: Priority,
hostname: &str,
tag: &str,
pid: Option<u32>,
msgid: Option<&str>,
structured_data: &[(String, String)],
message: &str,
) -> String {
let now = Local::now();
let timestamp = now.to_rfc3339_opts(chrono::SecondsFormat::Millis, false);
let procid = pid.map(|p| p.to_string()).unwrap_or_else(|| "-".to_string());
let msgid = msgid.unwrap_or("-");
let sd = if structured_data.is_empty() {
"-".to_string()
} else {
let pairs: Vec<String> = structured_data
.iter()
.map(|(k, v)| format!("{}=\"{}\"", sanitize_sd_key(k), escape_sd_value(v)))
.collect();
format!("[logger2@32473 {}]", pairs.join(" "))
};
format!(
"<{}>1 {} {} {} {} {} {} {}",
priority.pri(),
timestamp,
hostname,
tag,
procid,
msgid,
sd,
message
)
}
fn sanitize_sd_key(k: &str) -> String {
k.chars()
.filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_')
.collect()
}
fn escape_sd_value(v: &str) -> String {
v.replace('\\', "\\\\").replace('"', "\\\"").replace(']', "\\]")
}
pub fn octet_count_frame(message: &str) -> String {
format!("{} {}", message.len(), message)
}
pub fn newline_frame(message: &str) -> String {
format!("{}\n", message)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::level::{Facility, Level};
#[test]
fn rfc3164_basic_shape() {
let pri = Priority {
facility: Facility::User,
level: Level::Notice,
};
let out = rfc3164(pri, "myhost", "mytag", Some(1234), "hello world");
assert!(out.starts_with("<13>"));
assert!(out.contains("myhost"));
assert!(out.contains("mytag[1234]:"));
assert!(out.ends_with("hello world"));
}
#[test]
fn rfc5424_basic_shape() {
let pri = Priority {
facility: Facility::Local0,
level: Level::Error,
};
let out = rfc5424(pri, "myhost", "mytag", Some(42), None, &[], "boom");
assert!(out.starts_with("<131>1 "));
assert!(out.contains("myhost"));
assert!(out.contains("mytag"));
assert!(out.ends_with("boom"));
}
}