79 lines
1.9 KiB
Rust
79 lines
1.9 KiB
Rust
use std::process::Command;
|
|
|
|
use log::{Level, Log, Metadata, Record};
|
|
use reqwest::blocking;
|
|
|
|
mod message;
|
|
pub use message::{LogMsg, Severity};
|
|
|
|
pub struct SnitchLogger<L: Log> {
|
|
wrapped: L,
|
|
url: String,
|
|
service_name: String,
|
|
hostname: String,
|
|
}
|
|
|
|
impl<L: Log> SnitchLogger<L> {
|
|
pub fn new(wrapped: L, url: impl Into<String>, service_name: impl Into<String>) -> Self {
|
|
SnitchLogger {
|
|
wrapped,
|
|
url: url.into(),
|
|
service_name: service_name.into(),
|
|
hostname: probe_hostname(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<L: Log> Log for SnitchLogger<L> {
|
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
|
self.wrapped.enabled(metadata) || metadata.level() <= Level::Warn
|
|
}
|
|
|
|
fn log(&self, record: &Record) {
|
|
self.wrapped.log(record);
|
|
|
|
let severity = match record.metadata().level() {
|
|
Level::Error => Severity::Error,
|
|
Level::Warn => Severity::Warning,
|
|
_ => return,
|
|
};
|
|
|
|
let record = LogMsg {
|
|
severity,
|
|
file: record.file().map(String::from),
|
|
line: record.line(),
|
|
..LogMsg::new(
|
|
self.service_name.clone(),
|
|
record.args().to_string(),
|
|
self.hostname.clone(),
|
|
)
|
|
};
|
|
|
|
let client = blocking::Client::new();
|
|
if let Err(e) = client.post(&self.url).json(&record).send() {
|
|
// TODO: log error (without sending it)
|
|
eprintln!("failed to send log record: {e:?}");
|
|
}
|
|
}
|
|
|
|
fn flush(&self) {
|
|
self.wrapped.flush();
|
|
}
|
|
}
|
|
|
|
pub fn probe_hostname() -> String {
|
|
let output = Command::new("uname").arg("-n").output().ok();
|
|
|
|
output
|
|
.as_ref()
|
|
.and_then(|output| std::str::from_utf8(&output.stdout).ok())
|
|
.unwrap_or("<unknown_hostname>")
|
|
.to_string()
|
|
}
|
|
|
|
impl<L: Log> Drop for SnitchLogger<L> {
|
|
fn drop(&mut self) {
|
|
self.flush();
|
|
}
|
|
}
|