Fixed statsd support

This commit is contained in:
Dennis Schwerdel 2020-05-30 16:12:54 +02:00
parent 1f94d0deff
commit cac5af890b
6 changed files with 98 additions and 39 deletions

View File

@ -28,7 +28,7 @@ use super::{
traffic::TrafficStats, traffic::TrafficStats,
types::{Error, HeaderMagic, NodeId, Protocol, Range, Table}, types::{Error, HeaderMagic, NodeId, Protocol, Range, Table},
udpmessage::{decode, encode, Message}, udpmessage::{decode, encode, Message},
util::{addr_nice, resolve, CtrlC, Duration, Time, TimeSource} util::{addr_nice, resolve, CtrlC, Duration, StatsdMsg, Time, TimeSource}
}; };
pub type Hash = BuildHasherDefault<FnvHasher>; pub type Hash = BuildHasherDefault<FnvHasher>;
@ -600,35 +600,43 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
let peer_traffic = self.traffic.total_peer_traffic(); let peer_traffic = self.traffic.total_peer_traffic();
let payload_traffic = self.traffic.total_payload_traffic(); let payload_traffic = self.traffic.total_payload_traffic();
let dropped = &self.traffic.dropped; let dropped = &self.traffic.dropped;
let msg = format!( let prefix = self.config.statsd_prefix.as_ref().map(|s| s as &str).unwrap_or("vpncloud");
"peer_count:{}|g\ntable_entries:{}|g\n\ let msg = StatsdMsg::new()
traffic.protocol.inbound.bytes:{}\n\ .with_ns(prefix, |msg| {
traffic.protocol.inbound.packets:{}\n\ msg.add("peer_count", self.peers.len(), "g");
traffic.protocol.outbound.bytes:{}\n\ msg.add("table_entries", self.table.len(), "g");
traffic.protocol.outbound.packets:{}\n\ msg.with_ns("traffic", |msg| {
traffic.payload.inbound.bytes:{}\n\ msg.with_ns("protocol", |msg| {
traffic.payload.inbound.packets:{}\n\ msg.with_ns("inbound", |msg| {
traffic.payload.outbound.bytes:{}\n\ msg.add("bytes", peer_traffic.in_bytes, "c");
traffic.payload.outbound.packets:{}\n\ msg.add("packets", peer_traffic.in_packets, "c");
invalid_protocol_traffic.bytes:{}\n\ });
invalid_protocol_traffic.packets:{}\n\ msg.with_ns("outbound", |msg| {
dropped_payload.bytes:{}\n\ msg.add("bytes", peer_traffic.out_bytes, "c");
dropped_payload.packets:{}", msg.add("packets", peer_traffic.out_packets, "c");
self.peers.len(), });
self.table.len(), });
peer_traffic.in_bytes, msg.with_ns("payload", |msg| {
peer_traffic.in_packets, msg.with_ns("inbound", |msg| {
peer_traffic.out_bytes, msg.add("bytes", payload_traffic.in_bytes, "c");
peer_traffic.out_packets, msg.add("packets", payload_traffic.in_packets, "c");
payload_traffic.in_bytes, });
payload_traffic.in_packets, msg.with_ns("outbound", |msg| {
payload_traffic.out_bytes, msg.add("bytes", payload_traffic.out_bytes, "c");
payload_traffic.out_packets, msg.add("packets", payload_traffic.out_packets, "c");
dropped.in_bytes, });
dropped.in_packets, });
dropped.out_bytes, });
dropped.out_packets msg.with_ns("invalid_protocol_traffic", |msg| {
); msg.add("bytes", dropped.in_bytes, "c");
msg.add("packets", dropped.in_packets, "c");
});
msg.with_ns("dropped_payload", |msg| {
msg.add("bytes", dropped.out_bytes, "c");
msg.add("packets", dropped.out_packets, "c");
});
})
.build();
let msg_data = msg.as_bytes(); let msg_data = msg.as_bytes();
let addrs = resolve(endpoint)?; let addrs = resolve(endpoint)?;
if let Some(addr) = addrs.first() { if let Some(addr) = addrs.first() {

View File

@ -59,6 +59,7 @@ pub struct Config {
pub pid_file: Option<String>, pub pid_file: Option<String>,
pub stats_file: Option<String>, pub stats_file: Option<String>,
pub statsd_server: Option<String>, pub statsd_server: Option<String>,
pub statsd_prefix: Option<String>,
pub user: Option<String>, pub user: Option<String>,
pub group: Option<String> pub group: Option<String>
} }
@ -89,6 +90,7 @@ impl Default for Config {
pid_file: None, pid_file: None,
stats_file: None, stats_file: None,
statsd_server: None, statsd_server: None,
statsd_prefix: None,
user: None, user: None,
group: None group: None
} }
@ -168,6 +170,9 @@ impl Config {
if let Some(val) = file.statsd_server { if let Some(val) = file.statsd_server {
self.statsd_server = Some(val); self.statsd_server = Some(val);
} }
if let Some(val) = file.statsd_prefix {
self.statsd_prefix = Some(val);
}
if let Some(val) = file.user { if let Some(val) = file.user {
self.user = Some(val); self.user = Some(val);
} }
@ -246,6 +251,9 @@ impl Config {
if let Some(val) = args.statsd_server { if let Some(val) = args.statsd_server {
self.statsd_server = Some(val); self.statsd_server = Some(val);
} }
if let Some(val) = args.statsd_prefix {
self.statsd_prefix = Some(val);
}
if let Some(val) = args.user { if let Some(val) = args.user {
self.user = Some(val); self.user = Some(val);
} }
@ -307,6 +315,7 @@ pub struct ConfigFile {
pub pid_file: Option<String>, pub pid_file: Option<String>,
pub stats_file: Option<String>, pub stats_file: Option<String>,
pub statsd_server: Option<String>, pub statsd_server: Option<String>,
pub statsd_prefix: Option<String>,
pub user: Option<String>, pub user: Option<String>,
pub group: Option<String> pub group: Option<String>
} }
@ -342,6 +351,7 @@ group: nogroup
pid_file: /run/vpncloud.run pid_file: /run/vpncloud.run
stats_file: /var/log/vpncloud.stats stats_file: /var/log/vpncloud.stats
statsd_server: example.com:1234 statsd_server: example.com:1234
statsd_prefix: prefix
"; ";
assert_eq!(serde_yaml::from_str::<ConfigFile>(config_file).unwrap(), ConfigFile { assert_eq!(serde_yaml::from_str::<ConfigFile>(config_file).unwrap(), ConfigFile {
device_type: Some(Type::Tun), device_type: Some(Type::Tun),
@ -368,7 +378,8 @@ statsd_server: example.com:1234
group: Some("nogroup".to_string()), group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()), pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()), stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd_server: Some("example.com:1234".to_string()) statsd_server: Some("example.com:1234".to_string()),
statsd_prefix: Some("prefix".to_string())
}) })
} }
@ -400,7 +411,8 @@ fn config_merge() {
group: Some("nogroup".to_string()), group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()), pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()), stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd_server: Some("example.com:1234".to_string()) statsd_server: Some("example.com:1234".to_string()),
statsd_prefix: Some("prefix".to_string())
}); });
assert_eq!(config, Config { assert_eq!(config, Config {
device_type: Type::Tun, device_type: Type::Tun,
@ -427,6 +439,7 @@ fn config_merge() {
pid_file: Some("/run/vpncloud.run".to_string()), pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()), stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd_server: Some("example.com:1234".to_string()), statsd_server: Some("example.com:1234".to_string()),
statsd_prefix: Some("prefix".to_string()),
..Default::default() ..Default::default()
}); });
config.merge_args(Args { config.merge_args(Args {
@ -453,6 +466,7 @@ fn config_merge() {
pid_file: Some("/run/vpncloud-mynet.run".to_string()), pid_file: Some("/run/vpncloud-mynet.run".to_string()),
stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()), stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
statsd_server: Some("example.com:2345".to_string()), statsd_server: Some("example.com:2345".to_string()),
statsd_prefix: Some("prefix2".to_string()),
user: Some("root".to_string()), user: Some("root".to_string()),
group: Some("root".to_string()), group: Some("root".to_string()),
..Default::default() ..Default::default()
@ -486,6 +500,7 @@ fn config_merge() {
pid_file: Some("/run/vpncloud-mynet.run".to_string()), pid_file: Some("/run/vpncloud-mynet.run".to_string()),
stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()), stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
statsd_server: Some("example.com:2345".to_string()), statsd_server: Some("example.com:2345".to_string()),
statsd_prefix: Some("prefix2".to_string()),
daemonize: true daemonize: true
}); });
} }

