pyruse/src/infra/log.rs

158 lines
4.8 KiB
Rust

use crate::domain::{LogMessage, LogPort, Record, Value};
use chrono::DateTime;
use std::collections::HashMap;
use std::iter::FromIterator;
use systemd::journal::{print, Journal, OpenOptions};
type JournalFieldMapper = fn(String) -> Value;
const STR_MAPPER: JournalFieldMapper = |s| Value::Str(s);
const INT_MAPPER: JournalFieldMapper = |s| {
s.parse::<isize>()
.map(|i| Value::Int(i))
.unwrap_or(Value::Str(s))
};
const DATE_MAPPER: JournalFieldMapper = |s| {
s.parse::<DateTime<chrono::Utc>>()
.map(|d| Value::Date(d))
.unwrap_or(Value::Str(s))
};
pub struct SystemdLogAdapter {
journal: Journal,
mappers: HashMap<String, JournalFieldMapper>,
}
impl SystemdLogAdapter {
pub fn open() -> Result<Self, ()> {
let mappers = create_mappers();
if let Ok(mut journal) = OpenOptions::default()
.system(true)
.current_user(false)
.local_only(false)
.open()
{
if let Ok(_) = journal.seek_tail() {
return Ok(SystemdLogAdapter { journal, mappers });
}
}
Err(())
}
}
impl LogPort for SystemdLogAdapter {
fn read_next(&mut self) -> Result<Record, ()> {
loop {
match self.journal.await_next_entry(None) {
Err(_) => return Err(()),
Ok(Some(mut entry)) => {
let mut record: Record = HashMap::with_capacity(entry.len());
let all_keys = entry.keys().map(|s| s.clone()).collect::<Vec<String>>();
for k in all_keys {
let (k, v) = entry.remove_entry(&k).unwrap();
let mapper = self.mappers.get(&k);
if mapper == None {
continue;
}
record.insert(k, (mapper.unwrap())(v));
}
return Ok(record);
}
Ok(None) => continue,
};
}
}
fn write(&mut self, message: LogMessage) -> Result<(), ()> {
let unix_status = match message {
LogMessage::EMERG(m) => print(0, m),
LogMessage::ALERT(m) => print(1, m),
LogMessage::CRIT(m) => print(2, m),
LogMessage::ERR(m) => print(3, m),
LogMessage::WARNING(m) => print(4, m),
LogMessage::NOTICE(m) => print(5, m),
LogMessage::INFO(m) => print(6, m),
LogMessage::DEBUG(m) => print(7, m),
};
match unix_status {
0 => Ok(()),
_ => Err(()),
}
}
}
fn create_mappers<'t>() -> HashMap<String, JournalFieldMapper> {
let map: HashMap<String, JournalFieldMapper> = HashMap::from_iter(
[
("MESSAGE", STR_MAPPER),
("MESSAGE_ID", STR_MAPPER),
("PRIORITY", INT_MAPPER),
("CODE_FILE", STR_MAPPER),
("CODE_LINE", INT_MAPPER),
("CODE_FUNC", STR_MAPPER),
("ERRNO", INT_MAPPER),
("INVOCATION_ID", STR_MAPPER),
("USER_INVOCATION_ID", STR_MAPPER),
("SYSLOG_FACILITY", INT_MAPPER),
("SYSLOG_IDENTIFIER", STR_MAPPER),
("SYSLOG_PID", INT_MAPPER),
("SYSLOG_TIMESTAMP", DATE_MAPPER),
("SYSLOG_RAW", STR_MAPPER),
("DOCUMENTATION", STR_MAPPER),
("TID", INT_MAPPER),
("_PID", INT_MAPPER),
("_UID", INT_MAPPER),
("_GID", INT_MAPPER),
("_COMM", STR_MAPPER),
("_EXE", STR_MAPPER),
("_CMDLINE", STR_MAPPER),
("_CAP_EFFECTIVE", STR_MAPPER),
("_AUDIT_SESSION", STR_MAPPER),
("_AUDIT_LOGINUID", INT_MAPPER),
("_SYSTEMD_CGROUP", STR_MAPPER),
("_SYSTEMD_SLICE", STR_MAPPER),
("_SYSTEMD_UNIT", STR_MAPPER),
("_SYSTEMD_USER_UNIT", STR_MAPPER),
("_SYSTEMD_USER_SLICE", STR_MAPPER),
("_SYSTEMD_SESSION", STR_MAPPER),
("_SYSTEMD_OWNER_UID", INT_MAPPER),
("_SELINUX_CONTEXT", STR_MAPPER),
("_SOURCE_REALTIME_TIMESTAMP", DATE_MAPPER),
("_BOOT_ID", STR_MAPPER),
("_MACHINE_ID", STR_MAPPER),
("_SYSTEMD_INVOCATION_ID", STR_MAPPER),
("_HOSTNAME", STR_MAPPER),
("_TRANSPORT", STR_MAPPER),
("_STREAM_ID", STR_MAPPER),
("_LINE_BREAK", STR_MAPPER),
("_NAMESPACE", STR_MAPPER),
("_KERNEL_DEVICE", STR_MAPPER),
("_KERNEL_SUBSYSTEM", STR_MAPPER),
("_UDEV_SYSNAME", STR_MAPPER),
("_UDEV_DEVNODE", STR_MAPPER),
("_UDEV_DEVLINK", STR_MAPPER),
("COREDUMP_UNIT", STR_MAPPER),
("COREDUMP_USER_UNIT", STR_MAPPER),
("OBJECT_PID", INT_MAPPER),
("OBJECT_UID", INT_MAPPER),
("OBJECT_GID", INT_MAPPER),
("OBJECT_COMM", STR_MAPPER),
("OBJECT_EXE", STR_MAPPER),
("OBJECT_CMDLINE", STR_MAPPER),
("OBJECT_AUDIT_SESSION", STR_MAPPER),
("OBJECT_AUDIT_LOGINUID", INT_MAPPER),
("OBJECT_SYSTEMD_CGROUP", STR_MAPPER),
("OBJECT_SYSTEMD_SESSION", STR_MAPPER),
("OBJECT_SYSTEMD_OWNER_UID", INT_MAPPER),
("OBJECT_SYSTEMD_UNIT", STR_MAPPER),
("OBJECT_SYSTEMD_USER_UNIT", STR_MAPPER),
("__CURSOR", STR_MAPPER),
("__REALTIME_TIMESTAMP", DATE_MAPPER),
("__MONOTONIC_TIMESTAMP", DATE_MAPPER),
]
.iter()
.map(|(s, m)| (s.to_string(), m.to_owned())),
);
map
}