use std::collections::BTreeMap;
use chrono::{TimeZone, Utc};
use fakecloud_core::delivery::CloudwatchDelivery;
use crate::state::{MetricDatum, SharedCloudWatchState};
pub struct CloudwatchDeliveryImpl {
state: SharedCloudWatchState,
}
impl CloudwatchDeliveryImpl {
pub fn new(state: SharedCloudWatchState) -> Self {
Self { state }
}
}
impl CloudwatchDelivery for CloudwatchDeliveryImpl {
fn put_metric(
&self,
account_id: &str,
region: &str,
namespace: &str,
metric_name: &str,
value: f64,
unit: Option<&str>,
dimensions: BTreeMap<String, String>,
timestamp_ms: i64,
) {
let timestamp = Utc
.timestamp_millis_opt(timestamp_ms)
.single()
.unwrap_or_else(Utc::now);
let mut state = self.state.write();
let acct = state.get_or_create(account_id);
let metrics_map = acct.metrics_in_mut(region);
let bucket = metrics_map.entry(namespace.to_string()).or_default();
bucket.push(MetricDatum {
metric_name: metric_name.to_string(),
dimensions,
timestamp,
value: Some(value),
statistic_values: None,
unit: unit.map(|s| s.to_string()),
storage_resolution: None,
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::state::CloudWatchAccounts;
use parking_lot::RwLock;
use std::sync::Arc;
#[test]
fn put_metric_appends_datum_to_namespace() {
let state: SharedCloudWatchState = Arc::new(RwLock::new(CloudWatchAccounts::new()));
let delivery = CloudwatchDeliveryImpl::new(state.clone());
delivery.put_metric(
"123456789012",
"us-east-1",
"MyApp",
"ErrorCount",
1.0,
None,
BTreeMap::new(),
1_700_000_000_000,
);
let guard = state.read();
let acct = guard.get("123456789012").unwrap();
let metrics = acct.metrics_in("us-east-1").unwrap();
let bucket = metrics.get("MyApp").unwrap();
assert_eq!(bucket.len(), 1);
assert_eq!(bucket[0].metric_name, "ErrorCount");
assert_eq!(bucket[0].value, Some(1.0));
}
}