use crate::context::ResourceContext;
use crate::plugin::metrics::reporting::{MetricReport, MetricSnapshot};
use crate::plugin::metrics::types::{MetricDefinition, MetricId, MetricValue};
use async_trait::async_trait;
#[async_trait]
pub trait MetricsHook: Send + Sync {
async fn on_metric_defined(
&self,
_definition: &MetricDefinition,
_resources: &mut ResourceContext,
) {
}
async fn on_metric_recorded(&self, _value: &MetricValue, _resources: &mut ResourceContext) {
}
async fn on_snapshot_created(
&self,
_snapshot: &MetricSnapshot,
_resources: &mut ResourceContext,
) {
}
async fn on_report_generated(&self, _report: &MetricReport, _resources: &mut ResourceContext) {
}
async fn on_metric_removed(&self, _metric_id: &MetricId, _resources: &mut ResourceContext) {
}
async fn on_registry_cleared(&self, _resources: &mut ResourceContext) {
}
}
pub struct NoOpMetricsHook;
#[async_trait]
impl MetricsHook for NoOpMetricsHook {}
#[cfg(test)]
mod tests {
use super::*;
use crate::plugin::metrics::types::MetricType;
use std::sync::Arc;
use tokio::sync::Mutex;
#[derive(Clone)]
struct TestHook {
recorded_values: Arc<Mutex<Vec<MetricValue>>>,
snapshots: Arc<Mutex<Vec<MetricSnapshot>>>,
reports: Arc<Mutex<Vec<MetricReport>>>,
}
impl TestHook {
fn new() -> Self {
Self {
recorded_values: Arc::new(Mutex::new(Vec::new())),
snapshots: Arc::new(Mutex::new(Vec::new())),
reports: Arc::new(Mutex::new(Vec::new())),
}
}
}
#[async_trait]
impl MetricsHook for TestHook {
async fn on_metric_recorded(&self, value: &MetricValue, _resources: &mut ResourceContext) {
self.recorded_values.lock().await.push(value.clone());
}
async fn on_snapshot_created(
&self,
snapshot: &MetricSnapshot,
_resources: &mut ResourceContext,
) {
self.snapshots.lock().await.push(snapshot.clone());
}
async fn on_report_generated(
&self,
report: &MetricReport,
_resources: &mut ResourceContext,
) {
self.reports.lock().await.push(report.clone());
}
}
#[tokio::test]
async fn test_noop_hook() {
let hook = NoOpMetricsHook;
let mut resources = ResourceContext::new();
let metric_id = MetricId::new("test");
let definition =
MetricDefinition::new("test", "Test", "Test metric", MetricType::Counter, "count");
let value = MetricValue::new(metric_id.clone(), 42.0, 1000);
let snapshot = MetricSnapshot::new(1000);
let report = MetricReport::new(1000, 2000);
hook.on_metric_defined(&definition, &mut resources).await;
hook.on_metric_recorded(&value, &mut resources).await;
hook.on_snapshot_created(&snapshot, &mut resources).await;
hook.on_report_generated(&report, &mut resources).await;
hook.on_metric_removed(&metric_id, &mut resources).await;
hook.on_registry_cleared(&mut resources).await;
}
#[tokio::test]
async fn test_custom_hook() {
let hook = TestHook::new();
let mut resources = ResourceContext::new();
let metric_id = MetricId::new("test");
let value = MetricValue::new(metric_id.clone(), 42.0, 1000);
let snapshot = MetricSnapshot::new(1000);
let report = MetricReport::new(1000, 2000);
hook.on_metric_recorded(&value, &mut resources).await;
hook.on_snapshot_created(&snapshot, &mut resources).await;
hook.on_report_generated(&report, &mut resources).await;
assert_eq!(hook.recorded_values.lock().await.len(), 1);
assert_eq!(hook.snapshots.lock().await.len(), 1);
assert_eq!(hook.reports.lock().await.len(), 1);
}
}