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,
types::{Error, HeaderMagic, NodeId, Protocol, Range, Table},
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>;
@ -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 payload_traffic = self.traffic.total_payload_traffic();
let dropped = &self.traffic.dropped;
let msg = format!(
"peer_count:{}|g\ntable_entries:{}|g\n\
traffic.protocol.inbound.bytes:{}\n\
traffic.protocol.inbound.packets:{}\n\
traffic.protocol.outbound.bytes:{}\n\
traffic.protocol.outbound.packets:{}\n\
traffic.payload.inbound.bytes:{}\n\
traffic.payload.inbound.packets:{}\n\
traffic.payload.outbound.bytes:{}\n\
traffic.payload.outbound.packets:{}\n\
invalid_protocol_traffic.bytes:{}\n\
invalid_protocol_traffic.packets:{}\n\
dropped_payload.bytes:{}\n\
dropped_payload.packets:{}",
self.peers.len(),
self.table.len(),
peer_traffic.in_bytes,
peer_traffic.in_packets,
peer_traffic.out_bytes,
peer_traffic.out_packets,
payload_traffic.in_bytes,
payload_traffic.in_packets,
payload_traffic.out_bytes,
payload_traffic.out_packets,
dropped.in_bytes,
dropped.in_packets,
dropped.out_bytes,
dropped.out_packets
);
let prefix = self.config.statsd_prefix.as_ref().map(|s| s as &str).unwrap_or("vpncloud");
let msg = StatsdMsg::new()
.with_ns(prefix, |msg| {
msg.add("peer_count", self.peers.len(), "g");
msg.add("table_entries", self.table.len(), "g");
msg.with_ns("traffic", |msg| {
msg.with_ns("protocol", |msg| {
msg.with_ns("inbound", |msg| {
msg.add("bytes", peer_traffic.in_bytes, "c");
msg.add("packets", peer_traffic.in_packets, "c");
});
msg.with_ns("outbound", |msg| {
msg.add("bytes", peer_traffic.out_bytes, "c");
msg.add("packets", peer_traffic.out_packets, "c");
});
});
msg.with_ns("payload", |msg| {
msg.with_ns("inbound", |msg| {
msg.add("bytes", payload_traffic.in_bytes, "c");
msg.add("packets", payload_traffic.in_packets, "c");
});
msg.with_ns("outbound", |msg| {
msg.add("bytes", payload_traffic.out_bytes, "c");
msg.add("packets", payload_traffic.out_packets, "c");
});
});
});
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 addrs = resolve(endpoint)?;
if let Some(addr) = addrs.first() {

View File

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

View File

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

View File

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

View File

@ -228,6 +228,9 @@ pub trait Table {
fn remove(&mut self, _: &Address) -> bool;
fn remove_all(&mut self, _: &SocketAddr);
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
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]
fn base62() {
assert_eq!("", to_base62(&[0]));