use crate::anomaly::Severity;
use crate::anomaly::sink::AnomalyWriter;
use crate::correlate::TimeBucketedCounter;
use crate::ctx::Ctx;
pub trait Report: Send + 'static {
const NAME: &'static str;
}
pub trait ReportSink<R: Report>: Send + 'static {
fn record(&mut self, report: &R);
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
pub struct ReportSnapshot<'a, 'c> {
pub(crate) ctx: &'a mut Ctx<'c>,
pub(crate) now: flowscope::Timestamp,
}
impl ReportSnapshot<'_, '_> {
pub fn now(&self) -> flowscope::Timestamp {
self.now
}
#[cfg(feature = "flow")]
pub fn bandwidth(&self) -> Option<crate::monitor::BandwidthReport<'_>> {
self.ctx.bandwidth()
}
pub fn state<T: 'static>(&self) -> Option<&T> {
self.ctx.state::<T>()
}
pub fn counter<K>(&self) -> Option<&TimeBucketedCounter<K>>
where
K: std::hash::Hash + Eq + Clone + Send + 'static,
{
self.ctx.counter::<K>()
}
pub fn emit(&mut self, kind: &'static str, severity: Severity) -> AnomalyWriter<'_> {
self.ctx.emit(kind, severity)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct StdoutReportSink;
impl<R: Report + std::fmt::Debug> ReportSink<R> for StdoutReportSink {
fn record(&mut self, report: &R) {
println!("[{}] {report:?}", R::NAME);
}
}
#[cfg(feature = "serde")]
#[derive(Debug, Default, Clone, Copy)]
pub struct JsonReportSink;
#[cfg(feature = "serde")]
impl<R: Report + serde::Serialize> ReportSink<R> for JsonReportSink {
fn record(&mut self, report: &R) {
match serde_json::to_string(report) {
Ok(line) => println!("{line}"),
Err(e) => eprintln!("JsonReportSink: serialize failed: {e}"),
}
}
}