refactor(metrics): encapsulate metric dispatch with MetricsSender

This commit is contained in:
Nils Andreas Svee committed 2026-04-13 18:57:50 +07:00
1 parent b930a01fd6
commit 451d42640b
2 files changed
+58 -22

No files matched your search

+2 -3
View File
@@ -14,13 +14,12 @@ mod time;
mod util; mod util;
use crate::baseliner::{Baseliner, ReflectorStats}; use crate::baseliner::{Baseliner, ReflectorStats};
use crate::metrics::{Metric, Metrics}; use crate::metrics::{Metric, Metrics, MetricsSender};
use crate::time::Time;
use ::log::{debug, info}; use ::log::{debug, info};
use rustix::time::ClockId;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::IpAddr; use std::net::IpAddr;
use std::str::FromStr; use std::str::FromStr;
use std::sync::atomic::AtomicU64;
use std::sync::mpsc::{channel, sync_channel}; use std::sync::mpsc::{channel, sync_channel};
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use std::thread::sleep; use std::thread::sleep;
+56 -19
View File
@@ -1,10 +1,13 @@
use log::{error, info, warn};
use crate::Config;
use crate::config::{MeasurementType, ObservabilityProtocol}; use crate::config::{MeasurementType, ObservabilityProtocol};
use crate::time::Time;
use crate::Config;
use log::{error, info, warn};
use rustix::time::ClockId;
use std::fmt::Write; use std::fmt::Write;
use std::net::{IpAddr, TcpStream, UdpSocket}; use std::net::{IpAddr, TcpStream, UdpSocket};
use std::sync::mpsc::{Receiver, RecvTimeoutError}; use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::mpsc::{Receiver, RecvTimeoutError, SyncSender};
use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
const MAX_RECONNECT_BACKOFF: u64 = 60; const MAX_RECONNECT_BACKOFF: u64 = 60;
@@ -90,7 +93,6 @@ pub enum Metric {
rtt: f64, rtt: f64,
up_time: f64, up_time: f64,
down_time: f64, down_time: f64,
timestamp_ns: u64,
}, },
Rate { Rate {
dl_rate: f64, dl_rate: f64,
@@ -99,7 +101,6 @@ pub enum Metric {
tx_load: f64, tx_load: f64,
delta_delay_down: f64, delta_delay_down: f64,
delta_delay_up: f64, delta_delay_up: f64,
timestamp_ns: u64,
}, },
Baseline { Baseline {
reflector: IpAddr, reflector: IpAddr,
@@ -107,19 +108,52 @@ pub enum Metric {
baseline_down_ewma: f64, baseline_down_ewma: f64,
recent_up_ewma: f64, recent_up_ewma: f64,
recent_down_ewma: f64, recent_down_ewma: f64,
timestamp_ns: u64,
}, },
Event { Event {
name: &'static str, name: &'static str,
reason: &'static str, reason: &'static str,
reflector: Option<IpAddr>, reflector: Option<IpAddr>,
timestamp_ns: u64,
}, },
Dropped {
count: u64,
},
}
#[derive(Clone)]
pub struct MetricsSender {
tx: Option<SyncSender<(Metric, u64)>>,
dropped: Arc<AtomicU64>,
}
impl MetricsSender {
pub fn new(tx: SyncSender<(Metric, u64)>, dropped: Arc<AtomicU64>) -> Self {
Self {
tx: Some(tx),
dropped,
}
}
pub fn disabled() -> Self {
Self {
tx: None,
dropped: Arc::new(AtomicU64::new(0)),
}
}
pub fn send(&self, metric: Metric) {
if let Some(ref tx) = self.tx {
let ts = Time::new(ClockId::Realtime).as_nanos();
if tx.try_send((metric, ts)).is_err() {
self.dropped.fetch_add(1, Ordering::Relaxed);
}
}
}
} }
pub struct Metrics { pub struct Metrics {
pub config: Config, pub config: Config,
pub metrics_rx: Receiver<Metric>, pub metrics_dropped: Arc<AtomicU64>,
pub metrics_rx: Receiver<(Metric, u64)>,
} }
impl Metrics { impl Metrics {
@@ -184,7 +218,7 @@ impl Metrics {
Ok(()) Ok(())
} }
fn flush(&self, transport: &mut Transport, batch: &[Metric], host_tag: &str) { fn flush(&self, transport: &mut Transport, batch: &[(Metric, u64)], host_tag: &str) {
match transport { match transport {
/* /*
* the UDP receive buffer might be too small on the receiver to accept batched data, * the UDP receive buffer might be too small on the receiver to accept batched data,
@@ -192,23 +226,23 @@ impl Metrics {
*/ */
Transport::Udp(_) => { Transport::Udp(_) => {
let mut data = String::with_capacity(300); let mut data = String::with_capacity(300);
for metric in batch { for (metric, timestamp_ns) in batch {
data.clear(); data.clear();
self.write_lines(metric, host_tag, &mut data); self.write_lines(metric, *timestamp_ns, host_tag, &mut data);
transport.send(&data); transport.send(&data);
} }
} }
Transport::Tcp { .. } => { Transport::Tcp { .. } => {
let mut data = String::with_capacity(batch.len() * 300); let mut data = String::with_capacity(batch.len() * 300);
for metric in batch { for (metric, timestamp_ns) in batch {
self.write_lines(metric, host_tag, &mut data); self.write_lines(metric, *timestamp_ns, host_tag, &mut data);
} }
transport.send(&data); transport.send(&data);
} }
} }
} }
fn write_lines(&self, metric: &Metric, host_tag: &str, out: &mut String) { fn write_lines(&self, metric: &Metric, timestamp_ns: u64, host_tag: &str, out: &mut String) {
match metric { match metric {
Metric::Ping { Metric::Ping {
reflector, reflector,
@@ -216,7 +250,6 @@ impl Metrics {
rtt, rtt,
up_time, up_time,
down_time, down_time,
timestamp_ns,
} => { } => {
writeln!( writeln!(
out, out,
@@ -232,7 +265,6 @@ impl Metrics {
tx_load, tx_load,
delta_delay_down, delta_delay_down,
delta_delay_up, delta_delay_up,
timestamp_ns,
} => { } => {
writeln!(out, writeln!(out,
"sqm_rate,host={host_tag},direction=download \ "sqm_rate,host={host_tag},direction=download \
@@ -249,7 +281,6 @@ impl Metrics {
baseline_down_ewma, baseline_down_ewma,
recent_up_ewma, recent_up_ewma,
recent_down_ewma, recent_down_ewma,
timestamp_ns,
} => { } => {
writeln!(out, writeln!(out,
"sqm_baseline,host={host_tag},reflector={reflector},direction=up \ "sqm_baseline,host={host_tag},reflector={reflector},direction=up \
@@ -264,7 +295,6 @@ impl Metrics {
name, name,
reason, reason,
reflector, reflector,
timestamp_ns,
} => { } => {
let mut tags = format!("host={host_tag},type={name}"); let mut tags = format!("host={host_tag},type={name}");
@@ -277,6 +307,13 @@ impl Metrics {
} }
writeln!(out, "sqm_event,{tags} count=1i {timestamp_ns}").unwrap_or(()); writeln!(out, "sqm_event,{tags} count=1i {timestamp_ns}").unwrap_or(());
} }
Metric::Dropped { count } => {
writeln!(
out,
"sqm_metrics_dropped,host={host_tag} count={count}i {timestamp_ns}"
)
.unwrap_or(());
}
} }
} }
} }