use log::LogLevel;
use std::io;
use std::net::{
ToSocketAddrs,
SocketAddr,
UdpSocket
};
use types::{
MetricResult,
ErrorKind
};
pub trait MetricSink {
fn emit(&self, metric: &str) -> io::Result<usize>;
}
pub struct UdpMetricSink {
sink_addr: SocketAddr,
socket: UdpSocket
}
impl UdpMetricSink {
pub fn new<A>(sink_addr: A, socket: UdpSocket) -> MetricResult<UdpMetricSink>
where A: ToSocketAddrs {
let mut addr_iter = try!(sink_addr.to_socket_addrs());
let addr = try!(addr_iter.next().ok_or(
(ErrorKind::InvalidInput, "No socket addresses yielded")
));
Ok(UdpMetricSink{sink_addr: addr, socket: socket})
}
}
impl MetricSink for UdpMetricSink {
fn emit(&self, metric: &str) -> io::Result<usize> {
self.socket.send_to(metric.as_bytes(), &self.sink_addr)
}
}
pub struct NopMetricSink;
impl MetricSink for NopMetricSink {
#[allow(unused_variables)]
fn emit(&self, metric: &str) -> io::Result<usize> {
Ok(0)
}
}
pub struct ConsoleMetricSink;
impl MetricSink for ConsoleMetricSink {
fn emit(&self, metric: &str) -> io::Result<usize> {
println!("{}", metric);
Ok(metric.len())
}
}
pub struct LoggingMetricSink {
level: LogLevel
}
impl LoggingMetricSink {
pub fn new(level: LogLevel) -> LoggingMetricSink {
LoggingMetricSink{level: level}
}
}
impl MetricSink for LoggingMetricSink {
fn emit(&self, metric: &str) -> io::Result<usize> {
log!(target: "cadence::metrics", self.level, "{}", metric);
Ok(metric.len())
}
}
#[cfg(test)]
mod tests {
use log::LogLevel;
use std::net::UdpSocket;
use super::{
MetricSink,
NopMetricSink,
ConsoleMetricSink,
LoggingMetricSink,
UdpMetricSink
};
#[test]
fn test_nop_metric_sink() {
let sink = NopMetricSink;
assert_eq!(0, sink.emit("baz:4|c").unwrap());
}
#[test]
fn test_console_metric_sink() {
let sink = ConsoleMetricSink;
assert_eq!(7, sink.emit("foo:2|t").unwrap());
}
#[test]
fn test_logging_metric_sink() {
let sink = LoggingMetricSink::new(LogLevel::Info);
assert_eq!(7, sink.emit("bar:1|g").unwrap());
}
#[test]
fn test_udp_metric_sink() {
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
let sink = UdpMetricSink::new("127.0.0.1:8125", socket).unwrap();
assert_eq!(7, sink.emit("buz:1|m").unwrap());
}
}