From 7922987b760985479946518e4c11cf6014371133 Mon Sep 17 00:00:00 2001 From: Sebastian Rollen Date: Thu, 17 Jun 2021 11:55:35 -0400 Subject: [PATCH] nicer api --- Cargo.toml | 2 +- src/client.rs | 11 ++--- src/lib.rs | 2 + src/metric.rs | 118 +++++++++++++++++++++----------------------------- src/tag.rs | 32 ++++++++++++++ 5 files changed, 87 insertions(+), 78 deletions(-) create mode 100644 src/tag.rs diff --git a/Cargo.toml b/Cargo.toml index b4b6a52..0ba81e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dogstatsd" -version = "0.1.0" +version = "0.2.0" authors = ["Sebastian Rollen "] edition = "2018" diff --git a/src/client.rs b/src/client.rs index dd7f1cf..dc0f935 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,4 @@ -use crate::metric::Metric; +use crate::Metric; use std::io::Error; use tokio::net::{ToSocketAddrs, UdpSocket}; @@ -16,11 +16,7 @@ impl Client { Ok(Self { socket }) } - pub async fn send(&self, metric: Metric<'_, I, T>) -> Result<(), Error> - where - I: IntoIterator, - T: AsRef, - { + pub async fn send<'a>(&self, metric: Metric<'a>) -> Result<(), Error> { let bytes = metric.into_bytes(); self.socket.send(&bytes).await?; Ok(()) @@ -34,11 +30,10 @@ mod test { #[tokio::test] async fn test_client() { let udp_receiver = UdpSocket::bind("127.0.0.1:8125").await.unwrap(); - let v: &[&str] = &[]; let client = Client::new("127.0.0.1:1234", "127.0.0.1:8125") .await .unwrap(); - client.send(Metric::increase("test", v)).await.unwrap(); + client.send(Metric::increase("test")).await.unwrap(); udp_receiver.connect("127.0.0.1:1234").await.unwrap(); let mut bytes_received: usize = 0; let mut buf = [0; 8]; diff --git a/src/lib.rs b/src/lib.rs index e086fa3..44357cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ mod client; mod metric; +mod tag; pub use client::Client; pub use metric::Metric; +pub use tag::Tag; diff --git a/src/metric.rs b/src/metric.rs index 009ba63..81d6949 100644 --- a/src/metric.rs +++ b/src/metric.rs @@ -1,3 +1,4 @@ +use crate::Tag; use bytes::{Bytes, BytesMut}; enum Type<'a> { @@ -10,75 +11,52 @@ enum Type<'a> { Set(&'a str), } -pub struct Metric<'a, I, T> -where - I: IntoIterator, - T: AsRef, -{ +pub struct Metric<'a> { frame_type: Type<'a>, message: &'a str, - tags: I, + tags: Vec>, } -impl<'a, I, T> Metric<'a, I, T> -where - I: IntoIterator, - T: AsRef, -{ - pub fn increase(message: &'a str, tags: I) -> Self { +impl<'a> Metric<'a> { + fn new(frame_type: Type<'a>, message: &'a str) -> Self { Self { - frame_type: Type::Increase, + frame_type, message, - tags, + tags: vec![], } } - pub fn decrease(message: &'a str, tags: I) -> Self { - Self { - frame_type: Type::Decrease, - message, - tags, - } + pub fn increase(message: &'a str) -> Self { + Self::new(Type::Increase, message) } - pub fn count(count: isize, message: &'a str, tags: I) -> Self { - Self { - frame_type: Type::Count(count), - message, - tags, - } + pub fn decrease(message: &'a str) -> Self { + Self::new(Type::Decrease, message) } - pub fn gauge(value: &'a str, message: &'a str, tags: I) -> Self { - Self { - frame_type: Type::Gauge(value), - message, - tags, - } + pub fn count(count: isize, message: &'a str) -> Self { + Self::new(Type::Count(count), message) } - pub fn histogram(value: &'a str, message: &'a str, tags: I) -> Self { - Self { - frame_type: Type::Histogram(value), - message, - tags, - } + pub fn gauge(value: &'a str, message: &'a str) -> Self { + Self::new(Type::Gauge(value), message) } - pub fn distribution(value: &'a str, message: &'a str, tags: I) -> Self { - Self { - frame_type: Type::Distribution(value), - message, - tags, - } + pub fn histogram(value: &'a str, message: &'a str) -> Self { + Self::new(Type::Histogram(value), message) } - pub fn set(value: &'a str, message: &'a str, tags: I) -> Self { - Self { - frame_type: Type::Set(value), - message, - tags, - } + pub fn distribution(value: &'a str, message: &'a str) -> Self { + Self::new(Type::Distribution(value), message) + } + + pub fn set(value: &'a str, message: &'a str) -> Self { + Self::new(Type::Set(value), message) + } + + pub fn add_tag>>(mut self, tag: T) -> Self { + self.tags.push(tag.into()); + self } pub(crate) fn into_bytes(self) -> Bytes { @@ -138,7 +116,17 @@ where } while next_tag.is_some() { - buf.extend_from_slice(next_tag.unwrap().as_ref().as_bytes()); + let tag = next_tag.unwrap().into(); + match tag { + Tag::Single(value) => { + buf.extend_from_slice(value.as_bytes()); + } + Tag::KeyValue(key, value) => { + buf.extend_from_slice(key.as_bytes()); + buf.extend_from_slice(b":"); + buf.extend_from_slice(value.as_bytes()); + } + } next_tag = tags_iter.next(); if next_tag.is_some() { @@ -156,37 +144,29 @@ mod test { #[test] fn test_into_bytes() { - let v: &[&str] = &[]; - assert_eq!( - Metric::increase("test", v).into_bytes().as_ref(), - b"test:1|c" - ); - assert_eq!( - Metric::decrease("test", v).into_bytes().as_ref(), - b"test:-1|c" - ); - assert_eq!( - Metric::count(2, "test", v).into_bytes().as_ref(), - b"test:2|c" - ); + assert_eq!(Metric::increase("test").into_bytes().as_ref(), b"test:1|c"); + assert_eq!(Metric::decrease("test").into_bytes().as_ref(), b"test:-1|c"); + assert_eq!(Metric::count(2, "test").into_bytes().as_ref(), b"test:2|c"); assert_eq!( - Metric::gauge("1.2", "test", v).into_bytes().as_ref(), + Metric::gauge("1.2", "test").into_bytes().as_ref(), b"test:1.2|g" ); assert_eq!( - Metric::histogram("1.2", "test", v).into_bytes().as_ref(), + Metric::histogram("1.2", "test").into_bytes().as_ref(), b"test:1.2|h" ); assert_eq!( - Metric::distribution("1.2", "test", v).into_bytes().as_ref(), + Metric::distribution("1.2", "test").into_bytes().as_ref(), b"test:1.2|d" ); assert_eq!( - Metric::set("1.2", "test", v).into_bytes().as_ref(), + Metric::set("1.2", "test").into_bytes().as_ref(), b"test:1.2|s" ); assert_eq!( - Metric::increase("test", &["a:b", "c"]) + Metric::increase("test") + .add_tag(("a", "b")) + .add_tag("c") .into_bytes() .as_ref(), b"test:1|c|#a:b,c" diff --git a/src/tag.rs b/src/tag.rs new file mode 100644 index 0000000..8f52a12 --- /dev/null +++ b/src/tag.rs @@ -0,0 +1,32 @@ +use std::borrow::Cow; + +pub enum Tag<'a> { + Single(Cow<'a, str>), + KeyValue(Cow<'a, str>, Cow<'a, str>), +} + +impl<'a> From<&'a str> for Tag<'a> { + fn from(s: &'a str) -> Tag<'a> { + Tag::Single(Cow::Borrowed(s)) + } +} + +impl<'a> From<(&'a str, &'a str)> for Tag<'a> { + fn from(s: (&'a str, &'a str)) -> Tag<'a> { + Tag::KeyValue(Cow::Borrowed(s.0), Cow::Borrowed(s.1)) + } +} + +impl<'a> Into> for Tag<'a> { + fn into(self) -> Cow<'a, str> { + match self { + Tag::Single(single) => single, + Tag::KeyValue(key, value) => { + let mut out = key.to_string(); + out.push(':'); + out.push_str(value.as_ref()); + Cow::Owned(out) + } + } + } +}