View File

@ -173,6 +173,10 @@ pub struct Args {
#[structopt(long)] #[structopt(long)]
statsd_server: Option<String>, statsd_server: Option<String>,
/// Use the given prefix for statsd records
#[structopt(long)]
statsd_prefix: Option<String>,
/// Run as other user /// Run as other user
#[structopt(long)] #[structopt(long)]
user: Option<String>, user: Option<String>,

View File

@ -10,7 +10,7 @@ use std::{
}; };
use super::{ use super::{
cloud::Hash, cloud::{Hash, STATS_INTERVAL},
types::Address, types::Address,
util::{addr_nice, Bytes} util::{addr_nice, Bytes}
}; };
@ -157,10 +157,10 @@ impl TrafficStats {
out, out,
" - peer: \"{}\"\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}", " - peer: \"{}\"\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
addr_nice(**addr), addr_nice(**addr),
Bytes(data.in_bytes / 60), Bytes(data.in_bytes / STATS_INTERVAL as u64),
data.in_bytes, data.in_bytes,
data.in_packets, data.in_packets,
Bytes(data.out_bytes / 60), Bytes(data.out_bytes / STATS_INTERVAL as u64),
data.out_bytes, data.out_bytes,
data.out_packets data.out_packets
)?; )?;
@ -175,10 +175,10 @@ impl TrafficStats {
" - addrs: [\"{}\", \"{}\"]\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}", " - addrs: [\"{}\", \"{}\"]\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
remote, remote,
local, local,
Bytes(data.in_bytes / 60), Bytes(data.in_bytes / STATS_INTERVAL as u64),
data.in_bytes, data.in_bytes,
data.in_packets, data.in_packets,
Bytes(data.out_bytes / 60), Bytes(data.out_bytes / STATS_INTERVAL as u64),
data.out_bytes, data.out_bytes,
data.out_packets data.out_packets
)?; )?;
@ -187,14 +187,14 @@ impl TrafficStats {
writeln!( writeln!(
out, out,
"invalid_protocol_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}", "invalid_protocol_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
Bytes(self.dropped.in_bytes / 60), Bytes(self.dropped.in_bytes / STATS_INTERVAL as u64),
self.dropped.in_bytes, self.dropped.in_bytes,
self.dropped.in_packets self.dropped.in_packets
)?; )?;
writeln!( writeln!(
out, out,
"dropped_payload_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}", "dropped_payload_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
Bytes(self.dropped.out_bytes / 60), Bytes(self.dropped.out_bytes / STATS_INTERVAL as u64),
self.dropped.out_bytes, self.dropped.out_bytes,
self.dropped.out_packets self.dropped.out_packets
)?; )?;

View File

@ -228,6 +228,9 @@ pub trait Table {
fn remove(&mut self, _: &Address) -> bool; fn remove(&mut self, _: &Address) -> bool;
fn remove_all(&mut self, _: &SocketAddr); fn remove_all(&mut self, _: &SocketAddr);
fn len(&self) -> usize; fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
} }
pub trait Protocol: Sized { pub trait Protocol: Sized {

View File

@ -319,6 +319,35 @@ pub fn from_base62(data: &str) -> Result<Vec<u8>, char> {
} }
#[derive(Default)]
pub struct StatsdMsg {
entries: Vec<String>,
key: Vec<String>
}
impl StatsdMsg {
pub fn new() -> Self {
Default::default()
}
pub fn add<T: fmt::Display>(&mut self, key: &str, val: T, type_: &str) -> &mut Self {
self.entries.push(format!("{}.{}:{}|{}", self.key.join("."), key, val, type_));
self
}
pub fn with_ns<F: FnOnce(&mut Self)>(&mut self, ns: &str, f: F) -> &mut Self {
self.key.push(ns.to_string());
f(self);
self.key.pop();
self
}
pub fn build(&self) -> String {
self.entries.join("\n")
}
}
#[test] #[test]
fn base62() { fn base62() {
assert_eq!("", to_base62(&[0])); assert_eq!("", to_base62(&[0]));