Skip to content

Commit

Permalink
Add new time_duration method to Timed trait
Browse files Browse the repository at this point in the history
Add a new method for recording timings using std::time::Duration
instead of a u64 of milliseconds. The duration is converted to the
number of milliseconds before being send to the sink. Any integer
overflow will cause an error to be returned.

Fixes #48
  • Loading branch information
56quarters committed Jan 27, 2017
1 parent eb5dc49 commit 0fbb049
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 3 deletions.
7 changes: 6 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## [v0.12.0](https://github.com/tshlabs/cadence/tree/0.12.0) - ????-??-??
* Add new `time_duration` method to `Timed` trait per
[#48](https://github.com/tshlabs/cadence/issues/48). This allows users to record
timings using the `Duration` struct from the standard library.

## [v0.11.0](https://github.com/tshlabs/cadence/tree/0.11.0) - 2017-01-18
* **Breaking change** - Remove deprecated `AsyncMetricSink` per
[#47](https://github.com/tshlabs/cadence/issues/47). Users are encouraged to
Expand All @@ -11,7 +16,7 @@
of the client to care about the `MetricSink` implementation, put it behind an `Arc`
pointer in the client and remove the type `T` from the signature. This makes the
client easier to use and share between threads.
* Remove use of `Arc` inside various sinks per [#35](https://github.com/tshlabs/cadence/issues/45).
* Remove use of `Arc` inside various sinks per [#35](https://github.com/tshlabs/cadence/issues/35).

## [v0.10.0](https://github.com/tshlabs/cadence/tree/0.10.0) - 2017-01-08
* **Breaking change** - Remove deprecated `ConsoleMetricSink` and `LoggingMetricSink`
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ crossbeam = "0.2.10"
[lib]
name = "cadence"
path = "src/lib.rs"

[badges]
travis-ci = { repository = "tshlabs/cadence" }
45 changes: 43 additions & 2 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
use std::fmt;
use std::net::{ToSocketAddrs, UdpSocket};
use std::sync::Arc;
use std::time::Duration;

use ::sinks::{MetricSink, UdpMetricSink};

use ::types::{MetricResult, Counter, Timer, Gauge, Meter, Histogram, Metric};
use ::types::{MetricResult, MetricError, ErrorKind, Counter, Timer, Gauge,
Meter, Histogram, Metric};


/// Trait for incrementing and decrementing counters.
Expand Down Expand Up @@ -50,6 +52,12 @@ pub trait Counted {
pub trait Timed {
/// Record a timing in milliseconds with the given key
fn time(&self, key: &str, time: u64) -> MetricResult<Timer>;

/// Record a timing in milliseocnds with the given key
///
/// The duration will be truncated to millisecond precision. If the
/// duration cannot be represented as a `u64` an error will be returned.
fn time_duration(&self, key: &str, duration: Duration) -> MetricResult<Timer>;
}


Expand Down Expand Up @@ -142,7 +150,6 @@ pub trait MetricClient: Counted + Timed + Gauged + Metered + Histogrammed {}
/// For more information about the uses for each type of metric, see the
/// documentation for each mentioned trait.
///
///
/// # Sinks
///
/// The client uses some implementation of a `MetricSink` to emit the metrics.
Expand Down Expand Up @@ -381,6 +388,19 @@ impl Timed for StatsdClient {
self.send_metric(&timer)?;
Ok(timer)
}

fn time_duration(&self, key: &str, duration: Duration) -> MetricResult<Timer> {
let secs_as_ms = duration.as_secs().checked_mul(1_000);
let nanos_as_ms = (duration.subsec_nanos() as u64).checked_div(1_000_000);

let millis = secs_as_ms
.and_then(|v1| nanos_as_ms.and_then(|v2| v1.checked_add(v2)))
.ok_or_else(|| MetricError::from((ErrorKind::InvalidInput, "u64 overflow")))?;

let timer = Timer::new(&self.prefix, key, millis);
self.send_metric(&timer)?;
Ok(timer)
}
}


Expand Down Expand Up @@ -429,9 +449,12 @@ fn trim_key(val: &str) -> &str {

#[cfg(test)]
mod tests {
use std::time::Duration;
use std::u64;
use super::{trim_key, Counted, Timed, Gauged, Metered, Histogrammed,
MetricClient, StatsdClient};
use ::sinks::NopMetricSink;
use ::types::{ErrorKind, Timer};

#[test]
fn test_trim_key_with_trailing_dot() {
Expand Down Expand Up @@ -498,4 +521,22 @@ mod tests {
client.meter("some.meter", 29).unwrap();
client.histogram("some.histogram", 32).unwrap();
}

#[test]
fn test_statsd_client_time_duration_no_overflow() {
let client = StatsdClient::from_sink("prefix", NopMetricSink);
let res = client.time_duration("key", Duration::from_millis(157));
let expected = Timer::new("prefix", "key", 157);

assert_eq!(expected, res.unwrap());
}

#[test]
fn test_statsd_client_time_duration_with_overflow() {
let client = StatsdClient::from_sink("prefix", NopMetricSink);
let res = client.time_duration("key", Duration::from_secs(u64::MAX));
let err = res.unwrap_err();

assert_eq!(ErrorKind::InvalidInput, err.kind())
}
}
8 changes: 8 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ fn test_statsd_client_time() {
}


#[test]
fn test_statsd_client_time_duration() {
let client = new_nop_client("client.test");
let expected = Timer::new("client.test", "timer.key", 35);
assert_eq!(expected, client.time_duration("timer.key", Duration::from_millis(35)).unwrap());
}


#[test]
fn test_statsd_client_gauge() {
let client = new_nop_client("client.test");
Expand Down

0 comments on commit 0fbb049

Please sign in to comment.