statsd-0.16.0/.cargo_vcs_info.json0000644000000001360000000000100124220ustar { "git": { "sha1": "1094ea63857f6cc14324d7f7abc926de9811737a" }, "path_in_vcs": "" }statsd-0.16.0/Cargo.lock0000644000000044570000000000100104070ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "getrandom" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "libc" version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "statsd" version = "0.16.0" dependencies = [ "itertools", "rand", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" statsd-0.16.0/Cargo.toml0000644000000015620000000000100104240ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "statsd" version = "0.16.0" authors = ["Mark Story "] include = [ "**/*.rs", "Cargo.toml", "README.md", "LICENSE.txt", ] description = "A basic statsd client for rust." homepage = "https://github.com/markstory/rust-statsd" readme = "README.md" license = "MIT" [dependencies.rand] version = "0.8" [dev-dependencies.itertools] version = "0.10" statsd-0.16.0/Cargo.toml.orig000064400000000000000000000006171046102023000141050ustar 00000000000000[package] name = "statsd" version = "0.16.0" description = "A basic statsd client for rust." homepage = "https://github.com/markstory/rust-statsd" readme = "README.md" license = "MIT" authors = ["Mark Story "] include = [ "**/*.rs", "Cargo.toml", "README.md", "LICENSE.txt", ] edition = "2018" [dependencies] rand = "0.8" [dev-dependencies] itertools = "0.10" statsd-0.16.0/LICENSE.txt000064400000000000000000000021061046102023000130340ustar 00000000000000The MIT License Copyright (c) 2015, Mark Story Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. statsd-0.16.0/README.md000064400000000000000000000043661046102023000125020ustar 00000000000000# Rust Statsd [![Build Status](https://secure.travis-ci.org/markstory/rust-statsd.png?branch=master)](http://travis-ci.org/markstory/rust-statsd) A StatsD client implementation of statsd in rust. ## Using the client library Add the `statsd` package as a dependency in your `Cargo.toml` file: ```toml [dependencies] statsd = "^0.16" ``` You need rustc >= 1.31.0 for statsd to work. You can then get a client instance and start tracking metrics: ```rust // Load the crate extern crate statsd; // Import the client object. use statsd::Client; // Get a client with the prefix of `myapp`. The host should be the // IP:port of your statsd daemon. let client = Client::new("127.0.0.1:8125", "myapp").unwrap(); ``` ## Tracking Metrics Once you've created a client, you can track timers and metrics: ```rust // Increment a counter by 1 client.incr("some.counter"); // Decrement a counter by 1 client.decr("some.counter"); // Update a gauge client.gauge("some.value", 12.0); // Modify a counter by an arbitrary float. client.count("some.counter", 511.0); // Send a histogram value as a float. client.histogram("some.histogram", 511.0); // Send a key/value. client.kv("some.data", 15.26); ``` ### Tracking Timers Timers can be updated using `timer()` and `time()`: ```rust // Update a timer based on a calculation you've done. client.timer("operation.duration", 13.4); // Time a closure client.time("operation.duration", || { // Do something expensive. }); ``` ### Pipeline Multiple metrics can be sent to StatsD once using pipeline: ```rust let mut pipe = client.pipeline(): // Increment a counter by 1 pipe.incr("some.counter"); // Decrement a counter by 1 pipe.decr("some.counter"); // Update a gauge pipe.gauge("some.value", 12.0); // Modify a counter by an arbitrary float. pipe.count("some.counter", 511.0); // Send a histogram value as a float. pipe.histogram("some.histogram", 511.0); // Send a key/value. pipe.kv("some.data", 15.26); // Set max UDP packet size if you wish, default is 512 pipe.set_max_udp_size(128); // Send to StatsD pipe.send(&client); ``` Pipelines are also helpful to make functions simpler to test, as you can pass a pipeline and be confident that no UDP packets will be sent. ## License Licenesed under the [MIT License](LICENSE.txt). statsd-0.16.0/examples/client.rs000064400000000000000000000007341046102023000146600ustar 00000000000000// Load the crate extern crate statsd; // Import the client object. use statsd::client::Client; fn main() { let client = Client::new("127.0.0.1:8125", "myapp").unwrap(); client.incr("some.counter"); println!("Sent a counter!"); client.gauge("some.gauge", 124.0); println!("Set a gauge!"); client.timer("timer.duration", 182.1); println!("Set a timer!"); client.time("closure.duration", || { println!("Timing a closure"); }); } statsd-0.16.0/src/client.rs000064400000000000000000000504341046102023000136330ustar 00000000000000use std::collections::VecDeque; use std::error; use std::fmt; use std::io::Error; use std::net::AddrParseError; use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; use std::time; #[derive(Debug)] pub enum StatsdError { IoError(Error), AddrParseError(String), } impl From for StatsdError { fn from(_: AddrParseError) -> StatsdError { StatsdError::AddrParseError("Address parsing error".to_string()) } } impl From for StatsdError { fn from(err: Error) -> StatsdError { StatsdError::IoError(err) } } impl fmt::Display for StatsdError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { StatsdError::IoError(ref e) => write!(f, "{}", e), StatsdError::AddrParseError(ref e) => write!(f, "{}", e), } } } impl error::Error for StatsdError {} /// Client socket for statsd servers. /// /// After creating a metric you can use `Client` /// to send metrics to the configured statsd server /// /// # Example /// /// Creating a client and sending metrics is easy. /// /// ```ignore /// use statsd::client::Client; /// /// let client = Client::new("127.0.0.1:8125", "myapp"); /// client.incr("some.metric.completed"); /// ``` pub struct Client { socket: UdpSocket, server_address: SocketAddr, prefix: String, } impl Client { /// Construct a new statsd client given an host/port & prefix pub fn new(host: T, prefix: &str) -> Result { let server_address = host .to_socket_addrs()? .next() .ok_or_else(|| StatsdError::AddrParseError("Address parsing error".to_string()))?; // Bind to a generic port as we'll only be writing on this // socket. let socket = if server_address.is_ipv4() { UdpSocket::bind("0.0.0.0:0")? } else { UdpSocket::bind("[::]:0")? }; Ok(Client { socket, prefix: prefix.to_string(), server_address, }) } /// Increment a metric by 1 /// /// ```ignore /// # Increment a given metric by 1. /// client.incr("metric.completed"); /// ``` /// /// This modifies a counter with an effective sampling /// rate of 1.0. pub fn incr(&self, metric: &str) { self.count(metric, 1.0); } /// Decrement a metric by -1 /// /// ```ignore /// # Decrement a given metric by 1 /// client.decr("metric.completed"); /// ``` /// /// This modifies a counter with an effective sampling /// rate of 1.0. pub fn decr(&self, metric: &str) { self.count(metric, -1.0); } /// Modify a counter by `value`. /// /// Will increment or decrement a counter by `value` with /// a sampling rate of 1.0. /// /// ```ignore /// // Increment by 12 /// client.count("metric.completed", 12.0); /// ``` pub fn count(&self, metric: &str, value: f64) { let data = self.prepare(format!("{}:{}|c", metric, value)); self.send(data); } /// Modify a counter by `value` only x% of the time. /// /// Will increment or decrement a counter by `value` with /// a custom sampling rate. /// /// /// ```ignore /// // Increment by 4 50% of the time. /// client.sampled_count("metric.completed", 4, 0.5); /// ``` pub fn sampled_count(&self, metric: &str, value: f64, rate: f64) { if rand::random::() >= rate { return; } let data = self.prepare(format!("{}:{}|c|@{}", metric, value, rate)); self.send(data); } /// Set a gauge value. /// /// ```ignore /// // set a gauge to 9001 /// client.gauge("power_level.observed", 9001.0); /// ``` pub fn gauge(&self, metric: &str, value: f64) { let data = self.prepare(format!("{}:{}|g", metric, value)); self.send(data); } /// Send a timer value. /// /// The value is expected to be in ms. /// /// ```ignore /// // pass a duration value /// client.timer("response.duration", 10.123); /// ``` pub fn timer(&self, metric: &str, value: f64) { let data = self.prepare(format!("{}:{}|ms", metric, value)); self.send(data); } /// Time a block of code. /// /// The passed closure will be timed and executed. The block's /// duration will be sent as a metric. /// /// ```ignore /// // pass a duration value /// client.time("response.duration", || { /// // Your code here. /// }); /// ``` pub fn time(&self, metric: &str, callable: F) -> R where F: FnOnce() -> R, { let start = time::Instant::now(); let return_val = callable(); let used = start.elapsed(); let data = self.prepare(format!("{}:{}|ms", metric, used.as_millis())); self.send(data); return_val } fn prepare>(&self, data: T) -> String { if self.prefix.is_empty() { data.as_ref().to_string() } else { format!("{}.{}", self.prefix, data.as_ref()) } } /// Send data along the UDP socket. fn send(&self, data: String) { let _ = self.socket.send_to(data.as_bytes(), self.server_address); } /// Get a pipeline struct that allows optimizes the number of UDP /// packets used to send multiple metrics /// /// ```ignore /// let mut pipeline = client.pipeline(); /// pipeline.incr("some.metric", 1); /// pipeline.incr("other.metric", 1); /// pipeline.send(&mut client); /// ``` pub fn pipeline(&self) -> Pipeline { Pipeline::new() } /// Send a histogram value. /// /// ```ignore /// // pass response size value /// client.histogram("response.size", 128.0); /// ``` pub fn histogram(&self, metric: &str, value: f64) { let data = self.prepare(format!("{}:{}|h", metric, value)); self.send(data); } /// Send a key/value /// /// ```ignore /// client.kv("key", 1.); /// ``` pub fn kv(&self, metric: &str, value: f64) { let data = self.prepare(format!("{}:{}|kv", metric, value)); self.send(data); } } pub struct Pipeline { stats: VecDeque, max_udp_size: usize, } impl Pipeline { pub fn new() -> Pipeline { Pipeline { stats: VecDeque::new(), max_udp_size: 512, } } /// Set max UDP packet size /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// pipe.set_max_udp_size(128); /// ``` pub fn set_max_udp_size(&mut self, max_udp_size: usize) { self.max_udp_size = max_udp_size; } /// Increment a metric by 1 /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // Increment a given metric by 1. /// pipe.incr("metric.completed"); /// ``` /// /// This modifies a counter with an effective sampling /// rate of 1.0. pub fn incr(&mut self, metric: &str) { self.count(metric, 1.0); } /// Decrement a metric by -1 /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // Decrement a given metric by 1 /// pipe.decr("metric.completed"); /// ``` /// /// This modifies a counter with an effective sampling /// rate of 1.0. pub fn decr(&mut self, metric: &str) { self.count(metric, -1.0); } /// Modify a counter by `value`. /// /// Will increment or decrement a counter by `value` with /// a sampling rate of 1.0. /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // Increment by 12 /// pipe.count("metric.completed", 12.0); /// ``` pub fn count(&mut self, metric: &str, value: f64) { let data = format!("{}:{}|c", metric, value); self.stats.push_back(data); } /// Modify a counter by `value` only x% of the time. /// /// Will increment or decrement a counter by `value` with /// a custom sampling rate. /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // Increment by 4 50% of the time. /// pipe.sampled_count("metric.completed", 4.0, 0.5); /// ``` pub fn sampled_count(&mut self, metric: &str, value: f64, rate: f64) { if rand::random::() >= rate { return; } let data = format!("{}:{}|c|@{}", metric, value, rate); self.stats.push_back(data); } /// Set a gauge value. /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // set a gauge to 9001 /// pipe.gauge("power_level.observed", 9001.0); /// ``` pub fn gauge(&mut self, metric: &str, value: f64) { let data = format!("{}:{}|g", metric, value); self.stats.push_back(data); } /// Send a timer value. /// /// The value is expected to be in ms. /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // pass a duration value /// pipe.timer("response.duration", 10.123); /// ``` pub fn timer(&mut self, metric: &str, value: f64) { let data = format!("{}:{}|ms", metric, value); self.stats.push_back(data); } /// Time a block of code. /// /// The passed closure will be timed and executed. The block's /// duration will be sent as a metric. /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // pass a duration value /// pipe.time("response.duration", || { /// // Your code here. /// }); /// ``` pub fn time(&mut self, metric: &str, callable: F) where F: FnOnce(), { let start = time::Instant::now(); callable(); let used = start.elapsed(); let data = format!("{}:{}|ms", metric, used.as_millis()); self.stats.push_back(data); } /// Send a histogram value. /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // pass response size value /// pipe.histogram("response.size", 128.0); /// ``` pub fn histogram(&mut self, metric: &str, value: f64) { let data = format!("{}:{}|h", metric, value); self.stats.push_back(data); } /// Send a key/value. /// /// ``` /// use statsd::client::Pipeline; /// /// let mut pipe = Pipeline::new(); /// // pass response size value /// pipe.kv("response.size", 256.); /// ``` pub fn kv(&mut self, metric: &str, value: f64) { let data = format!("{}:{}|kv", metric, value); self.stats.push_back(data); } /// Send data along the UDP socket. pub fn send(&mut self, client: &Client) { let mut _data = String::new(); if let Some(data) = self.stats.pop_front() { _data += client.prepare(&data).as_ref(); while !self.stats.is_empty() { let stat = client.prepare(self.stats.pop_front().unwrap()); if data.len() + stat.len() + 1 > self.max_udp_size { client.send(_data.clone()); _data.clear(); _data += &stat; } else { _data += "\n"; _data += &stat; } } } if !_data.is_empty() { client.send(_data); } } } impl Default for Pipeline { fn default() -> Self { Self::new() } } #[cfg(test)] mod test { use super::*; use std::net::{SocketAddr, UdpSocket}; use std::sync::{ atomic::{AtomicBool, Ordering}, mpsc::channel, Arc, }; use std::thread; use std::time::Duration; struct Server { local_addr: SocketAddr, sock: UdpSocket, } impl Server { fn new() -> Self { let addr: SocketAddr = "127.0.0.1:0".parse().unwrap(); let sock = UdpSocket::bind(addr).unwrap(); sock.set_read_timeout(Some(Duration::from_millis(100))) .unwrap(); let local_addr = sock.local_addr().unwrap(); Server { local_addr, sock } } fn addr(&self) -> SocketAddr { self.local_addr.clone() } /// Run the given test function while receiving several packets. Return a vector of the /// packets. fn run_while_receiving_all(self, func: F) -> Vec where F: Fn(), { let (serv_tx, serv_rx) = channel(); let func_ran = Arc::new(AtomicBool::new(false)); let bg_func_ran = Arc::clone(&func_ran); let bg = thread::spawn(move || loop { let mut buf = [0; 1500]; if let Ok((len, _)) = self.sock.recv_from(&mut buf) { let bytes = Vec::from(&buf[0..len]); serv_tx.send(bytes).unwrap(); } // go through the loop least once (do...while) if bg_func_ran.load(Ordering::SeqCst) { break; } }); func(); std::thread::sleep(Duration::from_millis(200)); func_ran.store(true, Ordering::SeqCst); bg.join().expect("background thread should join"); serv_rx .into_iter() .map(|bytes| String::from_utf8(bytes).unwrap()) .collect() } /// Run the given test function while receiving several packets. Return the concatenation /// of the packets. fn run_while_receiving(self, func: F) -> String where F: Fn(), { itertools::Itertools::intersperse( self.run_while_receiving_all(func).into_iter(), String::from("\n"), ) .fold(String::new(), |acc, b| acc + &b) } } #[test] fn test_sending_gauge() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| client.gauge("metric", 9.1)); assert_eq!("myapp.metric:9.1|g", response); } #[test] fn test_sending_gauge_without_prefix() { let server = Server::new(); let client = Client::new(server.addr(), "").unwrap(); let response = server.run_while_receiving(|| client.gauge("metric", 9.1)); assert_eq!("metric:9.1|g", response); } #[test] fn test_sending_incr() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| client.incr("metric")); assert_eq!("myapp.metric:1|c", response); } #[test] fn test_sending_decr() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| client.decr("metric")); assert_eq!("myapp.metric:-1|c", response); } #[test] fn test_sending_count() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| client.count("metric", 12.2)); assert_eq!("myapp.metric:12.2|c", response); } #[test] fn test_sending_timer() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| client.timer("metric", 21.39)); assert_eq!("myapp.metric:21.39|ms", response); } struct TimeTest { num: u8, } #[test] fn test_sending_timed_block() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| { let mut t = TimeTest { num: 10 }; let output = client.time("time_block", || { t.num += 2; "a string" }); assert_eq!(output, "a string"); assert_eq!(t.num, 12); }); assert!(response.contains("myapp.time_block")); assert!(response.contains("|ms")); } #[test] fn test_sending_histogram() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| client.histogram("metric", 9.1)); assert_eq!("myapp.metric:9.1|h", response); } #[test] fn test_sending_kv() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| client.kv("metric", 15.26)); assert_eq!("myapp.metric:15.26|kv", response); } #[test] fn test_pipeline_sending_time_block() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| { let mut pipeline = client.pipeline(); pipeline.gauge("metric", 9.1); let mut t = TimeTest { num: 10 }; pipeline.time("time_block", || { t.num += 2; }); pipeline.send(&client); assert_eq!(t.num, 12); }); assert_eq!("myapp.metric:9.1|g\nmyapp.time_block:0|ms", response); } #[test] fn test_pipeline_sending_gauge() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| { let mut pipeline = client.pipeline(); pipeline.gauge("metric", 9.1); pipeline.send(&client); }); assert_eq!("myapp.metric:9.1|g", response); } #[test] fn test_pipeline_sending_histogram() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| { let mut pipeline = client.pipeline(); pipeline.histogram("metric", 9.1); pipeline.send(&client); }); assert_eq!("myapp.metric:9.1|h", response); } #[test] fn test_pipeline_sending_kv() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| { let mut pipeline = client.pipeline(); pipeline.kv("metric", 15.26); pipeline.send(&client); }); assert_eq!("myapp.metric:15.26|kv", response); } #[test] fn test_pipeline_sending_multiple_data() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving(|| { let mut pipeline = client.pipeline(); pipeline.gauge("metric", 9.1); pipeline.count("metric", 12.2); pipeline.send(&client); }); assert_eq!("myapp.metric:9.1|g\nmyapp.metric:12.2|c", response); } #[test] fn test_pipeline_set_max_udp_size() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving_all(|| { let mut pipeline = client.pipeline(); pipeline.set_max_udp_size(20); pipeline.gauge("metric", 9.1); pipeline.count("metric", 12.2); pipeline.send(&client); }); assert_eq!(vec!["myapp.metric:9.1|g", "myapp.metric:12.2|c"], response); } #[test] fn test_pipeline_send_metric_after_pipeline() { let server = Server::new(); let client = Client::new(server.addr(), "myapp").unwrap(); let response = server.run_while_receiving_all(|| { let mut pipeline = client.pipeline(); pipeline.gauge("load", 9.0); pipeline.count("customers", 7.0); pipeline.send(&client); // Should still be able to send metrics // with the client. client.count("customers", 6.0); }); assert_eq!( vec!["myapp.load:9|g\nmyapp.customers:7|c", "myapp.customers:6|c"], response ); } } statsd-0.16.0/src/lib.rs000064400000000000000000000006601046102023000131170ustar 00000000000000//! A Rust implementation of statsd server & client. //! //! The statsd protocol consistents of plain-text single-packet messages sent //! over UDP, containing not much more than a key and (possibly sampled) value. //! //! Due to the inherent design of the system, there is no guarantee that metrics //! will be received by the server, and there is (by design) no indication of //! this. //! pub mod client; pub use client::Client;