From 47cd337841b129e5b36e048d74a2070f74b2011b Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Tue, 27 Nov 2012 18:32:29 -0600 Subject: [PATCH 01/69] 2.0.1: Add floating-point support; reflect pending release under indeedeng aegis --- README.md | 18 +- build.xml | 2 +- java-statsd-client.pom | 27 +- .../com/timgroup/statsd/NoOpStatsDClient.java | 17 ++ .../statsd/NonBlockingStatsDClient.java | 232 ++++++++++++++++++ .../com/timgroup/statsd/StatsDClient.java | 206 ++++++++++++++-- .../statsd/NonBlockingStatsDClientTest.java | 100 +++++++- 7 files changed, 561 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index be7a600..11ee7aa 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,19 @@ -java-statsd-client +java-dogstatsd-client ================== A statsd client library implemented in Java. Allows for Java applications to easily communicate with statsd. +This version is forked from the upstream [java-statsd-client](https://github.com/youdevise/java-statsd-client) project, adding support for [DataDog](http://datadoghq.com/) extensions for use with [dogstatsd](http://docs.datadoghq.com/guides/dogstatsd/). + Downloads --------- The client jar is distributed via maven central, and can be downloaded [here](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.timgroup%20a%3Ajava-statsd-client). ```xml - com.timgroup - java-statsd-client - 2.0.0 + com.indeed + java-dogstatsd-client + 2.0.1 ``` @@ -25,9 +27,11 @@ public class Foo { private static final StatsDClient statsd = new NonBlockingStatsDClient("my.prefix", "statsd-host", 8125); public static final void main(String[] args) { - statsd.incrementCounter("bar"); - statsd.recordGaugeValue("baz", 100); - statsd.recordExecutionTime("bag", 25); + statsd.incrementCounter("foo"); + statsd.recordGaugeValue("bar", 100); + statsd.recordGaugeValue("baz", 0.01); /* DataDog extension: support for floating-point gauges */ + statsd.recordExecutionTime("bag", 25, {"cluster:foo"}); /* DataDog extension: cluster tag */ + statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ } } ``` diff --git a/build.xml b/build.xml index 474b92b..435c023 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - + diff --git a/java-statsd-client.pom b/java-statsd-client.pom index d6d8ad0..7a5eb63 100644 --- a/java-statsd-client.pom +++ b/java-statsd-client.pom @@ -1,12 +1,12 @@ - + 4.0.0 - com.timgroup - java-statsd-client + com.indeed + java-dogstatsd-client jar - java-statsd-client + java-dogstatsd-client @VERSION@ - A tiny library allowing Java applications to communicate with statsd instances easily. - http://github.com/youdevise/java-statsd-client + A tiny library allowing Java applications to communicate with DataDog statsd instances easily. + https://github.com/indeedeng/java-dogstatsd-client The MIT License (MIT) @@ -15,15 +15,20 @@ - http://github.com/youdevise/java-statsd-client - scm:git:git://github.com/youdevise/java-statsd-client.git - scm:git:git@github.com:youdevise/java-statsd-client.git + http://github.com/indeedeng/java-dogstatsd-client + scm:git:git://github.com/indeedeng/java-dogstatsd-client.git + scm:git:git@github.com:indeedeng/java-dogstatsd-client.git - + + duffy + Charles Duffy + duffy@indeed.com + + scarytom Tom Denley tom.denley@timgroup.com - \ No newline at end of file + diff --git a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java index 2f6455a..fc2bbeb 100644 --- a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java @@ -9,13 +9,30 @@ */ public final class NoOpStatsDClient implements StatsDClient { @Override public void stop() { } + @Override public void count(String aspect, int delta, String[] tags) { } @Override public void count(String aspect, int delta) { } + @Override public void incrementCounter(String aspect, String[] tags) { } @Override public void incrementCounter(String aspect) { } + @Override public void increment(String aspect, String[] tags) { } @Override public void increment(String aspect) { } + @Override public void decrementCounter(String aspect, String[] tags) { } @Override public void decrementCounter(String aspect) { } + @Override public void decrement(String aspect, String[] tags) { } @Override public void decrement(String aspect) { } + @Override public void recordGaugeValue(String aspect, double value, String[] tags) { } + @Override public void recordGaugeValue(String aspect, double value) { } + @Override public void gauge(String aspect, double value, String[] tags) { } + @Override public void gauge(String aspect, double value) { } + @Override public void recordGaugeValue(String aspect, int value, String[] tags) { } @Override public void recordGaugeValue(String aspect, int value) { } + @Override public void gauge(String aspect, int value, String[] tags) { } @Override public void gauge(String aspect, int value) { } + @Override public void recordExecutionTime(String aspect, int timeInMs, String[] tags) { } @Override public void recordExecutionTime(String aspect, int timeInMs) { } + @Override public void time(String aspect, int value, String[] tags) { } @Override public void time(String aspect, int value) { } + @Override public void recordHistogramValue(String aspect, int value, String[] tags) { } + @Override public void recordHistogramValue(String aspect, int value) { } + @Override public void histogram(String aspect, int value, String[] tags) { } + @Override public void histogram(String aspect, int value) { } } diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index aafd383..add03ba 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -22,6 +22,7 @@ *
  • {@link #incrementCounter} - adds one to the value of the specified named counter
  • *
  • {@link #recordGaugeValue} - records the latest fixed value for the specified named gauge
  • *
  • {@link #recordExecutionTime} - records an execution time in milliseconds for the specified named operation
  • + *
  • {@link #recordHistogramValue} - records a value, to be tracked with average, maximum, and percentiles
  • * * From the perspective of the application, these methods are non-blocking, with the resulting * IO operations being carried out in a separate thread. Furthermore, these methods are guaranteed @@ -130,6 +131,40 @@ public void stop() { } } + /** + * Generate a suffix conveying the given tag list to the client + */ + String tagString(String[] tags) { + if(tags == null || tags.length == 0) { + return ""; + } + StringBuilder sb = new StringBuilder("|#"); + for(int n=tags.length - 1; n>=0; n--) { + sb.append(tags[n]); + if(n > 0) { + sb.append(","); + } + } + return sb.toString(); + } + + /** + * Adjusts the specified counter by a given delta. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the counter to adjust + * @param delta + * the amount to adjust the counter by + * @param tags + * array of tags to be added to the data + */ + @Override + public void count(String aspect, int delta, String[] tags) { + send(String.format("%s.%s:%d|c%s", prefix, aspect, delta, tagString(tags))); + } + /** * Adjusts the specified counter by a given delta. * @@ -145,6 +180,21 @@ public void count(String aspect, int delta) { send(String.format("%s.%s:%d|c", prefix, aspect, delta)); } + /** + * Increments the specified counter by one. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the counter to increment + * @param tags + * array of tags to be added to the data + */ + @Override + public void incrementCounter(String aspect, String[] tags) { + count(aspect, 1, tags); + } + /** * Increments the specified counter by one. * @@ -158,6 +208,14 @@ public void incrementCounter(String aspect) { count(aspect, 1); } + /** + * Convenience method equivalent to {@link #incrementCounter(String, String[])}. + */ + @Override + public void increment(String aspect, String[] tags) { + incrementCounter(aspect, tags); + } + /** * Convenience method equivalent to {@link #incrementCounter(String)}. */ @@ -166,6 +224,21 @@ public void increment(String aspect) { incrementCounter(aspect); } + /** + * Decrements the specified counter by one. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the counter to decrement + * @param tags + * array of tags to be added to the data + */ + @Override + public void decrementCounter(String aspect, String[] tags) { + count(aspect, -1, tags); + } + /** * Decrements the specified counter by one. * @@ -179,6 +252,14 @@ public void decrementCounter(String aspect) { count(aspect, -1); } + /** + * Convenience method equivalent to {@link #decrementCounter(String, String[])}. + */ + @Override + public void decrement(String aspect, String[] tags) { + decrementCounter(aspect, tags); + } + /** * Convenience method equivalent to {@link #decrementCounter(String)}. */ @@ -187,6 +268,76 @@ public void decrement(String aspect) { decrementCounter(aspect); } + /** + * Records the latest fixed value for the specified named gauge. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the gauge + * @param value + * the new reading of the gauge + * @param tags + * array of tags to be added to the data + */ + @Override + public void recordGaugeValue(String aspect, double value, String[] tags) { + /* Intentionally using %s rather than %f here to avoid + * padding with extra 0s to represent precision */ + send(String.format("%s.%s:%s|g%s", prefix, aspect, value, tagString(tags))); + } + + /** + * Records the latest fixed value for the specified named gauge. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the gauge + * @param value + * the new reading of the gauge + */ + @Override + public void recordGaugeValue(String aspect, double value) { + /* Intentionally using %s rather than %f here to avoid + * padding with extra 0s to represent precision */ + send(String.format("%s.%s:%s|g", prefix, aspect, value)); + } + + /** + * Convenience method equivalent to {@link #recordGaugeValue(String, double, String[])}. + */ + @Override + public void gauge(String aspect, double value, String[] tags) { + recordGaugeValue(aspect, value, tags); + } + + /** + * Convenience method equivalent to {@link #recordGaugeValue(String, double)}. + */ + @Override + public void gauge(String aspect, double value) { + recordGaugeValue(aspect, value); + } + + + /** + * Records the latest fixed value for the specified named gauge. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the gauge + * @param value + * the new reading of the gauge + * @param tags + * array of tags to be added to the data + */ + @Override + public void recordGaugeValue(String aspect, int value, String[] tags) { + send(String.format("%s.%s:%d|g%s", prefix, aspect, value, tagString(tags))); + } + /** * Records the latest fixed value for the specified named gauge. * @@ -202,6 +353,14 @@ public void recordGaugeValue(String aspect, int value) { send(String.format("%s.%s:%d|g", prefix, aspect, value)); } + /** + * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. + */ + @Override + public void gauge(String aspect, int value, String[] tags) { + recordGaugeValue(aspect, value, tags); + } + /** * Convenience method equivalent to {@link #recordGaugeValue(String, int)}. */ @@ -210,6 +369,23 @@ public void gauge(String aspect, int value) { recordGaugeValue(aspect, value); } + /** + * Records an execution time in milliseconds for the specified named operation. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the timed operation + * @param timeInMs + * the time in milliseconds + * @param tags + * array of tags to be added to the data + */ + @Override + public void recordExecutionTime(String aspect, int timeInMs, String[] tags) { + send(String.format("%s.%s:%d|ms%s", prefix, aspect, timeInMs, tagString(tags))); + } + /** * Records an execution time in milliseconds for the specified named operation. * @@ -225,6 +401,14 @@ public void recordExecutionTime(String aspect, int timeInMs) { send(String.format("%s.%s:%d|ms", prefix, aspect, timeInMs)); } + /** + * Convenience method equivalent to {@link #recordExecutionTime(String, int, String[])}. + */ + @Override + public void time(String aspect, int value, String[] tags) { + recordExecutionTime(aspect, value, tags); + } + /** * Convenience method equivalent to {@link #recordExecutionTime(String, int)}. */ @@ -233,6 +417,54 @@ public void time(String aspect, int value) { recordExecutionTime(aspect, value); } + /** + * Records a value for the specified named histogram. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + * @param tags + * array of tags to be added to the data + */ + @Override + public void recordHistogramValue(String aspect, int value, String[] tags) { + send(String.format("%s.%s:%d|h%s", prefix, aspect, value, tagString(tags))); + } + + /** + * Records a value for the specified named histogram. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + */ + @Override + public void recordHistogramValue(String aspect, int value) { + send(String.format("%s.%s:%d|h", prefix, aspect, value)); + } + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. + */ + @Override + public void histogram(String aspect, int value, String[] tags) { + recordHistogramValue(aspect, value, tags); + } + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, int)}. + */ + @Override + public void histogram(String aspect, int value) { + recordHistogramValue(aspect, value); + } + private void send(final String message) { try { executor.execute(new Runnable() { diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index ef8bd2a..121a28e 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -3,7 +3,7 @@ /** * Describes a client connection to a StatsD server, which may be used to post metrics * in the form of counters, timers, and gauges. - * + * *

    Three key methods are provided for the submission of data-points for the application under * scrutiny: *

      @@ -11,7 +11,7 @@ *
    • {@link #recordGaugeValue} - records the latest fixed value for the specified named gauge
    • *
    • {@link #recordExecutionTime} - records an execution time in milliseconds for the specified named operation
    • *
    - * + * * @author Tom Denley * */ @@ -25,9 +25,25 @@ public interface StatsDClient { /** * Adjusts the specified counter by a given delta. - * + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * + * + * @param aspect + * the name of the counter to adjust + * @param delta + * the amount to adjust the counter by + * @param tags + * array of tags to be added to the data + */ + void count(String aspect, int delta, String[] tags); + + /** + * Adjusts the specified counter by a given delta. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * * @param aspect * the name of the counter to adjust * @param delta @@ -37,39 +53,129 @@ public interface StatsDClient { /** * Increments the specified counter by one. - * + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * + * + * @param aspect + * the name of the counter to increment + * @param tags + * array of tags to be added to the data + */ + void incrementCounter(String aspect, String[] tags); + + /** + * Increments the specified counter by one. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * * @param aspect * the name of the counter to increment */ void incrementCounter(String aspect); /** - * Convenience method equivalent to {@link #incrementCounter(String)}. + * Convenience method equivalent to {@link #incrementCounter(String, String[])}. + */ + void increment(String aspect, String[] tags); + + /** + * Convenience method equivalent to {@link #incrementCounter(String)}. */ void increment(String aspect); /** * Decrements the specified counter by one. - * + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the counter to decrement + * @param tags + * array of tags to be added to the data + */ + void decrementCounter(String aspect, String[] tags); + + /** + * Decrements the specified counter by one. + * *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * + * * @param aspect * the name of the counter to decrement */ void decrementCounter(String aspect); /** - * Convenience method equivalent to {@link #decrementCounter(String)}. + * Convenience method equivalent to {@link #decrementCounter(String)}. */ void decrement(String aspect); + /** + * Convenience method equivalent to {@link #decrementCounter(String, String[])}. + */ + void decrement(String aspect, String[] tags); + /** * Records the latest fixed value for the specified named gauge. - * + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * + * + * @param aspect + * the name of the gauge + * @param value + * the new reading of the gauge + */ + void recordGaugeValue(String aspect, double value, String[] tags); + + /** + * Records the latest fixed value for the specified named gauge. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the gauge + * @param value + * the new reading of the gauge + */ + void recordGaugeValue(String aspect, double value); + + + /** + * Convenience method equivalent to {@link #recordGaugeValue(String, double, String[])}. + */ + void gauge(String aspect, double value, String[] tags); + + /** + * Convenience method equivalent to {@link #recordGaugeValue(String, double)}. + */ + void gauge(String aspect, double value); + + + /** + * Records the latest fixed value for the specified named gauge. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the gauge + * @param value + * the new reading of the gauge + */ + void recordGaugeValue(String aspect, int value, String[] tags); + + /** + * Records the latest fixed value for the specified named gauge. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * * @param aspect * the name of the gauge * @param value @@ -77,16 +183,38 @@ public interface StatsDClient { */ void recordGaugeValue(String aspect, int value); + + /** + * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. + */ + void gauge(String aspect, int value, String[] tags); + /** - * Convenience method equivalent to {@link #recordGaugeValue(String, int)}. + * Convenience method equivalent to {@link #recordGaugeValue(String, int)}. */ void gauge(String aspect, int value); /** * Records an execution time in milliseconds for the specified named operation. - * + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * + * + * @param aspect + * the name of the timed operation + * @param timeInMs + * the time in milliseconds + * @param tags + * array of tags to be added to the data + */ + void recordExecutionTime(String aspect, int timeInMs, String[] tags); + + /** + * Records an execution time in milliseconds for the specified named operation. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * * @param aspect * the name of the timed operation * @param timeInMs @@ -95,8 +223,52 @@ public interface StatsDClient { void recordExecutionTime(String aspect, int timeInMs); /** - * Convenience method equivalent to {@link #recordExecutionTime(String, int)}. + * Convenience method equivalent to {@link #recordExecutionTime(String, int, String[])}. + */ + void time(String aspect, int value, String[] tags); + + /** + * Convenience method equivalent to {@link #recordExecutionTime(String, int)}. */ void time(String aspect, int value); -} \ No newline at end of file + /** + * Records a value for the specified named histogram. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + * @param tags + * array of tags to be added to the data + */ + void recordHistogramValue(String aspect, int value, String[] tags); + + /** + * Records a value for the specified named histogram. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + */ + void recordHistogramValue(String aspect, int value); + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. + */ + void histogram(String aspect, int value, String[] tags); + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, int)}. + */ + void histogram(String aspect, int value); +} diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 4e879ef..4c830ac 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -1,7 +1,7 @@ package com.timgroup.statsd; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; +import org.junit.After; +import org.junit.Test; import java.net.DatagramPacket; import java.net.DatagramSocket; @@ -9,8 +9,8 @@ import java.util.ArrayList; import java.util.List; -import org.junit.After; -import org.junit.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; public class NonBlockingStatsDClientTest { @@ -32,6 +32,36 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); } + @Test(timeout=5000L) public void + sends_counter_value_to_statsd_with_null_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.count("mycount", 24, null); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); + } + + @Test(timeout=5000L) public void + sends_counter_value_to_statsd_with_empty_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.count("mycount", 24, new String[]{}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); + } + + @Test(timeout=5000L) public void + sends_counter_value_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.count("mycount", 24, new String[]{"foo:bar","baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c|#baz,foo:bar")); + } + @Test(timeout=5000L) public void sends_counter_increment_to_statsd() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); @@ -42,6 +72,16 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.myinc:1|c")); } + @Test(timeout=5000L) public void + sends_counter_increment_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.incrementCounter("myinc", new String[]{"foo:bar","baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.myinc:1|c|#baz,foo:bar")); + } + @Test(timeout=5000L) public void sends_counter_decrement_to_statsd() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); @@ -52,6 +92,16 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mydec:-1|c")); } + @Test(timeout=5000L) public void + sends_counter_decrement_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.decrementCounter("mydec", new String[]{"foo:bar", "baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mydec:-1|c|#baz,foo:bar")); + } + @Test(timeout=5000L) public void sends_gauge_to_statsd() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); @@ -62,6 +112,36 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mygauge:423|g")); } + @Test(timeout=5000L) public void + sends_double_gauge_to_statsd() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordGaugeValue("mygauge", 0.423); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:0.423|g")); + } + + @Test(timeout=5000L) public void + sends_gauge_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordGaugeValue("mygauge", 423, new String[]{"foo:bar","baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:423|g|#baz,foo:bar")); + } + + @Test(timeout=5000L) public void + sends_double_gauge_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordGaugeValue("mygauge", 0.423, new String[]{"foo:bar","baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:0.423|g|#baz,foo:bar")); + } + @Test(timeout=5000L) public void sends_timer_to_statsd() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); @@ -72,6 +152,16 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms")); } + @Test(timeout=5000L) public void + sends_timer_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordExecutionTime("mytime", 123, new String[]{"foo:bar","baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms|#baz,foo:bar")); + } + private static final class DummyStatsDServer { private final List messagesReceived = new ArrayList(); private final DatagramSocket server; @@ -101,4 +191,4 @@ public List messagesReceived() { return new ArrayList(messagesReceived); } } -} \ No newline at end of file +} From d4596990a99e17984d50cfa86328582223d02fb2 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Wed, 28 Nov 2012 11:37:07 -0600 Subject: [PATCH 02/69] 2.0.2: Allow histograms to be floating-point; add test coverage --- README.md | 5 +- build.xml | 2 +- .../com/timgroup/statsd/NoOpStatsDClient.java | 4 ++ .../statsd/NonBlockingStatsDClient.java | 52 +++++++++++++++++++ .../com/timgroup/statsd/StatsDClient.java | 40 ++++++++++++++ .../statsd/NonBlockingStatsDClientTest.java | 40 ++++++++++++++ 6 files changed, 140 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 11ee7aa..fbd0d5e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The client jar is distributed via maven central, and can be downloaded [here](ht com.indeed java-dogstatsd-client - 2.0.1 + 2.0.2 ``` @@ -31,7 +31,8 @@ public class Foo { statsd.recordGaugeValue("bar", 100); statsd.recordGaugeValue("baz", 0.01); /* DataDog extension: support for floating-point gauges */ statsd.recordExecutionTime("bag", 25, {"cluster:foo"}); /* DataDog extension: cluster tag */ - statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ + statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ + statsd.recordHistogram("qux", 15.5) /* ...also floating-point */ } } ``` diff --git a/build.xml b/build.xml index 435c023..2ce61bb 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - + diff --git a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java index fc2bbeb..8653752 100644 --- a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java @@ -31,6 +31,10 @@ public final class NoOpStatsDClient implements StatsDClient { @Override public void recordExecutionTime(String aspect, int timeInMs) { } @Override public void time(String aspect, int value, String[] tags) { } @Override public void time(String aspect, int value) { } + @Override public void recordHistogramValue(String aspect, double value, String[] tags) { } + @Override public void recordHistogramValue(String aspect, double value) { } + @Override public void histogram(String aspect, double value, String[] tags) { } + @Override public void histogram(String aspect, double value) { } @Override public void recordHistogramValue(String aspect, int value, String[] tags) { } @Override public void recordHistogramValue(String aspect, int value) { } @Override public void histogram(String aspect, int value, String[] tags) { } diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index add03ba..c6e2d71 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -417,6 +417,58 @@ public void time(String aspect, int value) { recordExecutionTime(aspect, value); } + /** + * Records a value for the specified named histogram. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + * @param tags + * array of tags to be added to the data + */ + @Override + public void recordHistogramValue(String aspect, double value, String[] tags) { + /* Intentionally using %s rather than %f here to avoid + * padding with extra 0s to represent precision */ + send(String.format("%s.%s:%s|h%s", prefix, aspect, value, tagString(tags))); + } + + /** + * Records a value for the specified named histogram. + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + */ + @Override + public void recordHistogramValue(String aspect, double value) { + /* Intentionally using %s rather than %f here to avoid + * padding with extra 0s to represent precision */ + send(String.format("%s.%s:%s|h", prefix, aspect, value)); + } + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, double, String[])}. + */ + @Override + public void histogram(String aspect, double value, String[] tags) { + recordHistogramValue(aspect, value, tags); + } + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, double, String[])}. + */ + @Override + public void histogram(String aspect, double value) { + recordHistogramValue(aspect, value); + } + /** * Records a value for the specified named histogram. * diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index 121a28e..fef3268 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -232,6 +232,46 @@ public interface StatsDClient { */ void time(String aspect, int value); + /** + * Records a value for the specified named histogram. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + * @param tags + * array of tags to be added to the data + */ + void recordHistogramValue(String aspect, double value, String[] tags); + + /** + * Records a value for the specified named histogram. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the histogram + * @param value + * the value to be incorporated in the histogram + */ + void recordHistogramValue(String aspect, double value); + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, double, String[])}. + */ + void histogram(String aspect, double value, String[] tags); + + /** + * Convenience method equivalent to {@link #recordHistogramValue(String, double)}. + */ + void histogram(String aspect, double value); + /** * Records a value for the specified named histogram. * diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 4c830ac..825a23a 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -142,6 +142,46 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mygauge:0.423|g|#baz,foo:bar")); } + @Test(timeout=5000L) public void + sends_histogram_to_statsd() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordHistogramValue("myhistogram", 423); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:423|h")); + } + + @Test(timeout=5000L) public void + sends_double_histogram_to_statsd() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordHistogramValue("myhistogram", 0.423); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:0.423|h")); + } + + @Test(timeout=5000L) public void + sends_histogram_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordHistogramValue("myhistogram", 423, new String[]{"foo:bar","baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:423|h|#baz,foo:bar")); + } + + @Test(timeout=5000L) public void + sends_double_histogram_to_statsd_with_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordHistogramValue("myhistogram", 0.423, new String[]{"foo:bar","baz"}); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:0.423|h|#baz,foo:bar")); + } + @Test(timeout=5000L) public void sends_timer_to_statsd() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); From 90073536b2a87b95eed5eaf9cc406096b84e914f Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Wed, 28 Nov 2012 16:50:44 -0600 Subject: [PATCH 03/69] 2.0.3: Add support for null or empty prefix values --- README.md | 2 ++ build.xml | 2 +- .../statsd/NonBlockingStatsDClient.java | 30 +++++++++++-------- .../statsd/NonBlockingStatsDClientTest.java | 21 +++++++++++++ 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index fbd0d5e..4f563d0 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ A statsd client library implemented in Java. Allows for Java applications to ea This version is forked from the upstream [java-statsd-client](https://github.com/youdevise/java-statsd-client) project, adding support for [DataDog](http://datadoghq.com/) extensions for use with [dogstatsd](http://docs.datadoghq.com/guides/dogstatsd/). +This version also adds support for empty or null prefixes, to allow a client to send arbitrary statistic names. + Downloads --------- The client jar is distributed via maven central, and can be downloaded [here](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.timgroup%20a%3Ajava-statsd-client). diff --git a/build.xml b/build.xml index 2ce61bb..3819c20 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - + diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index c6e2d71..f6e0677 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -100,7 +100,11 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws * if the client could not be started */ public NonBlockingStatsDClient(String prefix, String hostname, int port, StatsDClientErrorHandler errorHandler) throws StatsDClientException { - this.prefix = prefix; + if(prefix != null && prefix.length() > 0) { + this.prefix = String.format("%s.", prefix); + } else { + this.prefix = ""; + } this.handler = errorHandler; try { @@ -162,7 +166,7 @@ String tagString(String[] tags) { */ @Override public void count(String aspect, int delta, String[] tags) { - send(String.format("%s.%s:%d|c%s", prefix, aspect, delta, tagString(tags))); + send(String.format("%s%s:%d|c%s", prefix, aspect, delta, tagString(tags))); } /** @@ -177,7 +181,7 @@ public void count(String aspect, int delta, String[] tags) { */ @Override public void count(String aspect, int delta) { - send(String.format("%s.%s:%d|c", prefix, aspect, delta)); + send(String.format("%s%s:%d|c", prefix, aspect, delta)); } /** @@ -284,7 +288,7 @@ public void decrement(String aspect) { public void recordGaugeValue(String aspect, double value, String[] tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s.%s:%s|g%s", prefix, aspect, value, tagString(tags))); + send(String.format("%s%s:%s|g%s", prefix, aspect, value, tagString(tags))); } /** @@ -301,7 +305,7 @@ public void recordGaugeValue(String aspect, double value, String[] tags) { public void recordGaugeValue(String aspect, double value) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s.%s:%s|g", prefix, aspect, value)); + send(String.format("%s%s:%s|g", prefix, aspect, value)); } /** @@ -335,7 +339,7 @@ public void gauge(String aspect, double value) { */ @Override public void recordGaugeValue(String aspect, int value, String[] tags) { - send(String.format("%s.%s:%d|g%s", prefix, aspect, value, tagString(tags))); + send(String.format("%s%s:%d|g%s", prefix, aspect, value, tagString(tags))); } /** @@ -350,7 +354,7 @@ public void recordGaugeValue(String aspect, int value, String[] tags) { */ @Override public void recordGaugeValue(String aspect, int value) { - send(String.format("%s.%s:%d|g", prefix, aspect, value)); + send(String.format("%s%s:%d|g", prefix, aspect, value)); } /** @@ -383,7 +387,7 @@ public void gauge(String aspect, int value) { */ @Override public void recordExecutionTime(String aspect, int timeInMs, String[] tags) { - send(String.format("%s.%s:%d|ms%s", prefix, aspect, timeInMs, tagString(tags))); + send(String.format("%s%s:%d|ms%s", prefix, aspect, timeInMs, tagString(tags))); } /** @@ -398,7 +402,7 @@ public void recordExecutionTime(String aspect, int timeInMs, String[] tags) { */ @Override public void recordExecutionTime(String aspect, int timeInMs) { - send(String.format("%s.%s:%d|ms", prefix, aspect, timeInMs)); + send(String.format("%s%s:%d|ms", prefix, aspect, timeInMs)); } /** @@ -433,7 +437,7 @@ public void time(String aspect, int value) { public void recordHistogramValue(String aspect, double value, String[] tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s.%s:%s|h%s", prefix, aspect, value, tagString(tags))); + send(String.format("%s%s:%s|h%s", prefix, aspect, value, tagString(tags))); } /** @@ -450,7 +454,7 @@ public void recordHistogramValue(String aspect, double value, String[] tags) { public void recordHistogramValue(String aspect, double value) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s.%s:%s|h", prefix, aspect, value)); + send(String.format("%s%s:%s|h", prefix, aspect, value)); } /** @@ -483,7 +487,7 @@ public void histogram(String aspect, double value) { */ @Override public void recordHistogramValue(String aspect, int value, String[] tags) { - send(String.format("%s.%s:%d|h%s", prefix, aspect, value, tagString(tags))); + send(String.format("%s%s:%d|h%s", prefix, aspect, value, tagString(tags))); } /** @@ -498,7 +502,7 @@ public void recordHistogramValue(String aspect, int value, String[] tags) { */ @Override public void recordHistogramValue(String aspect, int value) { - send(String.format("%s.%s:%d|h", prefix, aspect, value)); + send(String.format("%s%s:%d|h", prefix, aspect, value)); } /** diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 825a23a..70ec755 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -202,6 +202,27 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms|#baz,foo:bar")); } + + @Test(timeout=5000L) public void + sends_gauge_empty_prefix() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("", "localhost", STATSD_SERVER_PORT); + empty_prefix_client.gauge("top.level.value", 423); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("top.level.value:423|g")); + } + + @Test(timeout=5000L) public void + sends_gauge_null_prefix() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient null_prefix_client = new NonBlockingStatsDClient(null, "localhost", STATSD_SERVER_PORT); + null_prefix_client.gauge("top.level.value", 423); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("top.level.value:423|g")); + } + private static final class DummyStatsDServer { private final List messagesReceived = new ArrayList(); private final DatagramSocket server; From 63781194b3320dfe40773b8e958103df8f1de2f7 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 3 Dec 2012 16:29:57 -0600 Subject: [PATCH 04/69] 2.0.4: Format floating-point values more explicitly --- build.xml | 4 ++-- ...sd-client.pom => java-dogstatsd-client.pom | 0 .../statsd/NonBlockingStatsDClient.java | 16 +++++++++++---- .../statsd/NonBlockingStatsDClientTest.java | 20 +++++++++++++++++++ 4 files changed, 34 insertions(+), 6 deletions(-) rename java-statsd-client.pom => java-dogstatsd-client.pom (100%) diff --git a/build.xml b/build.xml index 3819c20..5975c61 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - + - + diff --git a/java-statsd-client.pom b/java-dogstatsd-client.pom similarity index 100% rename from java-statsd-client.pom rename to java-dogstatsd-client.pom diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index f6e0677..1f1c2ab 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -3,6 +3,7 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; +import java.text.NumberFormat; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -41,6 +42,13 @@ public final class NonBlockingStatsDClient implements StatsDClient { @Override public void handle(Exception e) { /* No-op */ } }; + private static final NumberFormat FORMAT; + static { + FORMAT = java.text.NumberFormat.getInstance(); + FORMAT.setGroupingUsed(false); + FORMAT.setMaximumFractionDigits(6); + } + private final String prefix; private final DatagramSocket clientSocket; private final StatsDClientErrorHandler handler; @@ -288,7 +296,7 @@ public void decrement(String aspect) { public void recordGaugeValue(String aspect, double value, String[] tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|g%s", prefix, aspect, value, tagString(tags))); + send(String.format("%s%s:%s|g%s", prefix, aspect, FORMAT.format(value), tagString(tags))); } /** @@ -305,7 +313,7 @@ public void recordGaugeValue(String aspect, double value, String[] tags) { public void recordGaugeValue(String aspect, double value) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|g", prefix, aspect, value)); + send(String.format("%s%s:%s|g", prefix, aspect, FORMAT.format(value))); } /** @@ -437,7 +445,7 @@ public void time(String aspect, int value) { public void recordHistogramValue(String aspect, double value, String[] tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|h%s", prefix, aspect, value, tagString(tags))); + send(String.format("%s%s:%s|h%s", prefix, aspect, FORMAT.format(value), tagString(tags))); } /** @@ -454,7 +462,7 @@ public void recordHistogramValue(String aspect, double value, String[] tags) { public void recordHistogramValue(String aspect, double value) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|h", prefix, aspect, value)); + send(String.format("%s%s:%s|h", prefix, aspect, FORMAT.format(value))); } /** diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 70ec755..d42f92b 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -112,6 +112,26 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mygauge:423|g")); } + @Test(timeout=5000L) public void + sends_large_double_gauge_to_statsd() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordGaugeValue("mygauge", 123456789012345.67890); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:123456789012345.67|g")); + } + + @Test(timeout=5000L) public void + sends_exact_double_gauge_to_statsd() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordGaugeValue("mygauge", 123.45678901234567890); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:123.456789|g")); + } + @Test(timeout=5000L) public void sends_double_gauge_to_statsd() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); From 27e56edf1359d15dede6826585252b31fd61f3a8 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Wed, 5 Dec 2012 11:16:05 -0600 Subject: [PATCH 05/69] Move from Ant to Maven --- build.xml | 98 --------------------------------------- java-dogstatsd-client.pom | 34 -------------- pom.xml | 88 +++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 132 deletions(-) delete mode 100644 build.xml delete mode 100644 java-dogstatsd-client.pom create mode 100644 pom.xml diff --git a/build.xml b/build.xml deleted file mode 100644 index 5975c61..0000000 --- a/build.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java-dogstatsd-client.pom b/java-dogstatsd-client.pom deleted file mode 100644 index 7a5eb63..0000000 --- a/java-dogstatsd-client.pom +++ /dev/null @@ -1,34 +0,0 @@ - - 4.0.0 - com.indeed - java-dogstatsd-client - jar - java-dogstatsd-client - @VERSION@ - A tiny library allowing Java applications to communicate with DataDog statsd instances easily. - https://github.com/indeedeng/java-dogstatsd-client - - - The MIT License (MIT) - http://opensource.org/licenses/MIT - repo - - - - http://github.com/indeedeng/java-dogstatsd-client - scm:git:git://github.com/indeedeng/java-dogstatsd-client.git - scm:git:git@github.com:indeedeng/java-dogstatsd-client.git - - - - duffy - Charles Duffy - duffy@indeed.com - - - scarytom - Tom Denley - tom.denley@timgroup.com - - - diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..7cf4282 --- /dev/null +++ b/pom.xml @@ -0,0 +1,88 @@ + + 4.0.0 + com.indeed + java-dogstatsd-client + jar + java-dogstatsd-client + 2.0.5-SNAPSHOT + A tiny library allowing Java applications to communicate with DataDog statsd instances easily. + https://github.com/indeedeng/java-dogstatsd-client + + 1.6 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9 + + + attach-javadocs + + jar + + + + + + + + org.sonatype.oss + oss-parent + 7 + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + repo + + + + http://github.com/indeedeng/java-dogstatsd-client + scm:git:git://github.com/indeedeng/java-dogstatsd-client.git + scm:git:git@github.com:indeedeng/java-dogstatsd-client.git + + + + duffy + Charles Duffy + duffy@indeed.com + + + scarytom + Tom Denley + tom.denley@timgroup.com + + + + + org.hamcrest + hamcrest-core + 1.3 + test + + + org.hamcrest + hamcrest-library + 1.3 + test + + + junit + junit + 4.10 + test + + + From 2eed16ba5db7b2cd9f05b6b8701e579112fe1cb6 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Wed, 5 Dec 2012 11:22:07 -0600 Subject: [PATCH 06/69] [maven-release-plugin] prepare release 2.0.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7cf4282..c68d903 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,10 @@ - + 4.0.0 com.indeed java-dogstatsd-client jar java-dogstatsd-client - 2.0.5-SNAPSHOT + 2.0.5 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From adb5d9f09ffc37feef8825303b64a6e99b0bb7e5 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Wed, 5 Dec 2012 11:22:14 -0600 Subject: [PATCH 07/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c68d903..f9ddecd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.5 + 2.0.6-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From d01a2ea268cf301ef16b90fb1d3fe5d3f8992ed6 Mon Sep 17 00:00:00 2001 From: Alexander Lobanov Date: Fri, 21 Dec 2012 04:39:31 +0400 Subject: [PATCH 08/69] Changed signature of all methods: argument 'String[] tags' replaced by vararg String: 'String... tags'. Removed unnecessary methods without vararg tags argument. Changed signature of 'time' and 'recordExecutionTime' methods: timeInMs now is long. Removed explicit array creation in test case. --- .../com/timgroup/statsd/NoOpStatsDClient.java | 45 ++-- .../statsd/NonBlockingStatsDClient.java | 208 ++---------------- .../com/timgroup/statsd/StatsDClient.java | 165 ++------------ .../statsd/NonBlockingStatsDClientTest.java | 18 +- 4 files changed, 56 insertions(+), 380 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java index 8653752..5796605 100644 --- a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java @@ -9,34 +9,19 @@ */ public final class NoOpStatsDClient implements StatsDClient { @Override public void stop() { } - @Override public void count(String aspect, int delta, String[] tags) { } - @Override public void count(String aspect, int delta) { } - @Override public void incrementCounter(String aspect, String[] tags) { } - @Override public void incrementCounter(String aspect) { } - @Override public void increment(String aspect, String[] tags) { } - @Override public void increment(String aspect) { } - @Override public void decrementCounter(String aspect, String[] tags) { } - @Override public void decrementCounter(String aspect) { } - @Override public void decrement(String aspect, String[] tags) { } - @Override public void decrement(String aspect) { } - @Override public void recordGaugeValue(String aspect, double value, String[] tags) { } - @Override public void recordGaugeValue(String aspect, double value) { } - @Override public void gauge(String aspect, double value, String[] tags) { } - @Override public void gauge(String aspect, double value) { } - @Override public void recordGaugeValue(String aspect, int value, String[] tags) { } - @Override public void recordGaugeValue(String aspect, int value) { } - @Override public void gauge(String aspect, int value, String[] tags) { } - @Override public void gauge(String aspect, int value) { } - @Override public void recordExecutionTime(String aspect, int timeInMs, String[] tags) { } - @Override public void recordExecutionTime(String aspect, int timeInMs) { } - @Override public void time(String aspect, int value, String[] tags) { } - @Override public void time(String aspect, int value) { } - @Override public void recordHistogramValue(String aspect, double value, String[] tags) { } - @Override public void recordHistogramValue(String aspect, double value) { } - @Override public void histogram(String aspect, double value, String[] tags) { } - @Override public void histogram(String aspect, double value) { } - @Override public void recordHistogramValue(String aspect, int value, String[] tags) { } - @Override public void recordHistogramValue(String aspect, int value) { } - @Override public void histogram(String aspect, int value, String[] tags) { } - @Override public void histogram(String aspect, int value) { } + @Override public void count(String aspect, int delta, String... tags) { } + @Override public void incrementCounter(String aspect, String... tags) { } + @Override public void increment(String aspect, String... tags) { } + @Override public void decrementCounter(String aspect, String... tags) { } + @Override public void decrement(String aspect, String... tags) { } + @Override public void recordGaugeValue(String aspect, double value, String... tags) { } + @Override public void gauge(String aspect, double value, String... tags) { } + @Override public void recordGaugeValue(String aspect, int value, String... tags) { } + @Override public void gauge(String aspect, int value, String... tags) { } + @Override public void recordExecutionTime(String aspect, long timeInMs, String... tags) { } + @Override public void time(String aspect, long value, String... tags) { } + @Override public void recordHistogramValue(String aspect, double value, String... tags) { } + @Override public void histogram(String aspect, double value, String... tags) { } + @Override public void recordHistogramValue(String aspect, int value, String... tags) { } + @Override public void histogram(String aspect, int value, String... tags) { } } diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 1f1c2ab..055a2ab 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -173,25 +173,10 @@ String tagString(String[] tags) { * array of tags to be added to the data */ @Override - public void count(String aspect, int delta, String[] tags) { + public void count(String aspect, int delta, String... tags) { send(String.format("%s%s:%d|c%s", prefix, aspect, delta, tagString(tags))); } - /** - * Adjusts the specified counter by a given delta. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the counter to adjust - * @param delta - * the amount to adjust the counter by - */ - @Override - public void count(String aspect, int delta) { - send(String.format("%s%s:%d|c", prefix, aspect, delta)); - } - /** * Increments the specified counter by one. * @@ -203,39 +188,18 @@ public void count(String aspect, int delta) { * array of tags to be added to the data */ @Override - public void incrementCounter(String aspect, String[] tags) { + public void incrementCounter(String aspect, String... tags) { count(aspect, 1, tags); } - /** - * Increments the specified counter by one. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the counter to increment - */ - @Override - public void incrementCounter(String aspect) { - count(aspect, 1); - } - /** * Convenience method equivalent to {@link #incrementCounter(String, String[])}. */ @Override - public void increment(String aspect, String[] tags) { + public void increment(String aspect, String... tags) { incrementCounter(aspect, tags); } - /** - * Convenience method equivalent to {@link #incrementCounter(String)}. - */ - @Override - public void increment(String aspect) { - incrementCounter(aspect); - } - /** * Decrements the specified counter by one. * @@ -247,39 +211,18 @@ public void increment(String aspect) { * array of tags to be added to the data */ @Override - public void decrementCounter(String aspect, String[] tags) { + public void decrementCounter(String aspect, String... tags) { count(aspect, -1, tags); } - /** - * Decrements the specified counter by one. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the counter to decrement - */ - @Override - public void decrementCounter(String aspect) { - count(aspect, -1); - } - /** * Convenience method equivalent to {@link #decrementCounter(String, String[])}. */ @Override - public void decrement(String aspect, String[] tags) { + public void decrement(String aspect, String... tags) { decrementCounter(aspect, tags); } - /** - * Convenience method equivalent to {@link #decrementCounter(String)}. - */ - @Override - public void decrement(String aspect) { - decrementCounter(aspect); - } - /** * Records the latest fixed value for the specified named gauge. * @@ -293,45 +236,20 @@ public void decrement(String aspect) { * array of tags to be added to the data */ @Override - public void recordGaugeValue(String aspect, double value, String[] tags) { + public void recordGaugeValue(String aspect, double value, String... tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ send(String.format("%s%s:%s|g%s", prefix, aspect, FORMAT.format(value), tagString(tags))); } - /** - * Records the latest fixed value for the specified named gauge. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the gauge - * @param value - * the new reading of the gauge - */ - @Override - public void recordGaugeValue(String aspect, double value) { - /* Intentionally using %s rather than %f here to avoid - * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|g", prefix, aspect, FORMAT.format(value))); - } - /** * Convenience method equivalent to {@link #recordGaugeValue(String, double, String[])}. */ @Override - public void gauge(String aspect, double value, String[] tags) { + public void gauge(String aspect, double value, String... tags) { recordGaugeValue(aspect, value, tags); } - /** - * Convenience method equivalent to {@link #recordGaugeValue(String, double)}. - */ - @Override - public void gauge(String aspect, double value) { - recordGaugeValue(aspect, value); - } - /** * Records the latest fixed value for the specified named gauge. @@ -346,41 +264,18 @@ public void gauge(String aspect, double value) { * array of tags to be added to the data */ @Override - public void recordGaugeValue(String aspect, int value, String[] tags) { + public void recordGaugeValue(String aspect, int value, String... tags) { send(String.format("%s%s:%d|g%s", prefix, aspect, value, tagString(tags))); } - /** - * Records the latest fixed value for the specified named gauge. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the gauge - * @param value - * the new reading of the gauge - */ - @Override - public void recordGaugeValue(String aspect, int value) { - send(String.format("%s%s:%d|g", prefix, aspect, value)); - } - /** * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. */ @Override - public void gauge(String aspect, int value, String[] tags) { + public void gauge(String aspect, int value, String... tags) { recordGaugeValue(aspect, value, tags); } - /** - * Convenience method equivalent to {@link #recordGaugeValue(String, int)}. - */ - @Override - public void gauge(String aspect, int value) { - recordGaugeValue(aspect, value); - } - /** * Records an execution time in milliseconds for the specified named operation. * @@ -394,41 +289,18 @@ public void gauge(String aspect, int value) { * array of tags to be added to the data */ @Override - public void recordExecutionTime(String aspect, int timeInMs, String[] tags) { + public void recordExecutionTime(String aspect, long timeInMs, String... tags) { send(String.format("%s%s:%d|ms%s", prefix, aspect, timeInMs, tagString(tags))); } /** - * Records an execution time in milliseconds for the specified named operation. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the timed operation - * @param timeInMs - * the time in milliseconds + * Convenience method equivalent to {@link #recordExecutionTime(String, long, String[])}. */ @Override - public void recordExecutionTime(String aspect, int timeInMs) { - send(String.format("%s%s:%d|ms", prefix, aspect, timeInMs)); - } - - /** - * Convenience method equivalent to {@link #recordExecutionTime(String, int, String[])}. - */ - @Override - public void time(String aspect, int value, String[] tags) { + public void time(String aspect, long value, String... tags) { recordExecutionTime(aspect, value, tags); } - /** - * Convenience method equivalent to {@link #recordExecutionTime(String, int)}. - */ - @Override - public void time(String aspect, int value) { - recordExecutionTime(aspect, value); - } - /** * Records a value for the specified named histogram. * @@ -442,45 +314,20 @@ public void time(String aspect, int value) { * array of tags to be added to the data */ @Override - public void recordHistogramValue(String aspect, double value, String[] tags) { + public void recordHistogramValue(String aspect, double value, String... tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ send(String.format("%s%s:%s|h%s", prefix, aspect, FORMAT.format(value), tagString(tags))); } - /** - * Records a value for the specified named histogram. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the histogram - * @param value - * the value to be incorporated in the histogram - */ - @Override - public void recordHistogramValue(String aspect, double value) { - /* Intentionally using %s rather than %f here to avoid - * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|h", prefix, aspect, FORMAT.format(value))); - } - /** * Convenience method equivalent to {@link #recordHistogramValue(String, double, String[])}. */ @Override - public void histogram(String aspect, double value, String[] tags) { + public void histogram(String aspect, double value, String... tags) { recordHistogramValue(aspect, value, tags); } - /** - * Convenience method equivalent to {@link #recordHistogramValue(String, double, String[])}. - */ - @Override - public void histogram(String aspect, double value) { - recordHistogramValue(aspect, value); - } - /** * Records a value for the specified named histogram. * @@ -494,41 +341,18 @@ public void histogram(String aspect, double value) { * array of tags to be added to the data */ @Override - public void recordHistogramValue(String aspect, int value, String[] tags) { + public void recordHistogramValue(String aspect, int value, String... tags) { send(String.format("%s%s:%d|h%s", prefix, aspect, value, tagString(tags))); } - /** - * Records a value for the specified named histogram. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the histogram - * @param value - * the value to be incorporated in the histogram - */ - @Override - public void recordHistogramValue(String aspect, int value) { - send(String.format("%s%s:%d|h", prefix, aspect, value)); - } - /** * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. */ @Override - public void histogram(String aspect, int value, String[] tags) { + public void histogram(String aspect, int value, String... tags) { recordHistogramValue(aspect, value, tags); } - /** - * Convenience method equivalent to {@link #recordHistogramValue(String, int)}. - */ - @Override - public void histogram(String aspect, int value) { - recordHistogramValue(aspect, value); - } - private void send(final String message) { try { executor.execute(new Runnable() { diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index fef3268..79c69e7 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -37,19 +37,7 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void count(String aspect, int delta, String[] tags); - - /** - * Adjusts the specified counter by a given delta. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the counter to adjust - * @param delta - * the amount to adjust the counter by - */ - void count(String aspect, int delta); + void count(String aspect, int delta, String... tags); /** * Increments the specified counter by one. @@ -63,27 +51,12 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void incrementCounter(String aspect, String[] tags); - - /** - * Increments the specified counter by one. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the counter to increment - */ - void incrementCounter(String aspect); + void incrementCounter(String aspect, String... tags); /** * Convenience method equivalent to {@link #incrementCounter(String, String[])}. */ - void increment(String aspect, String[] tags); - - /** - * Convenience method equivalent to {@link #incrementCounter(String)}. - */ - void increment(String aspect); + void increment(String aspect, String... tags); /** * Decrements the specified counter by one. @@ -97,27 +70,12 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void decrementCounter(String aspect, String[] tags); - - /** - * Decrements the specified counter by one. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the counter to decrement - */ - void decrementCounter(String aspect); - - /** - * Convenience method equivalent to {@link #decrementCounter(String)}. - */ - void decrement(String aspect); + void decrementCounter(String aspect, String... tags); /** * Convenience method equivalent to {@link #decrementCounter(String, String[])}. */ - void decrement(String aspect, String[] tags); + void decrement(String aspect, String... tags); /** * Records the latest fixed value for the specified named gauge. @@ -131,31 +89,12 @@ public interface StatsDClient { * @param value * the new reading of the gauge */ - void recordGaugeValue(String aspect, double value, String[] tags); - - /** - * Records the latest fixed value for the specified named gauge. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the gauge - * @param value - * the new reading of the gauge - */ - void recordGaugeValue(String aspect, double value); - + void recordGaugeValue(String aspect, double value, String... tags); /** * Convenience method equivalent to {@link #recordGaugeValue(String, double, String[])}. */ - void gauge(String aspect, double value, String[] tags); - - /** - * Convenience method equivalent to {@link #recordGaugeValue(String, double)}. - */ - void gauge(String aspect, double value); - + void gauge(String aspect, double value, String... tags); /** * Records the latest fixed value for the specified named gauge. @@ -169,30 +108,12 @@ public interface StatsDClient { * @param value * the new reading of the gauge */ - void recordGaugeValue(String aspect, int value, String[] tags); - - /** - * Records the latest fixed value for the specified named gauge. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the gauge - * @param value - * the new reading of the gauge - */ - void recordGaugeValue(String aspect, int value); - + void recordGaugeValue(String aspect, int value, String... tags); /** * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. */ - void gauge(String aspect, int value, String[] tags); - - /** - * Convenience method equivalent to {@link #recordGaugeValue(String, int)}. - */ - void gauge(String aspect, int value); + void gauge(String aspect, int value, String... tags); /** * Records an execution time in milliseconds for the specified named operation. @@ -208,29 +129,12 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void recordExecutionTime(String aspect, int timeInMs, String[] tags); - - /** - * Records an execution time in milliseconds for the specified named operation. - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the timed operation - * @param timeInMs - * the time in milliseconds - */ - void recordExecutionTime(String aspect, int timeInMs); + void recordExecutionTime(String aspect, long timeInMs, String... tags); /** - * Convenience method equivalent to {@link #recordExecutionTime(String, int, String[])}. + * Convenience method equivalent to {@link #recordExecutionTime(String, long, String[])}. */ - void time(String aspect, int value, String[] tags); - - /** - * Convenience method equivalent to {@link #recordExecutionTime(String, int)}. - */ - void time(String aspect, int value); + void time(String aspect, long value, String... tags); /** * Records a value for the specified named histogram. @@ -246,31 +150,12 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void recordHistogramValue(String aspect, double value, String[] tags); - - /** - * Records a value for the specified named histogram. - * - *

    This method is a DataDog extension, and may not work with other servers.

    - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the histogram - * @param value - * the value to be incorporated in the histogram - */ - void recordHistogramValue(String aspect, double value); + void recordHistogramValue(String aspect, double value, String... tags); /** * Convenience method equivalent to {@link #recordHistogramValue(String, double, String[])}. */ - void histogram(String aspect, double value, String[] tags); - - /** - * Convenience method equivalent to {@link #recordHistogramValue(String, double)}. - */ - void histogram(String aspect, double value); + void histogram(String aspect, double value, String... tags); /** * Records a value for the specified named histogram. @@ -286,29 +171,11 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void recordHistogramValue(String aspect, int value, String[] tags); - - /** - * Records a value for the specified named histogram. - * - *

    This method is a DataDog extension, and may not work with other servers.

    - * - *

    This method is non-blocking and is guaranteed not to throw an exception.

    - * - * @param aspect - * the name of the histogram - * @param value - * the value to be incorporated in the histogram - */ - void recordHistogramValue(String aspect, int value); + void recordHistogramValue(String aspect, int value, String... tags); /** * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. */ - void histogram(String aspect, int value, String[] tags); + void histogram(String aspect, int value, String... tags); - /** - * Convenience method equivalent to {@link #recordHistogramValue(String, int)}. - */ - void histogram(String aspect, int value); } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index d42f92b..61b051f 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -46,7 +46,7 @@ public void stop() throws Exception { sends_counter_value_to_statsd_with_empty_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.count("mycount", 24, new String[]{}); + client.count("mycount", 24); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); @@ -56,7 +56,7 @@ public void stop() throws Exception { sends_counter_value_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.count("mycount", 24, new String[]{"foo:bar","baz"}); + client.count("mycount", 24, "foo:bar","baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c|#baz,foo:bar")); @@ -76,7 +76,7 @@ public void stop() throws Exception { sends_counter_increment_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.incrementCounter("myinc", new String[]{"foo:bar","baz"}); + client.incrementCounter("myinc", "foo:bar","baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.myinc:1|c|#baz,foo:bar")); @@ -96,7 +96,7 @@ public void stop() throws Exception { sends_counter_decrement_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.decrementCounter("mydec", new String[]{"foo:bar", "baz"}); + client.decrementCounter("mydec", "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mydec:-1|c|#baz,foo:bar")); @@ -146,7 +146,7 @@ public void stop() throws Exception { sends_gauge_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordGaugeValue("mygauge", 423, new String[]{"foo:bar","baz"}); + client.recordGaugeValue("mygauge", 423, "foo:bar","baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mygauge:423|g|#baz,foo:bar")); @@ -156,7 +156,7 @@ public void stop() throws Exception { sends_double_gauge_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordGaugeValue("mygauge", 0.423, new String[]{"foo:bar","baz"}); + client.recordGaugeValue("mygauge", 0.423, "foo:bar","baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mygauge:0.423|g|#baz,foo:bar")); @@ -186,7 +186,7 @@ public void stop() throws Exception { sends_histogram_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordHistogramValue("myhistogram", 423, new String[]{"foo:bar","baz"}); + client.recordHistogramValue("myhistogram", 423, "foo:bar","baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:423|h|#baz,foo:bar")); @@ -196,7 +196,7 @@ public void stop() throws Exception { sends_double_histogram_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordHistogramValue("myhistogram", 0.423, new String[]{"foo:bar","baz"}); + client.recordHistogramValue("myhistogram", 0.423, "foo:bar","baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:0.423|h|#baz,foo:bar")); @@ -216,7 +216,7 @@ public void stop() throws Exception { sends_timer_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordExecutionTime("mytime", 123, new String[]{"foo:bar","baz"}); + client.recordExecutionTime("mytime", 123, "foo:bar","baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms|#baz,foo:bar")); From 08ad3919340fe5665ce20922dbde1c7499c7868c Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Fri, 11 Jan 2013 18:56:44 -0600 Subject: [PATCH 09/69] Move README to point to 2.0.5 as last release --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f563d0..f6e83af 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The client jar is distributed via maven central, and can be downloaded [here](ht com.indeed java-dogstatsd-client - 2.0.2 + 2.0.5 ``` From 18955c3fb01dfed21feef6186139150ada85480f Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Fri, 11 Jan 2013 19:02:09 -0600 Subject: [PATCH 10/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f9ddecd..37d9a3c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.6-SNAPSHOT + 2.0.6 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 898bf676a1a51d454ec8551147d3cb3bd75c24e5 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Fri, 11 Jan 2013 19:02:12 -0600 Subject: [PATCH 11/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 37d9a3c..391cbc7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.6 + 2.0.7-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From c5a0ef4967a790ccf44d995ae7e721816ba2c35b Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Tue, 15 Jan 2013 17:38:07 -0600 Subject: [PATCH 12/69] Update README to reflect new usage; fix whitespace to conform with convention --- README.md | 2 +- .../statsd/NonBlockingStatsDClientTest.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f6e83af..9184dc9 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ public class Foo { statsd.incrementCounter("foo"); statsd.recordGaugeValue("bar", 100); statsd.recordGaugeValue("baz", 0.01); /* DataDog extension: support for floating-point gauges */ - statsd.recordExecutionTime("bag", 25, {"cluster:foo"}); /* DataDog extension: cluster tag */ + statsd.recordExecutionTime("bag", 25, "cluster:foo"); /* DataDog extension: cluster tag */ statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ statsd.recordHistogram("qux", 15.5) /* ...also floating-point */ } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 61b051f..5c1ba07 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -56,7 +56,7 @@ public void stop() throws Exception { sends_counter_value_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.count("mycount", 24, "foo:bar","baz"); + client.count("mycount", 24, "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c|#baz,foo:bar")); @@ -76,7 +76,7 @@ public void stop() throws Exception { sends_counter_increment_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.incrementCounter("myinc", "foo:bar","baz"); + client.incrementCounter("myinc", "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.myinc:1|c|#baz,foo:bar")); @@ -146,7 +146,7 @@ public void stop() throws Exception { sends_gauge_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordGaugeValue("mygauge", 423, "foo:bar","baz"); + client.recordGaugeValue("mygauge", 423, "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mygauge:423|g|#baz,foo:bar")); @@ -156,7 +156,7 @@ public void stop() throws Exception { sends_double_gauge_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordGaugeValue("mygauge", 0.423, "foo:bar","baz"); + client.recordGaugeValue("mygauge", 0.423, "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mygauge:0.423|g|#baz,foo:bar")); @@ -186,7 +186,7 @@ public void stop() throws Exception { sends_histogram_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordHistogramValue("myhistogram", 423, "foo:bar","baz"); + client.recordHistogramValue("myhistogram", 423, "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:423|h|#baz,foo:bar")); @@ -196,7 +196,7 @@ public void stop() throws Exception { sends_double_histogram_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordHistogramValue("myhistogram", 0.423, "foo:bar","baz"); + client.recordHistogramValue("myhistogram", 0.423, "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.myhistogram:0.423|h|#baz,foo:bar")); @@ -216,7 +216,7 @@ public void stop() throws Exception { sends_timer_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.recordExecutionTime("mytime", 123, "foo:bar","baz"); + client.recordExecutionTime("mytime", 123, "foo:bar", "baz"); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms|#baz,foo:bar")); From dcaed45c36ef74ba370d806647a4a06b173a9566 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 11 Feb 2013 13:19:23 -0600 Subject: [PATCH 13/69] Constant tags; compatibility with non-datadog recordExecutionTime - Add support for initialization-time constant tag list (similar use case to constant prefix). - Convert millisecond times to floating-point histogram type for compatibility with upstream semantics. --- README.md | 17 ++++- .../statsd/NonBlockingStatsDClient.java | 66 +++++++++++++++---- .../statsd/NonBlockingStatsDClientTest.java | 26 +++++++- 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9184dc9..d6d0ee9 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,26 @@ import com.timgroup.statsd.StatsDClient; import com.timgroup.statsd.NonBlockingStatsDClient; public class Foo { - private static final StatsDClient statsd = new NonBlockingStatsDClient("my.prefix", "statsd-host", 8125); + + private static final StatsDClient statsd = new NonBlockingStatsDClient( + "my.prefix", /* prefix to any stats; may be null or empty string */ + "statsd-host", /* common case: localhost */ + 8125, /* port */ + new String[] {"tag:value"} /* DataDog extension: Constant tags, always applied */ + ); public static final void main(String[] args) { statsd.incrementCounter("foo"); statsd.recordGaugeValue("bar", 100); statsd.recordGaugeValue("baz", 0.01); /* DataDog extension: support for floating-point gauges */ + statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ + statsd.recordHistogram("qux", 15.5) /* ...also floating-point */ + + /* Compatibility note: Unlike upstream statsd, DataDog expects execution times to be a + * floating-point value in seconds, not a millisecond value. This library + * does the conversion from ms to fractional seconds. + */ statsd.recordExecutionTime("bag", 25, "cluster:foo"); /* DataDog extension: cluster tag */ - statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ - statsd.recordHistogram("qux", 15.5) /* ...also floating-point */ } } ``` diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 055a2ab..44a9b29 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -52,6 +52,7 @@ public final class NonBlockingStatsDClient implements StatsDClient { private final String prefix; private final DatagramSocket clientSocket; private final StatsDClientErrorHandler handler; + private final String[] constantTags; private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() { final ThreadFactory delegate = Executors.defaultThreadFactory(); @@ -71,7 +72,7 @@ public final class NonBlockingStatsDClient implements StatsDClient { * be established. Once a client has been instantiated in this way, all * exceptions thrown during subsequent usage are consumed, guaranteeing * that failures in metrics will not affect normal code execution. - * + * * @param prefix * the prefix to apply to keys sent via this client * @param hostname @@ -82,9 +83,34 @@ public final class NonBlockingStatsDClient implements StatsDClient { * if the client could not be started */ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws StatsDClientException { - this(prefix, hostname, port, NO_OP_HANDLER); + this(prefix, hostname, port, null, NO_OP_HANDLER); + } + + /** + * Create a new StatsD client communicating with a StatsD instance on the + * specified host and port. All messages send via this client will have + * their keys prefixed with the specified string. The new client will + * attempt to open a connection to the StatsD server immediately upon + * instantiation, and may throw an exception if that a connection cannot + * be established. Once a client has been instantiated in this way, all + * exceptions thrown during subsequent usage are consumed, guaranteeing + * that failures in metrics will not affect normal code execution. + * + * @param prefix + * the prefix to apply to keys sent via this client + * @param hostname + * the host name of the targeted StatsD server + * @param port + * the port of the targeted StatsD server + * @param constantTags + * tags to be added to all content sent + * @throws StatsDClientException + * if the client could not be started + */ + public NonBlockingStatsDClient(String prefix, String hostname, int port, String[] constantTags) throws StatsDClientException { + this(prefix, hostname, port, constantTags, NO_OP_HANDLER); } - + /** * Create a new StatsD client communicating with a StatsD instance on the * specified host and port. All messages send via this client will have @@ -102,19 +128,25 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws * the host name of the targeted StatsD server * @param port * the port of the targeted StatsD server + * @param constantTags + * tags to be added to all content sent * @param errorHandler * handler to use when an exception occurs during usage * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(String prefix, String hostname, int port, StatsDClientErrorHandler errorHandler) throws StatsDClientException { + public NonBlockingStatsDClient(String prefix, String hostname, int port, String[] constantTags, StatsDClientErrorHandler errorHandler) throws StatsDClientException { if(prefix != null && prefix.length() > 0) { this.prefix = String.format("%s.", prefix); } else { this.prefix = ""; } this.handler = errorHandler; - + if(constantTags != null && constantTags.length == 0) { + constantTags = null; + } + this.constantTags = constantTags; + try { this.clientSocket = new DatagramSocket(); this.clientSocket.connect(new InetSocketAddress(hostname, port)); @@ -147,14 +179,26 @@ public void stop() { * Generate a suffix conveying the given tag list to the client */ String tagString(String[] tags) { - if(tags == null || tags.length == 0) { + boolean have_call_tags = (tags != null && tags.length > 0); + boolean have_constant_tags = (constantTags != null && constantTags.length > 0); + if(!have_call_tags && !have_constant_tags) { return ""; } StringBuilder sb = new StringBuilder("|#"); - for(int n=tags.length - 1; n>=0; n--) { - sb.append(tags[n]); - if(n > 0) { - sb.append(","); + if(have_constant_tags) { + for(int n=constantTags.length - 1; n>=0; n--) { + sb.append(constantTags[n]); + if(n > 0 || have_call_tags) { + sb.append(","); + } + } + } + if (have_call_tags) { + for(int n=tags.length - 1; n>=0; n--) { + sb.append(tags[n]); + if(n > 0) { + sb.append(","); + } } } return sb.toString(); @@ -290,7 +334,7 @@ public void gauge(String aspect, int value, String... tags) { */ @Override public void recordExecutionTime(String aspect, long timeInMs, String... tags) { - send(String.format("%s%s:%d|ms%s", prefix, aspect, timeInMs, tagString(tags))); + recordHistogramValue(aspect, (timeInMs * 0.001), tags); } /** diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 5c1ba07..eb96a91 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -36,7 +36,7 @@ public void stop() throws Exception { sends_counter_value_to_statsd_with_null_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - client.count("mycount", 24, null); + client.count("mycount", 24, (java.lang.String[]) null); server.waitForMessage(); assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); @@ -209,7 +209,7 @@ public void stop() throws Exception { client.recordExecutionTime("mytime", 123); server.waitForMessage(); - assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms")); + assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h")); } @Test(timeout=5000L) public void @@ -219,10 +219,30 @@ public void stop() throws Exception { client.recordExecutionTime("mytime", 123, "foo:bar", "baz"); server.waitForMessage(); - assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms|#baz,foo:bar")); + assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h|#baz,foo:bar")); } + @Test(timeout=5000L) public void + sends_gauge_mixed_tags() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, new String[] {"instance:foo", "app:bar"}); + empty_prefix_client.gauge("value", 423, "baz"); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.value:423|g|#app:bar,instance:foo,baz")); + } + + @Test(timeout=5000L) public void + sends_gauge_constant_tags_only() throws Exception { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, new String[] {"instance:foo", "app:bar"}); + empty_prefix_client.gauge("value", 423); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.value:423|g|#app:bar,instance:foo")); + } + @Test(timeout=5000L) public void sends_gauge_empty_prefix() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); From f2d16f6c6b20c4ab4b50c799947a1ea7319ec7f4 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 11 Feb 2013 13:29:55 -0600 Subject: [PATCH 14/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 391cbc7..9aa9efd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.7-SNAPSHOT + 2.0.7 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 4c8bc1e9f07cce72fd2042d6adc65d5d0b96185e Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 11 Feb 2013 13:30:01 -0600 Subject: [PATCH 15/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9aa9efd..cd018e9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.7 + 2.0.8-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 4b2322673c69d7d77b4e19f104e7bd0c9f254b56 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 11 Feb 2013 13:41:05 -0600 Subject: [PATCH 16/69] Update README to point to new release --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6d0ee9..3d6842e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The client jar is distributed via maven central, and can be downloaded [here](ht com.indeed java-dogstatsd-client - 2.0.5 + 2.0.7 ``` From 2807100b00fc6ec581642234a277c0967de88103 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 18 Feb 2013 12:26:39 -0600 Subject: [PATCH 17/69] Pre-render constant tags --- .../statsd/NonBlockingStatsDClient.java | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 44a9b29..148de49 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -52,7 +52,7 @@ public final class NonBlockingStatsDClient implements StatsDClient { private final String prefix; private final DatagramSocket clientSocket; private final StatsDClientErrorHandler handler; - private final String[] constantTags; + private final String constantTagsRendered; private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() { final ThreadFactory delegate = Executors.defaultThreadFactory(); @@ -142,10 +142,17 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port, String[ this.prefix = ""; } this.handler = errorHandler; + + /* Empty list should be null for faster comparison */ if(constantTags != null && constantTags.length == 0) { constantTags = null; } - this.constantTags = constantTags; + + if(constantTags != null) { + this.constantTagsRendered = tagString(constantTags, null); + } else { + this.constantTagsRendered = null; + } try { this.clientSocket = new DatagramSocket(); @@ -178,32 +185,37 @@ public void stop() { /** * Generate a suffix conveying the given tag list to the client */ - String tagString(String[] tags) { - boolean have_call_tags = (tags != null && tags.length > 0); - boolean have_constant_tags = (constantTags != null && constantTags.length > 0); - if(!have_call_tags && !have_constant_tags) { - return ""; - } - StringBuilder sb = new StringBuilder("|#"); - if(have_constant_tags) { - for(int n=constantTags.length - 1; n>=0; n--) { - sb.append(constantTags[n]); - if(n > 0 || have_call_tags) { - sb.append(","); - } + static String tagString(final String[] tags, final String tagPrefix) { + StringBuilder sb; + if(tagPrefix != null) { + if(tags == null || tags.length == 0) { + return tagPrefix; + } + sb = new StringBuilder(tagPrefix); + sb.append(","); + } else { + if(tags == null || tags.length == 0) { + return ""; } + sb = new StringBuilder("|#"); } - if (have_call_tags) { - for(int n=tags.length - 1; n>=0; n--) { - sb.append(tags[n]); - if(n > 0) { - sb.append(","); - } + + for(int n=tags.length - 1; n>=0; n--) { + sb.append(tags[n]); + if(n > 0) { + sb.append(","); } } return sb.toString(); } + /** + * Generate a suffix conveying the given tag list to the client + */ + String tagString(final String[] tags) { + return tagString(tags, constantTagsRendered); + } + /** * Adjusts the specified counter by a given delta. * From af79a44a7fd8bc8a2aa16d6d65d08b524220261d Mon Sep 17 00:00:00 2001 From: Aleksey Nikiforov Date: Wed, 12 Jun 2013 18:27:05 -0300 Subject: [PATCH 18/69] NonBlockingStatsDClient as a daemon thread. Simplify life-cycle management of NonBlockingStatsDClient by running send() in a daemon thread. --- src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 148de49..ce7bc8d 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -59,6 +59,7 @@ public final class NonBlockingStatsDClient implements StatsDClient { @Override public Thread newThread(Runnable r) { Thread result = delegate.newThread(r); result.setName("StatsD-" + result.getName()); + result.setDaemon(true); return result; } }); From d445d745632fb6f96df366c4cef4b70477a173ba Mon Sep 17 00:00:00 2001 From: Donal Murtagh Date: Mon, 22 Jul 2013 16:25:58 +0200 Subject: [PATCH 19/69] Fix for issues #3 and #4 with regression test for #3 --- .gitignore | 1 + .../statsd/NonBlockingStatsDClient.java | 29 ++++++++++++++----- .../statsd/NonBlockingStatsDClientTest.java | 27 +++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index c745919..5be5047 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ bin build +*.iml \ No newline at end of file diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 148de49..eb25522 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -4,6 +4,7 @@ import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.text.NumberFormat; +import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -42,12 +43,24 @@ public final class NonBlockingStatsDClient implements StatsDClient { @Override public void handle(Exception e) { /* No-op */ } }; - private static final NumberFormat FORMAT; - static { - FORMAT = java.text.NumberFormat.getInstance(); - FORMAT.setGroupingUsed(false); - FORMAT.setMaximumFractionDigits(6); - } + /** + * Because NumberFormat is not thread-safe we cannot share instances across threads. Use a ThreadLocal to + * create one pre thread as this seems to offer a significant performance improvement over creating one per-thread: + * http://stackoverflow.com/a/1285297/2648 + * https://github.com/indeedeng/java-dogstatsd-client/issues/4 + */ + private static final ThreadLocal NUMBER_FORMATTERS = new ThreadLocal() { + @Override + protected NumberFormat initialValue() { + + // Always create the formatter for the US locale in order to avoid this bug: + // https://github.com/indeedeng/java-dogstatsd-client/issues/3 + NumberFormat numberFormatter = NumberFormat.getInstance(Locale.US); + numberFormatter.setGroupingUsed(false); + numberFormatter.setMaximumFractionDigits(6); + return numberFormatter; + } + }; private final String prefix; private final DatagramSocket clientSocket; @@ -295,7 +308,7 @@ public void decrement(String aspect, String... tags) { public void recordGaugeValue(String aspect, double value, String... tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|g%s", prefix, aspect, FORMAT.format(value), tagString(tags))); + send(String.format("%s%s:%s|g%s", prefix, aspect, NUMBER_FORMATTERS.get().format(value), tagString(tags))); } /** @@ -373,7 +386,7 @@ public void time(String aspect, long value, String... tags) { public void recordHistogramValue(String aspect, double value, String... tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ - send(String.format("%s%s:%s|h%s", prefix, aspect, FORMAT.format(value), tagString(tags))); + send(String.format("%s%s:%s|h%s", prefix, aspect, NUMBER_FORMATTERS.get().format(value), tagString(tags))); } /** diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index eb96a91..465777a 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -8,6 +8,7 @@ import java.net.SocketException; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; @@ -212,6 +213,32 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h")); } + /** + * A regression test for this i18n number formatting bug + * @throws Exception + */ + @Test public void + sends_timer_to_statsd_from_locale_with_unamerican_number_formatting() throws Exception { + + Locale originalDefaultLocale = Locale.getDefault(); + + // change the default Locale to one that uses something other than a '.' as the decimal separator (Germany uses a comma) + Locale.setDefault(Locale.GERMANY); + + try { + final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + + client.recordExecutionTime("mytime", 123, "foo:bar", "baz"); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h|#baz,foo:bar")); + } finally { + // reset the default Locale in case changing it has side-effects + Locale.setDefault(originalDefaultLocale); + } + } + + @Test(timeout=5000L) public void sends_timer_to_statsd_with_tags() throws Exception { final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); From 5adaed0f3fa853cb6ca9c6f2867f17724c91177a Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 22 Jul 2013 10:08:22 -0500 Subject: [PATCH 20/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cd018e9..64c6c26 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.8-SNAPSHOT + 2.0.8 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 0d5b521cae180bc89206712c68b984e6f9e7636c Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Mon, 22 Jul 2013 10:08:26 -0500 Subject: [PATCH 21/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 64c6c26..086e4ae 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.8 + 2.0.9-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 985b2725e28ffc7012f501be0696a79d73017576 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Tue, 8 Oct 2013 11:36:46 -0500 Subject: [PATCH 22/69] Normalize POM with other Indeed OSS projects --- pom.xml | 154 +++++++++++++++++++++++++------------------------------- 1 file changed, 68 insertions(+), 86 deletions(-) diff --git a/pom.xml b/pom.xml index 086e4ae..1fb299c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,88 +1,70 @@ - 4.0.0 - com.indeed - java-dogstatsd-client - jar - java-dogstatsd-client - 2.0.9-SNAPSHOT - A tiny library allowing Java applications to communicate with DataDog statsd instances easily. - https://github.com/indeedeng/java-dogstatsd-client - - 1.6 - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.0 - - ${java.version} - ${java.version} - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9 - - - attach-javadocs - - jar - - - - - - - - org.sonatype.oss - oss-parent - 7 - - - - The MIT License (MIT) - http://opensource.org/licenses/MIT - repo - - - - http://github.com/indeedeng/java-dogstatsd-client - scm:git:git://github.com/indeedeng/java-dogstatsd-client.git - scm:git:git@github.com:indeedeng/java-dogstatsd-client.git - - - - duffy - Charles Duffy - duffy@indeed.com - - - scarytom - Tom Denley - tom.denley@timgroup.com - - - - - org.hamcrest - hamcrest-core - 1.3 - test - - - org.hamcrest - hamcrest-library - 1.3 - test - - - junit - junit - 4.10 - test - - + 4.0.0 + + + com.indeed + oss-parent + 5 + + + com.indeed + java-dogstatsd-client + jar + java-dogstatsd-client + 2.0.9-SNAPSHOT + A tiny library allowing Java applications to communicate with DataDog statsd instances easily. + https://github.com/indeedeng/java-dogstatsd-client + + + 1.6 + + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + repo + + + + + http://github.com/indeedeng/java-dogstatsd-client + scm:git:git://github.com/indeedeng/java-dogstatsd-client.git + scm:git:git@github.com:indeedeng/java-dogstatsd-client.git + + + + + duffy + Charles Duffy + duffy@indeed.com + + + scarytom + Tom Denley + tom.denley@timgroup.com + + + + + + org.hamcrest + hamcrest-core + 1.3 + test + + + org.hamcrest + hamcrest-library + 1.3 + test + + + junit + junit + 4.10 + test + + + From 88f4d4ebaa1866ff5ebcd0bf44a0f1c6f6d90a30 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Tue, 8 Oct 2013 11:38:54 -0500 Subject: [PATCH 23/69] rely on library versions from parent pom --- pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pom.xml b/pom.xml index 1fb299c..285be49 100644 --- a/pom.xml +++ b/pom.xml @@ -50,19 +50,16 @@ org.hamcrest hamcrest-core - 1.3 test org.hamcrest hamcrest-library - 1.3 test junit junit - 4.10 test From 73b4c5bdd4604d0f279b74e8c90753a12fb5b8ab Mon Sep 17 00:00:00 2001 From: Alexander Lobanov Date: Sat, 14 Dec 2013 12:49:03 +0400 Subject: [PATCH 24/69] int -> long --- .../com/timgroup/statsd/NoOpStatsDClient.java | 10 +++++----- .../timgroup/statsd/NonBlockingStatsDClient.java | 16 ++++++++-------- .../java/com/timgroup/statsd/StatsDClient.java | 14 +++++++------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java index 5796605..3dbce15 100644 --- a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java @@ -9,19 +9,19 @@ */ public final class NoOpStatsDClient implements StatsDClient { @Override public void stop() { } - @Override public void count(String aspect, int delta, String... tags) { } + @Override public void count(String aspect, long delta, String... tags) { } @Override public void incrementCounter(String aspect, String... tags) { } @Override public void increment(String aspect, String... tags) { } @Override public void decrementCounter(String aspect, String... tags) { } @Override public void decrement(String aspect, String... tags) { } @Override public void recordGaugeValue(String aspect, double value, String... tags) { } @Override public void gauge(String aspect, double value, String... tags) { } - @Override public void recordGaugeValue(String aspect, int value, String... tags) { } - @Override public void gauge(String aspect, int value, String... tags) { } + @Override public void recordGaugeValue(String aspect, long value, String... tags) { } + @Override public void gauge(String aspect, long value, String... tags) { } @Override public void recordExecutionTime(String aspect, long timeInMs, String... tags) { } @Override public void time(String aspect, long value, String... tags) { } @Override public void recordHistogramValue(String aspect, double value, String... tags) { } @Override public void histogram(String aspect, double value, String... tags) { } - @Override public void recordHistogramValue(String aspect, int value, String... tags) { } - @Override public void histogram(String aspect, int value, String... tags) { } + @Override public void recordHistogramValue(String aspect, long value, String... tags) { } + @Override public void histogram(String aspect, long value, String... tags) { } } diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 2584efc..b72849c 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -121,7 +121,7 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(String prefix, String hostname, int port, String[] constantTags) throws StatsDClientException { + public NonBlockingStatsDClient(String prefix, String hostname, int port, String... constantTags) throws StatsDClientException { this(prefix, hostname, port, constantTags, NO_OP_HANDLER); } @@ -243,7 +243,7 @@ String tagString(final String[] tags) { * array of tags to be added to the data */ @Override - public void count(String aspect, int delta, String... tags) { + public void count(String aspect, long delta, String... tags) { send(String.format("%s%s:%d|c%s", prefix, aspect, delta, tagString(tags))); } @@ -334,15 +334,15 @@ public void gauge(String aspect, double value, String... tags) { * array of tags to be added to the data */ @Override - public void recordGaugeValue(String aspect, int value, String... tags) { + public void recordGaugeValue(String aspect, long value, String... tags) { send(String.format("%s%s:%d|g%s", prefix, aspect, value, tagString(tags))); } /** - * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. + * Convenience method equivalent to {@link #recordGaugeValue(String, long, String[])}. */ @Override - public void gauge(String aspect, int value, String... tags) { + public void gauge(String aspect, long value, String... tags) { recordGaugeValue(aspect, value, tags); } @@ -411,15 +411,15 @@ public void histogram(String aspect, double value, String... tags) { * array of tags to be added to the data */ @Override - public void recordHistogramValue(String aspect, int value, String... tags) { + public void recordHistogramValue(String aspect, long value, String... tags) { send(String.format("%s%s:%d|h%s", prefix, aspect, value, tagString(tags))); } /** - * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. + * Convenience method equivalent to {@link #recordHistogramValue(String, long, String[])}. */ @Override - public void histogram(String aspect, int value, String... tags) { + public void histogram(String aspect, long value, String... tags) { recordHistogramValue(aspect, value, tags); } diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index 79c69e7..d231171 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -37,7 +37,7 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void count(String aspect, int delta, String... tags); + void count(String aspect, long delta, String... tags); /** * Increments the specified counter by one. @@ -108,12 +108,12 @@ public interface StatsDClient { * @param value * the new reading of the gauge */ - void recordGaugeValue(String aspect, int value, String... tags); + void recordGaugeValue(String aspect, long value, String... tags); /** - * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. + * Convenience method equivalent to {@link #recordGaugeValue(String, long, String[])}. */ - void gauge(String aspect, int value, String... tags); + void gauge(String aspect, long value, String... tags); /** * Records an execution time in milliseconds for the specified named operation. @@ -171,11 +171,11 @@ public interface StatsDClient { * @param tags * array of tags to be added to the data */ - void recordHistogramValue(String aspect, int value, String... tags); + void recordHistogramValue(String aspect, long value, String... tags); /** - * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. + * Convenience method equivalent to {@link #recordHistogramValue(String, long, String[])}. */ - void histogram(String aspect, int value, String... tags); + void histogram(String aspect, long value, String... tags); } From 5d34f1591b0c8cf7729632586323001ab7962110 Mon Sep 17 00:00:00 2001 From: mck Date: Fri, 7 Mar 2014 13:57:09 +0100 Subject: [PATCH 25/69] performance improvements: - fit as many messages (that are in the queue) into the MTU as possible - convert to NIO In addition to any NIO improvements, this will offer a performance improvement when the incoming message rate per the time it takes to call blockingSend() goes above one. Add NonBlockingStatsDClientPerfTest to ensure no messages are lost in a concurrent environment. --- .../statsd/NonBlockingStatsDClient.java | 138 ++++++++++------ .../timgroup/statsd/DummyStatsDServer.java | 54 +++++++ .../NonBlockingStatsDClientPerfTest.java | 59 +++++++ .../statsd/NonBlockingStatsDClientTest.java | 149 ++++++++---------- 4 files changed, 265 insertions(+), 135 deletions(-) create mode 100644 src/test/java/com/timgroup/statsd/DummyStatsDServer.java create mode 100644 src/test/java/com/timgroup/statsd/NonBlockingStatsDClientPerfTest.java diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 2584efc..6c35d85 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -1,23 +1,26 @@ package com.timgroup.statsd; -import java.net.DatagramPacket; -import java.net.DatagramSocket; +import java.io.IOException; import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; import java.text.NumberFormat; import java.util.Locale; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; /** * A simple StatsD client implementation facilitating metrics recording. - * + * *

    Upon instantiation, this client will establish a socket connection to a StatsD instance * running on the specified host and port. Metrics are then sent over this connection as they are * received by the client. *

    - * + * *

    Three key methods are provided for the submission of data-points for the application under * scrutiny: *

      @@ -30,15 +33,17 @@ * IO operations being carried out in a separate thread. Furthermore, these methods are guaranteed * not to throw an exception which may disrupt application execution. *

      - * + * *

      As part of a clean system shutdown, the {@link #stop()} method should be invoked * on any StatsD clients.

      - * + * * @author Tom Denley * */ public final class NonBlockingStatsDClient implements StatsDClient { + private static final int PACKET_SIZE_BYTES = 1500; + private static final StatsDClientErrorHandler NO_OP_HANDLER = new StatsDClientErrorHandler() { @Override public void handle(Exception e) { /* No-op */ } }; @@ -63,7 +68,8 @@ protected NumberFormat initialValue() { }; private final String prefix; - private final DatagramSocket clientSocket; + private final DatagramChannel clientChannel; + private final InetSocketAddress address; private final StatsDClientErrorHandler handler; private final String constantTagsRendered; @@ -77,6 +83,8 @@ protected NumberFormat initialValue() { } }); + private final BlockingQueue queue = new LinkedBlockingQueue(); + /** * Create a new StatsD client communicating with a StatsD instance on the * specified host and port. All messages send via this client will have @@ -109,7 +117,7 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws * be established. Once a client has been instantiated in this way, all * exceptions thrown during subsequent usage are consumed, guaranteeing * that failures in metrics will not affect normal code execution. - * + * * @param prefix * the prefix to apply to keys sent via this client * @param hostname @@ -135,7 +143,7 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port, String[ * exceptions thrown during subsequent usage are passed to the specified * handler and then consumed, guaranteeing that failures in metrics will * not affect normal code execution. - * + * * @param prefix * the prefix to apply to keys sent via this client * @param hostname @@ -169,11 +177,12 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port, String[ } try { - this.clientSocket = new DatagramSocket(); - this.clientSocket.connect(new InetSocketAddress(hostname, port)); + this.clientChannel = DatagramChannel.open(); + this.address = new InetSocketAddress(hostname, port); } catch (Exception e) { throw new StatsDClientException("Failed to start StatsD client", e); } + this.executor.submit(new QueueConsumer()); } /** @@ -190,8 +199,13 @@ public void stop() { handler.handle(e); } finally { - if (clientSocket != null) { - clientSocket.close(); + if (clientChannel != null) { + try { + clientChannel.close(); + } + catch (IOException e) { + handler.handle(e); + } } } } @@ -232,9 +246,9 @@ String tagString(final String[] tags) { /** * Adjusts the specified counter by a given delta. - * + * *

      This method is non-blocking and is guaranteed not to throw an exception.

      - * + * * @param aspect * the name of the counter to adjust * @param delta @@ -249,9 +263,9 @@ public void count(String aspect, int delta, String... tags) { /** * Increments the specified counter by one. - * + * *

      This method is non-blocking and is guaranteed not to throw an exception.

      - * + * * @param aspect * the name of the counter to increment * @param tags @@ -263,7 +277,7 @@ public void incrementCounter(String aspect, String... tags) { } /** - * Convenience method equivalent to {@link #incrementCounter(String, String[])}. + * Convenience method equivalent to {@link #incrementCounter(String, String[])}. */ @Override public void increment(String aspect, String... tags) { @@ -272,9 +286,9 @@ public void increment(String aspect, String... tags) { /** * Decrements the specified counter by one. - * + * *

      This method is non-blocking and is guaranteed not to throw an exception.

      - * + * * @param aspect * the name of the counter to decrement * @param tags @@ -286,7 +300,7 @@ public void decrementCounter(String aspect, String... tags) { } /** - * Convenience method equivalent to {@link #decrementCounter(String, String[])}. + * Convenience method equivalent to {@link #decrementCounter(String, String[])}. */ @Override public void decrement(String aspect, String... tags) { @@ -295,9 +309,9 @@ public void decrement(String aspect, String... tags) { /** * Records the latest fixed value for the specified named gauge. - * + * *

      This method is non-blocking and is guaranteed not to throw an exception.

      - * + * * @param aspect * the name of the gauge * @param value @@ -323,9 +337,9 @@ public void gauge(String aspect, double value, String... tags) { /** * Records the latest fixed value for the specified named gauge. - * + * *

      This method is non-blocking and is guaranteed not to throw an exception.

      - * + * * @param aspect * the name of the gauge * @param value @@ -339,7 +353,7 @@ public void recordGaugeValue(String aspect, int value, String... tags) { } /** - * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. + * Convenience method equivalent to {@link #recordGaugeValue(String, int, String[])}. */ @Override public void gauge(String aspect, int value, String... tags) { @@ -348,9 +362,9 @@ public void gauge(String aspect, int value, String... tags) { /** * Records an execution time in milliseconds for the specified named operation. - * + * *

      This method is non-blocking and is guaranteed not to throw an exception.

      - * + * * @param aspect * the name of the timed operation * @param timeInMs @@ -400,9 +414,9 @@ public void histogram(String aspect, double value, String... tags) { /** * Records a value for the specified named histogram. - * + * *

      This method is non-blocking and is guaranteed not to throw an exception.

      - * + * * @param aspect * the name of the histogram * @param value @@ -416,33 +430,61 @@ public void recordHistogramValue(String aspect, int value, String... tags) { } /** - * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. + * Convenience method equivalent to {@link #recordHistogramValue(String, int, String[])}. */ @Override public void histogram(String aspect, int value, String... tags) { recordHistogramValue(aspect, value, tags); } - private void send(final String message) { - try { - executor.execute(new Runnable() { - @Override public void run() { - blockingSend(message); + private void send(String message) { + queue.offer(message); + } + + private class QueueConsumer implements Runnable { + private final ByteBuffer sendBuffer = ByteBuffer.allocate(PACKET_SIZE_BYTES); + + @Override public void run() { + while(!executor.isShutdown()) { + try { + String message = queue.poll(1, TimeUnit.SECONDS); + if(null != message) { + byte[] data = message.getBytes(); + if(sendBuffer.remaining() < (data.length + 1)) { + blockingSend(); + } + if(sendBuffer.position() > 0) { + sendBuffer.put( (byte) '\n'); + } + sendBuffer.put(data); + if(null == queue.peek()) { + blockingSend(); + } + } + } catch (Exception e) { + handler.handle(e); } - }); - } - catch (Exception e) { - handler.handle(e); + } } - } - private void blockingSend(String message) { - try { - final byte[] sendData = message.getBytes(); - final DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length); - clientSocket.send(sendPacket); - } catch (Exception e) { - handler.handle(e); + private void blockingSend() throws IOException { + int sizeOfBuffer = sendBuffer.position(); + sendBuffer.flip(); + int sentBytes = clientChannel.send(sendBuffer, address); + sendBuffer.limit(sendBuffer.capacity()); + sendBuffer.rewind(); + + if (sizeOfBuffer != sentBytes) { + handler.handle( + new IOException( + String.format( + "Could not send entirely stat %s to host %s:%d. Only sent %d bytes out of %d bytes", + sendBuffer.toString(), + address.getHostName(), + address.getPort(), + sentBytes, + sizeOfBuffer))); + } } } } diff --git a/src/test/java/com/timgroup/statsd/DummyStatsDServer.java b/src/test/java/com/timgroup/statsd/DummyStatsDServer.java new file mode 100644 index 0000000..4f13316 --- /dev/null +++ b/src/test/java/com/timgroup/statsd/DummyStatsDServer.java @@ -0,0 +1,54 @@ + +package com.timgroup.statsd; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.List; + + +final class DummyStatsDServer { + private final List messagesReceived = new ArrayList(); + private final DatagramSocket server; + + public DummyStatsDServer(int port) throws SocketException { + server = new DatagramSocket(port); + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + while(!server.isClosed()) { + try { + final DatagramPacket packet = new DatagramPacket(new byte[1500], 1500); + server.receive(packet); + for(String msg : new String(packet.getData()).split("\n")) { + messagesReceived.add(msg.trim()); + } + } catch (IOException e) { + } + } + } + }); + thread.setDaemon(true); + thread.start(); + } + + public void waitForMessage() { + while (messagesReceived.isEmpty()) { + try { + Thread.sleep(50L); + } catch (InterruptedException e) { + } + } + } + + public List messagesReceived() { + return new ArrayList(messagesReceived); + } + + public void close() { + server.close(); + } + +} diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientPerfTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientPerfTest.java new file mode 100644 index 0000000..70c1219 --- /dev/null +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientPerfTest.java @@ -0,0 +1,59 @@ +package com.timgroup.statsd; + + +import java.net.SocketException; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public final class NonBlockingStatsDClientPerfTest { + + + private static final int STATSD_SERVER_PORT = 17255; + private static final Random RAND = new Random(); + private final NonBlockingStatsDClient client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT); + private final ExecutorService executor = Executors.newFixedThreadPool(20); + private DummyStatsDServer server; + + @Before + public void start() throws SocketException { + server = new DummyStatsDServer(STATSD_SERVER_PORT); + } + + @After + public void stop() throws Exception { + client.stop(); + server.close(); + } + + @Test(timeout=30000) + public void perf_test() throws Exception { + + int testSize = 10000; + for(int i = 0; i < testSize; ++i) { + executor.submit(new Runnable() { + public void run() { + client.count("mycount", RAND.nextInt()); + } + }); + + } + + executor.shutdown(); + executor.awaitTermination(20, TimeUnit.SECONDS); + + for(int i = 0; i < 20000 && server.messagesReceived().size() < testSize; i += 50) { + try { + Thread.sleep(50); + } catch (InterruptedException ex) {} + } + + assertEquals(testSize, server.messagesReceived().size()); + } +} diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 465777a..fadf1ed 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -1,13 +1,10 @@ package com.timgroup.statsd; +import java.net.SocketException; import org.junit.After; +import org.junit.Before; import org.junit.Test; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; import static org.hamcrest.MatcherAssert.assertThat; @@ -17,105 +14,112 @@ public class NonBlockingStatsDClientTest { private static final int STATSD_SERVER_PORT = 17254; private final NonBlockingStatsDClient client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT); + private DummyStatsDServer server; + + @Before + public void start() throws SocketException { + server = new DummyStatsDServer(STATSD_SERVER_PORT); + } @After public void stop() throws Exception { client.stop(); + server.close(); } @Test(timeout=5000L) public void sends_counter_value_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.count("mycount", 24); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); } @Test(timeout=5000L) public void sends_counter_value_to_statsd_with_null_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.count("mycount", 24, (java.lang.String[]) null); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); } @Test(timeout=5000L) public void sends_counter_value_to_statsd_with_empty_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.count("mycount", 24); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c")); } @Test(timeout=5000L) public void sends_counter_value_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.count("mycount", 24, "foo:bar", "baz"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mycount:24|c|#baz,foo:bar")); } @Test(timeout=5000L) public void sends_counter_increment_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.incrementCounter("myinc"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.myinc:1|c")); } @Test(timeout=5000L) public void sends_counter_increment_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.incrementCounter("myinc", "foo:bar", "baz"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.myinc:1|c|#baz,foo:bar")); } @Test(timeout=5000L) public void sends_counter_decrement_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.decrementCounter("mydec"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mydec:-1|c")); } @Test(timeout=5000L) public void sends_counter_decrement_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.decrementCounter("mydec", "foo:bar", "baz"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mydec:-1|c|#baz,foo:bar")); } @Test(timeout=5000L) public void sends_gauge_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.recordGaugeValue("mygauge", 423); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:423|g")); } @Test(timeout=5000L) public void sends_large_double_gauge_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + client.recordGaugeValue("mygauge", 123456789012345.67890); server.waitForMessage(); @@ -125,7 +129,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_exact_double_gauge_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + client.recordGaugeValue("mygauge", 123.45678901234567890); server.waitForMessage(); @@ -135,37 +139,37 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_double_gauge_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.recordGaugeValue("mygauge", 0.423); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:0.423|g")); } @Test(timeout=5000L) public void sends_gauge_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.recordGaugeValue("mygauge", 423, "foo:bar", "baz"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:423|g|#baz,foo:bar")); } @Test(timeout=5000L) public void sends_double_gauge_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.recordGaugeValue("mygauge", 0.423, "foo:bar", "baz"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:0.423|g|#baz,foo:bar")); } @Test(timeout=5000L) public void sends_histogram_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + client.recordHistogramValue("myhistogram", 423); server.waitForMessage(); @@ -175,7 +179,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_double_histogram_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + client.recordHistogramValue("myhistogram", 0.423); server.waitForMessage(); @@ -185,7 +189,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_histogram_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + client.recordHistogramValue("myhistogram", 423, "foo:bar", "baz"); server.waitForMessage(); @@ -195,7 +199,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_double_histogram_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + client.recordHistogramValue("myhistogram", 0.423, "foo:bar", "baz"); server.waitForMessage(); @@ -205,11 +209,11 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_timer_to_statsd() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.recordExecutionTime("mytime", 123); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h")); } @@ -226,7 +230,7 @@ public void stop() throws Exception { Locale.setDefault(Locale.GERMANY); try { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + client.recordExecutionTime("mytime", 123, "foo:bar", "baz"); server.waitForMessage(); @@ -241,18 +245,18 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_timer_to_statsd_with_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); - + + client.recordExecutionTime("mytime", 123, "foo:bar", "baz"); server.waitForMessage(); - + assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h|#baz,foo:bar")); } @Test(timeout=5000L) public void sends_gauge_mixed_tags() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, new String[] {"instance:foo", "app:bar"}); empty_prefix_client.gauge("value", 423, "baz"); server.waitForMessage(); @@ -262,7 +266,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_gauge_constant_tags_only() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, new String[] {"instance:foo", "app:bar"}); empty_prefix_client.gauge("value", 423); server.waitForMessage(); @@ -272,7 +276,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_gauge_empty_prefix() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("", "localhost", STATSD_SERVER_PORT); empty_prefix_client.gauge("top.level.value", 423); server.waitForMessage(); @@ -282,7 +286,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_gauge_null_prefix() throws Exception { - final DummyStatsDServer server = new DummyStatsDServer(STATSD_SERVER_PORT); + final NonBlockingStatsDClient null_prefix_client = new NonBlockingStatsDClient(null, "localhost", STATSD_SERVER_PORT); null_prefix_client.gauge("top.level.value", 423); server.waitForMessage(); @@ -290,33 +294,4 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("top.level.value:423|g")); } - private static final class DummyStatsDServer { - private final List messagesReceived = new ArrayList(); - private final DatagramSocket server; - - public DummyStatsDServer(int port) throws SocketException { - server = new DatagramSocket(port); - new Thread(new Runnable() { - @Override public void run() { - try { - final DatagramPacket packet = new DatagramPacket(new byte[256], 256); - server.receive(packet); - messagesReceived.add(new String(packet.getData()).trim()); - server.close(); - } catch (Exception e) { } - } - }).start(); - } - - public void waitForMessage() { - while (messagesReceived.isEmpty()) { - try { - Thread.sleep(50L); - } catch (InterruptedException e) {}} - } - - public List messagesReceived() { - return new ArrayList(messagesReceived); - } - } } From b99aab945318d04338f968cbe414310dc13e961c Mon Sep 17 00:00:00 2001 From: mck Date: Fri, 28 Mar 2014 12:52:25 +0100 Subject: [PATCH 26/69] =?UTF-8?q?restores=20compatibility=20with=20vanilla?= =?UTF-8?q?=20statsd=20=20references:=20=20=20statsd=20documentation=20?= =?UTF-8?q?=E2=80=93=20https://github.com/etsy/statsd/blob/master/docs/met?= =?UTF-8?q?ric=5Ftypes.md=20=20=20breakage=20from=20commit=20dcae=20=20?= =?UTF-8?q?=E2=80=93=C2=A0https://github.com/indeedeng/java-dogstatsd-clie?= =?UTF-8?q?nt/commit/dcaed45c36ef74ba370d806647a4a06b173a9566#commitcommen?= =?UTF-8?q?t-5832637?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- .../java/com/timgroup/statsd/NonBlockingStatsDClient.java | 2 +- .../com/timgroup/statsd/NonBlockingStatsDClientTest.java | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 5be5047..03d1d14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ bin build -*.iml \ No newline at end of file +*.iml +/target/ \ No newline at end of file diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 6c35d85..88729c8 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -374,7 +374,7 @@ public void gauge(String aspect, int value, String... tags) { */ @Override public void recordExecutionTime(String aspect, long timeInMs, String... tags) { - recordHistogramValue(aspect, (timeInMs * 0.001), tags); + send(String.format("%s%s:%d|ms%s", prefix, aspect, timeInMs, tagString(tags))); } /** diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index fadf1ed..3f9de9c 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -214,7 +214,7 @@ public void stop() throws Exception { client.recordExecutionTime("mytime", 123); server.waitForMessage(); - assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h")); + assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms")); } /** @@ -235,7 +235,7 @@ public void stop() throws Exception { client.recordExecutionTime("mytime", 123, "foo:bar", "baz"); server.waitForMessage(); - assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h|#baz,foo:bar")); + assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms|#baz,foo:bar")); } finally { // reset the default Locale in case changing it has side-effects Locale.setDefault(originalDefaultLocale); @@ -250,7 +250,7 @@ public void stop() throws Exception { client.recordExecutionTime("mytime", 123, "foo:bar", "baz"); server.waitForMessage(); - assertThat(server.messagesReceived(), contains("my.prefix.mytime:0.123|h|#baz,foo:bar")); + assertThat(server.messagesReceived(), contains("my.prefix.mytime:123|ms|#baz,foo:bar")); } From 3d2f31a06be433f7b52feb8832d829bf6cb08b95 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Wed, 14 Jan 2015 10:09:28 +0900 Subject: [PATCH 27/69] set parent.version to latest version of https://oss.sonatype.org/content/repositories/releases/com/indeed/oss-parent/maven-metadata.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 285be49..89a8669 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.indeed oss-parent - 5 + 13 com.indeed From 83024a65e1dfa33e648dd646243da6c42003ced0 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Wed, 14 Jan 2015 22:09:07 +0000 Subject: [PATCH 28/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 89a8669..47934d1 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.9-SNAPSHOT + 2.0.9 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 5723278984370ea6f85c8102814e1a76dd16c5e6 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Wed, 14 Jan 2015 22:09:07 +0000 Subject: [PATCH 29/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 47934d1..9c38f5f 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.9 + 2.0.10-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 6afa75cc1e6993f815ce544c8739cd32ab5acb9e Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Mon, 2 Mar 2015 11:43:24 +0900 Subject: [PATCH 30/69] COMMON-1195 : support posting events --- src/main/java/com/timgroup/statsd/Event.java | 166 ++++++++++++++++++ .../com/timgroup/statsd/NoOpStatsDClient.java | 1 + .../statsd/NonBlockingStatsDClient.java | 54 ++++++ .../com/timgroup/statsd/StatsDClient.java | 15 ++ .../java/com/timgroup/statsd/EventTest.java | 83 +++++++++ .../statsd/NonBlockingStatsDClientTest.java | 84 ++++++++- 6 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/timgroup/statsd/Event.java create mode 100644 src/test/java/com/timgroup/statsd/EventTest.java diff --git a/src/main/java/com/timgroup/statsd/Event.java b/src/main/java/com/timgroup/statsd/Event.java new file mode 100644 index 0000000..4507425 --- /dev/null +++ b/src/main/java/com/timgroup/statsd/Event.java @@ -0,0 +1,166 @@ +package com.timgroup.statsd; + +import java.util.Date; + +/** + * An event to send + * @see http://docs.datadoghq.com/guides/dogstatsd/#events + */ +public class Event { + private String title; + private String text; + private long millisSinceEpoch = -1; + private String hostname; + private String aggregationKey; + private String priority; + private String sourceTypeName; + private String alertType; + + public String getTitle() { + return title; + } + + public String getText() { + return text; + } + + /** + * @return -1 if not set + */ + public long getMillisSinceEpoch() { + return millisSinceEpoch; + } + + public String getHostname() { + return hostname; + } + + public String getAggregationKey() { + return aggregationKey; + } + + public String getPriority() { + return priority; + } + + public String getSourceTypeName() { + return sourceTypeName; + } + + public String getAlertType() { + return alertType; + } + + public static Builder builder() { + return new Builder(); + } + + private Event(){} + + public enum Priority { + LOW, NORMAL + } + + public enum AlertType { + ERROR, WARNING, INFO, SUCCESS + } + + @SuppressWarnings({"AccessingNonPublicFieldOfAnotherObject", "PrivateMemberAccessBetweenOuterAndInnerClass", "ParameterHidesMemberVariable"}) + public static class Builder { + private final Event event = new Event(); + private Builder() {} + + public Event build() { + if ((event.title == null) || event.title.isEmpty()) { + throw new IllegalStateException("event title must be set"); + } + if ((event.text == null) || event.text.isEmpty()) { + throw new IllegalStateException("event text must be set"); + } + return event; + } + + /** + * @param title + * Event title ; mandatory + */ + public Builder withTitle(final String title) { + event.title = title; + return this; + } + + /** + * @param text + * Event text ; supports line breaks ; mandatory + */ + public Builder withText(final String text) { + event.text = text; + return this; + } + + /** + * @param date + * Assign a timestamp to the event ; Default: none (Default is the current Unix epoch timestamp when not sent) + */ + public Builder withDate(final Date date) { + event.millisSinceEpoch = date.getTime(); + return this; + } + + /** + * @param millisSinceEpoch + * Assign a timestamp to the event ; Default: none (Default is the current Unix epoch timestamp when not sent) + */ + public Builder withDate(final long millisSinceEpoch) { + event.millisSinceEpoch = millisSinceEpoch; + return this; + } + + /** + * @param hostname + * Assign a hostname to the event ; Default: none + */ + public Builder withHostname(final String hostname) { + event.hostname = hostname; + return this; + } + + /** + * @param aggregationKey + * Assign an aggregation key to the event, to group it with some others ; Default: none + */ + public Builder withAggregationKey(final String aggregationKey) { + event.aggregationKey = aggregationKey; + return this; + } + + /** + * @param priority + * Can be "normal" or "low" ; Default: "normal" + */ + public Builder withPriority(final Priority priority) { + //noinspection StringToUpperCaseOrToLowerCaseWithoutLocale + event.priority = priority.name().toLowerCase(); + return this; + } + + /** + * @param sourceTypeName + * Assign a source type to the event ; Default: none + */ + public Builder withSourceTypeName(final String sourceTypeName) { + event.sourceTypeName = sourceTypeName; + return this; + } + + /** + * @param alertType + * Can be "error", "warning", "info" or "success" ; Default: "info" + */ + public Builder withAlertType(final AlertType alertType) { + //noinspection StringToUpperCaseOrToLowerCaseWithoutLocale + event.alertType = alertType.name().toLowerCase(); + return this; + } + } +} diff --git a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java index 3dbce15..cc4369b 100644 --- a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java @@ -24,4 +24,5 @@ public final class NoOpStatsDClient implements StatsDClient { @Override public void histogram(String aspect, double value, String... tags) { } @Override public void recordHistogramValue(String aspect, long value, String... tags) { } @Override public void histogram(String aspect, long value, String... tags) { } + @Override public void recordEvent(final Event event, final String... tags) { } } diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 4ca65de..9aa20f6 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -28,6 +28,7 @@ *
    • {@link #recordGaugeValue} - records the latest fixed value for the specified named gauge
    • *
    • {@link #recordExecutionTime} - records an execution time in milliseconds for the specified named operation
    • *
    • {@link #recordHistogramValue} - records a value, to be tracked with average, maximum, and percentiles
    • + *
    • {@link #recordEvent} - records an event
    • *
    * From the perspective of the application, these methods are non-blocking, with the resulting * IO operations being carried out in a separate thread. Furthermore, these methods are guaranteed @@ -437,6 +438,59 @@ public void histogram(String aspect, long value, String... tags) { recordHistogramValue(aspect, value, tags); } + private String eventMap(final Event event) { + final StringBuilder res = new StringBuilder(""); + + final long millisSinceEpoch = event.getMillisSinceEpoch(); + if (millisSinceEpoch != -1) { + res.append("|d:").append(millisSinceEpoch / 1000); + } + + final String hostname = event.getHostname(); + if (hostname != null) { + res.append("|h:").append(hostname); + } + + final String aggregationKey = event.getAggregationKey(); + if (aggregationKey != null) { + res.append("|k:").append(aggregationKey); + } + + final String priority = event.getPriority(); + if (priority != null) { + res.append("|p:").append(priority); + } + + final String alertType = event.getAlertType(); + if (alertType != null) { + res.append("|t:").append(alertType); + } + + return res.toString(); + } + + /** + * Records an event + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param event + * The event to record + * @param tags + * array of tags to be added to the data + * + * @see http://docs.datadoghq.com/guides/dogstatsd/#events-1 + */ + @Override + public void recordEvent(final Event event, final String... tags) { + final String title = prefix + event.getTitle(); + final String text = event.getText(); + send(String.format("_e{%d,%d}:%s|%s%s%s", + title.length(), text.length(), title, text, eventMap(event), tagString(tags))); + } + private void send(String message) { queue.offer(message); } diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index d231171..4d807be 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -178,4 +178,19 @@ public interface StatsDClient { */ void histogram(String aspect, long value, String... tags); + /** + * Records an event + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param event + * The event to record + * @param tags + * array of tags to be added to the data + * + * @see http://docs.datadoghq.com/guides/dogstatsd/#events-1 + */ + void recordEvent(Event event, String... tags); } diff --git a/src/test/java/com/timgroup/statsd/EventTest.java b/src/test/java/com/timgroup/statsd/EventTest.java new file mode 100644 index 0000000..7ff1f57 --- /dev/null +++ b/src/test/java/com/timgroup/statsd/EventTest.java @@ -0,0 +1,83 @@ +package com.timgroup.statsd; + +import org.junit.Test; + +import java.util.Date; + +import static org.junit.Assert.assertEquals; + +public class EventTest { + @Test + public void builds() { + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .withDate(1234) + .withHostname("host1") + .withPriority(Event.Priority.LOW) + .withAggregationKey("key1") + .withAlertType(Event.AlertType.ERROR) + .build(); + + assertEquals("title1", event.getTitle()); + assertEquals("text1", event.getText()); + assertEquals(1234, event.getMillisSinceEpoch()); + assertEquals("host1", event.getHostname()); + assertEquals("low", event.getPriority()); + assertEquals("key1", event.getAggregationKey()); + assertEquals("error", event.getAlertType()); + } + + @Test + public void builds_with_defaults() { + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .build(); + + assertEquals("title1", event.getTitle()); + assertEquals("text1", event.getText()); + assertEquals(-1, event.getMillisSinceEpoch()); + assertEquals(null, event.getHostname()); + assertEquals(null, event.getPriority()); + assertEquals(null, event.getAggregationKey()); + assertEquals(null, event.getAlertType()); + } + + @Test (expected = IllegalStateException.class) + public void fails_without_title() { + Event.builder().withText("text1") + .withDate(1234) + .withHostname("host1") + .withPriority(Event.Priority.LOW) + .withAggregationKey("key1") + .withAlertType(Event.AlertType.ERROR) + .build(); + } + + @Test (expected = IllegalStateException.class) + public void fails_without_text() { + Event.builder().withTitle("title1") + .withDate(1234) + .withHostname("host1") + .withPriority(Event.Priority.LOW) + .withAggregationKey("key1") + .withAlertType(Event.AlertType.ERROR) + .build(); + } + + @Test + public void builds_with_date() { + final long expectedMillis = 1234567000; + final Date date = new Date(expectedMillis); + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .withDate(date) + .build(); + + assertEquals("title1", event.getTitle()); + assertEquals("text1", event.getText()); + assertEquals(expectedMillis, event.getMillisSinceEpoch()); + } +} diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 3f9de9c..ac701e6 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -1,10 +1,10 @@ package com.timgroup.statsd; -import java.net.SocketException; import org.junit.After; import org.junit.Before; import org.junit.Test; +import java.net.SocketException; import java.util.Locale; import static org.hamcrest.MatcherAssert.assertThat; @@ -294,4 +294,86 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("top.level.value:423|g")); } + @Test(timeout=5000L) public void + sends_event() throws Exception { + + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .withDate(1234567000) + .withHostname("host1") + .withPriority(Event.Priority.LOW) + .withAggregationKey("key1") + .withAlertType(Event.AlertType.ERROR) + .build(); + client.recordEvent(event); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("_e{16,5}:my.prefix.title1|text1|d:1234567|h:host1|k:key1|p:low|t:error")); + } + + @Test(timeout=5000L) public void + sends_partial_event() throws Exception { + + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .withDate(1234567000) + .build(); + client.recordEvent(event); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("_e{16,5}:my.prefix.title1|text1|d:1234567")); + } + + @Test(timeout=5000L) public void + sends_event_with_tags() throws Exception { + + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .withDate(1234567000) + .withHostname("host1") + .withPriority(Event.Priority.LOW) + .withAggregationKey("key1") + .withAlertType(Event.AlertType.ERROR) + .build(); + client.recordEvent(event, "foo:bar", "baz"); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("_e{16,5}:my.prefix.title1|text1|d:1234567|h:host1|k:key1|p:low|t:error|#baz,foo:bar")); + } + + @Test(timeout=5000L) public void + sends_partial_event_with_tags() throws Exception { + + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .withDate(1234567000) + .build(); + client.recordEvent(event, "foo:bar", "baz"); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("_e{16,5}:my.prefix.title1|text1|d:1234567|#baz,foo:bar")); + } + + @Test(timeout=5000L) public void + sends_event_empty_prefix() throws Exception { + + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("", "localhost", STATSD_SERVER_PORT); + final Event event = Event.builder() + .withTitle("title1") + .withText("text1") + .withDate(1234567000) + .withHostname("host1") + .withPriority(Event.Priority.LOW) + .withAggregationKey("key1") + .withAlertType(Event.AlertType.ERROR) + .build(); + empty_prefix_client.recordEvent(event, "foo:bar", "baz"); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("_e{6,5}:title1|text1|d:1234567|h:host1|k:key1|p:low|t:error|#baz,foo:bar")); + } } From 2c04e5b6028543a5fd87295ab7714d0a3ec9af91 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Thu, 5 Mar 2015 03:59:22 +0000 Subject: [PATCH 31/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.10 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9c38f5f..c1ab527 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.10-SNAPSHOT + 2.0.10 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 337f61aaebccf622365bc58380b0ca92470952db Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Thu, 5 Mar 2015 03:59:22 +0000 Subject: [PATCH 32/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c1ab527..6497699 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.10 + 2.0.11-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From fc8042fb950fabe712d907ee6bca917626a2e830 Mon Sep 17 00:00:00 2001 From: Arthur Wang Date: Mon, 12 Jan 2015 17:51:12 +0000 Subject: [PATCH 33/69] Service check support --- README.md | 1 - .../com/timgroup/statsd/NoOpStatsDClient.java | 4 +- .../statsd/NonBlockingStatsDClient.java | 38 +++++ .../com/timgroup/statsd/ServiceCheck.java | 135 ++++++++++++++++++ .../com/timgroup/statsd/StatsDClient.java | 14 ++ .../statsd/NonBlockingStatsDClientTest.java | 13 ++ 6 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/timgroup/statsd/ServiceCheck.java diff --git a/README.md b/README.md index 3d6842e..2cc9c2c 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,3 @@ public class Foo { } } ``` - diff --git a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java index cc4369b..0c5bc01 100644 --- a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java @@ -3,7 +3,7 @@ /** * A No-Op StatsDClient, which can be substituted in when metrics are not * required. - * + * * @author Tom Denley * */ @@ -25,4 +25,6 @@ public final class NoOpStatsDClient implements StatsDClient { @Override public void recordHistogramValue(String aspect, long value, String... tags) { } @Override public void histogram(String aspect, long value, String... tags) { } @Override public void recordEvent(final Event event, final String... tags) { } + @Override public void recordServiceCheckRun(ServiceCheck sc) { } + @Override public void serviceCheck(ServiceCheck sc) { } } diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 9aa20f6..0123deb 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -491,6 +491,44 @@ public void recordEvent(final Event event, final String... tags) { title.length(), text.length(), title, text, eventMap(event), tagString(tags))); } + /** + * Records a run status for the specified named service check. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param sc + * the service check object + */ + @Override public void recordServiceCheckRun(ServiceCheck sc) { + send(toStatsDString(sc)); + } + + private String toStatsDString(ServiceCheck sc) { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("_sc|%s|%d", sc.getName(), sc.getStatus())); + if (sc.getTimestamp() > 0) { + sb.append(String.format("|d:%d", sc.getTimestamp())); + } + if (sc.getHostname() != null) { + sb.append(String.format("|h:%s", sc.getHostname())); + } + sb.append(tagString(sc.getTags())); + if (sc.getMessage() != null) { + sb.append(String.format("|m:%s", sc.getEscapedMessage())); + } + return sb.toString(); + } + + /** + * Convenience method equivalent to {@link #recordServiceCheckRun(ServiceCheck sc)}. + */ + @Override + public void serviceCheck(ServiceCheck sc) { + recordServiceCheckRun(sc); + } + private void send(String message) { queue.offer(message); } diff --git a/src/main/java/com/timgroup/statsd/ServiceCheck.java b/src/main/java/com/timgroup/statsd/ServiceCheck.java new file mode 100644 index 0000000..2f98e1a --- /dev/null +++ b/src/main/java/com/timgroup/statsd/ServiceCheck.java @@ -0,0 +1,135 @@ +package com.timgroup.statsd; + +/** + * A service check model, which is used to format a service check message + * sent to the datadog agent + */ +public class ServiceCheck { + public static final int OK = 0; + public static final int WARNING = 1; + public static final int CRITICAL = 2; + public static final int UNKNOWN = 3; + + private String name, hostname, message; + + private int status, checkRunId, timestamp; + + private String[] tags; + + /** + */ + public ServiceCheck() { + } + + /** + * @param name + * @param status + */ + public ServiceCheck(String name, int status) { + this(name, status, null, null, null); + } + + public ServiceCheck(String name, int status, String message, String[] tags) { + this(name, status, message, null, tags); + } + + public ServiceCheck(String name, int status, String message, String hostname, String[] tags) { + this.name = name; + this.status = status; + this.message = message; + this.hostname = hostname; + this.tags = tags; + } + + /** + * @return + */ + public String getName() { + return name; + } + + /** + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return + */ + public int getStatus() { + return status; + } + + /** + * @param status + */ + public void setStatus(int status) { + this.status = status; + } + + /** + * @return + */ + public String getMessage() { + return message; + } + + /** + * @return + */ + public String getEscapedMessage() { + return message.replace("\n", "\\n").replace("m:", "m\\:"); + } + + /** + * + * @param message + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * @return + */ + public String getHostname() { + return hostname; + } + + /** + * @param hostname + */ + public void setHostname(String hostname) { + this.hostname = hostname; + } + + /** + * @return + */ + public int getTimestamp() { + return timestamp; + } + + /** + * @param timestamp + */ + public void setTimestamp(int timestamp) { + this.timestamp = timestamp; + } + + /** + * @return + */ + public String[] getTags() { + return tags; + } + + /** + * @param tags + */ + public void setTags(String... tags) { + this.tags = tags; + } +} diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index 4d807be..0c5a0c9 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -193,4 +193,18 @@ public interface StatsDClient { * @see http://docs.datadoghq.com/guides/dogstatsd/#events-1 */ void recordEvent(Event event, String... tags); + + /** + * Records a run status for the specified named service check. + * + * @param sc + * the service check object + */ + void recordServiceCheckRun(ServiceCheck sc); + + /** + * Convenience method equivalent to {@link #recordServiceCheckRun(ServiceCheck sc)}. + */ + void serviceCheck(ServiceCheck sc); + } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index ac701e6..e695ed4 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -376,4 +376,17 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("_e{6,5}:title1|text1|d:1234567|h:host1|k:key1|p:low|t:error|#baz,foo:bar")); } + + @Test(timeout=5000L) public void + sends_service_check() throws Exception { + String[] tags = {"key1:val1", "key2:val2"}; + ServiceCheck sc = new ServiceCheck("my_check.name", ServiceCheck.WARNING, "♬ †øU \n†øU ¥ºu|m: T0µ ♪", "i-abcd1234", tags); + sc.setTimestamp(1420740000); + + client.serviceCheck(sc); + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains(String.format("_sc|my_check.name|1|d:1420740000|h:i-abcd1234|#key2:val2,key1:val1|m:%s", + "♬ †øU \\n†øU ¥ºu|m\\: T0µ ♪"))); + } } From 6c306b35456128c35eb039780af382c1d95775df Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Thu, 30 Apr 2015 16:42:38 +0900 Subject: [PATCH 34/69] minor code improvements: - added comments and "final"s - converted ServiceCheck to builder pattern - \u-encoded string --- .../statsd/NonBlockingStatsDClient.java | 10 +- .../com/timgroup/statsd/ServiceCheck.java | 144 +++++++----------- .../statsd/NonBlockingStatsDClientTest.java | 19 ++- 3 files changed, 77 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 0123deb..e3d2af3 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -501,12 +501,14 @@ public void recordEvent(final Event event, final String... tags) { * @param sc * the service check object */ - @Override public void recordServiceCheckRun(ServiceCheck sc) { + @Override + public void recordServiceCheckRun(final ServiceCheck sc) { send(toStatsDString(sc)); } - private String toStatsDString(ServiceCheck sc) { - StringBuilder sb = new StringBuilder(); + private String toStatsDString(final ServiceCheck sc) { + // see http://docs.datadoghq.com/guides/dogstatsd/#service-checks + final StringBuilder sb = new StringBuilder(); sb.append(String.format("_sc|%s|%d", sc.getName(), sc.getStatus())); if (sc.getTimestamp() > 0) { sb.append(String.format("|d:%d", sc.getTimestamp())); @@ -525,7 +527,7 @@ private String toStatsDString(ServiceCheck sc) { * Convenience method equivalent to {@link #recordServiceCheckRun(ServiceCheck sc)}. */ @Override - public void serviceCheck(ServiceCheck sc) { + public void serviceCheck(final ServiceCheck sc) { recordServiceCheckRun(sc); } diff --git a/src/main/java/com/timgroup/statsd/ServiceCheck.java b/src/main/java/com/timgroup/statsd/ServiceCheck.java index 2f98e1a..ab223c5 100644 --- a/src/main/java/com/timgroup/statsd/ServiceCheck.java +++ b/src/main/java/com/timgroup/statsd/ServiceCheck.java @@ -5,131 +5,99 @@ * sent to the datadog agent */ public class ServiceCheck { - public static final int OK = 0; - public static final int WARNING = 1; - public static final int CRITICAL = 2; - public static final int UNKNOWN = 3; + + public enum Status { + OK(0), WARNING(1), CRITICAL(2), UNKNOWN(3); + + private final int val; + Status(final int val) { + this.val = val; + } + } private String name, hostname, message; - private int status, checkRunId, timestamp; + private int checkRunId, timestamp; + + private Status status; private String[] tags; - /** - */ - public ServiceCheck() { + public static Builder builder() { + return new Builder(); } - /** - * @param name - * @param status - */ - public ServiceCheck(String name, int status) { - this(name, status, null, null, null); - } + public static class Builder { + final ServiceCheck res = new ServiceCheck(); + + public Builder withName(final String name) { + res.name = name; + return this; + } + + public Builder withHostname(final String hostname) { + res.hostname = hostname; + return this; + } + + public Builder withMessage(final String message) { + res.message = message; + return this; + } + + public Builder withCheckRunId(final int checkRunId) { + res.checkRunId = checkRunId; + return this; + } + + public Builder withTimestamp(final int timestamp) { + res.timestamp = timestamp; + return this; + } + + public Builder withStatus(final Status status) { + res.status = status; + return this; + } + + public Builder withTags(final String[] tags) { + res.tags = tags; + return this; + } - public ServiceCheck(String name, int status, String message, String[] tags) { - this(name, status, message, null, tags); + public ServiceCheck build() { + return res; + } } - public ServiceCheck(String name, int status, String message, String hostname, String[] tags) { - this.name = name; - this.status = status; - this.message = message; - this.hostname = hostname; - this.tags = tags; + private ServiceCheck() { } - /** - * @return - */ public String getName() { return name; } - /** - * @param name - */ - public void setName(String name) { - this.name = name; - } - - /** - * @return - */ public int getStatus() { - return status; - } - - /** - * @param status - */ - public void setStatus(int status) { - this.status = status; + return status.val; } - /** - * @return - */ public String getMessage() { return message; } - /** - * @return - */ public String getEscapedMessage() { return message.replace("\n", "\\n").replace("m:", "m\\:"); } - /** - * - * @param message - */ - public void setMessage(String message) { - this.message = message; - } - - /** - * @return - */ public String getHostname() { return hostname; } - /** - * @param hostname - */ - public void setHostname(String hostname) { - this.hostname = hostname; - } - - /** - * @return - */ public int getTimestamp() { return timestamp; } - /** - * @param timestamp - */ - public void setTimestamp(int timestamp) { - this.timestamp = timestamp; - } - - /** - * @return - */ public String[] getTags() { return tags; } - - /** - * @param tags - */ - public void setTags(String... tags) { - this.tags = tags; - } } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index e695ed4..9aab2cf 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -9,6 +9,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; +import static org.junit.Assert.assertEquals; public class NonBlockingStatsDClientTest { @@ -379,14 +380,24 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_service_check() throws Exception { - String[] tags = {"key1:val1", "key2:val2"}; - ServiceCheck sc = new ServiceCheck("my_check.name", ServiceCheck.WARNING, "♬ †øU \n†øU ¥ºu|m: T0µ ♪", "i-abcd1234", tags); - sc.setTimestamp(1420740000); + final String inputMessage = "\u266c \u2020\u00f8U \n\u2020\u00f8U \u00a5\u00bau|m: T0\u00b5 \u266a"; // "♬ †øU \n†øU ¥ºu|m: T0µ ♪" + final String outputMessage = "\u266c \u2020\u00f8U \\n\u2020\u00f8U \u00a5\u00bau|m\\: T0\u00b5 \u266a"; // note the escaped colon + final String[] tags = {"key1:val1", "key2:val2"}; + final ServiceCheck sc = ServiceCheck.builder() + .withName("my_check.name") + .withStatus(ServiceCheck.Status.WARNING) + .withMessage(inputMessage) + .withHostname("i-abcd1234") + .withTags(tags) + .withTimestamp(1420740000) + .build(); + + assertEquals(outputMessage, sc.getEscapedMessage()); client.serviceCheck(sc); server.waitForMessage(); assertThat(server.messagesReceived(), contains(String.format("_sc|my_check.name|1|d:1420740000|h:i-abcd1234|#key2:val2,key1:val1|m:%s", - "♬ †øU \\n†øU ¥ºu|m\\: T0µ ♪"))); + outputMessage))); } } From 17b2c84a2616c39ef39e14cfa36da53e5b76c26a Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Mon, 4 May 2015 00:59:33 +0900 Subject: [PATCH 35/69] DEVOPS-198 : fix broken unit test. The unit test is broken because of a different default charset used in String.getBytes() when sending messages in NonBlockingStatsDClient.QueueConsumer.run() This issue should be fixed separately, for now just fix the unit test so the new feature can be published. --- .../java/com/timgroup/statsd/NonBlockingStatsDClientTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 9aab2cf..2f2aaee 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -380,8 +380,8 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_service_check() throws Exception { - final String inputMessage = "\u266c \u2020\u00f8U \n\u2020\u00f8U \u00a5\u00bau|m: T0\u00b5 \u266a"; // "♬ †øU \n†øU ¥ºu|m: T0µ ♪" - final String outputMessage = "\u266c \u2020\u00f8U \\n\u2020\u00f8U \u00a5\u00bau|m\\: T0\u00b5 \u266a"; // note the escaped colon + final String inputMessage = "a bcU \ndeU fgu|m: T0h i"; + final String outputMessage = "a bcU \\ndeU fgu|m\\: T0h i"; // note the escaped colon final String[] tags = {"key1:val1", "key2:val2"}; final ServiceCheck sc = ServiceCheck.builder() .withName("my_check.name") From 932301e95336ebf1cf6c0cf4611da9a7c34a3ac8 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Sun, 3 May 2015 16:05:14 +0000 Subject: [PATCH 36/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6497699..5725d88 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.11-SNAPSHOT + 2.0.11 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 67181aa08cbb8e645cd64996ece2faec66db109a Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Sun, 3 May 2015 16:05:14 +0000 Subject: [PATCH 37/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5725d88..ce0b9b2 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.11 + 2.0.12-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 1011feabcbe92b6cad5a39892e3fce49cbb5a5b4 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Tue, 2 Jun 2015 19:55:30 +0900 Subject: [PATCH 38/69] DEVOPS-203 : specify a charset to String.getBytes() --- .../java/com/timgroup/statsd/NonBlockingStatsDClient.java | 5 ++++- .../com/timgroup/statsd/NonBlockingStatsDClientTest.java | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index e3d2af3..4208274 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -4,6 +4,7 @@ import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; +import java.nio.charset.Charset; import java.text.NumberFormat; import java.util.Locale; import java.util.concurrent.BlockingQueue; @@ -535,6 +536,8 @@ private void send(String message) { queue.offer(message); } + private final Charset UTF8 = Charset.forName("UTF-8"); + private class QueueConsumer implements Runnable { private final ByteBuffer sendBuffer = ByteBuffer.allocate(PACKET_SIZE_BYTES); @@ -543,7 +546,7 @@ private class QueueConsumer implements Runnable { try { String message = queue.poll(1, TimeUnit.SECONDS); if(null != message) { - byte[] data = message.getBytes(); + byte[] data = message.getBytes(UTF8); if(sendBuffer.remaining() < (data.length + 1)) { blockingSend(); } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 2f2aaee..9aab2cf 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -380,8 +380,8 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_service_check() throws Exception { - final String inputMessage = "a bcU \ndeU fgu|m: T0h i"; - final String outputMessage = "a bcU \\ndeU fgu|m\\: T0h i"; // note the escaped colon + final String inputMessage = "\u266c \u2020\u00f8U \n\u2020\u00f8U \u00a5\u00bau|m: T0\u00b5 \u266a"; // "♬ †øU \n†øU ¥ºu|m: T0µ ♪" + final String outputMessage = "\u266c \u2020\u00f8U \\n\u2020\u00f8U \u00a5\u00bau|m\\: T0\u00b5 \u266a"; // note the escaped colon final String[] tags = {"key1:val1", "key2:val2"}; final ServiceCheck sc = ServiceCheck.builder() .withName("my_check.name") From 8ef8047204190b7c552629b96bfb2e4edc7db1b8 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Sun, 7 Jun 2015 21:07:00 +0000 Subject: [PATCH 39/69] DEVOPS-203 : specify charset for new String() in test code --- .idea/uiDesigner.xml | 124 ++++++++++++++++++ .../statsd/NonBlockingStatsDClient.java | 4 +- .../timgroup/statsd/DummyStatsDServer.java | 2 +- 3 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 .idea/uiDesigner.xml diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 4208274..90364ad 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -536,7 +536,7 @@ private void send(String message) { queue.offer(message); } - private final Charset UTF8 = Charset.forName("UTF-8"); + public static final Charset MESSAGE_CHARSET = Charset.forName("UTF-8"); private class QueueConsumer implements Runnable { private final ByteBuffer sendBuffer = ByteBuffer.allocate(PACKET_SIZE_BYTES); @@ -546,7 +546,7 @@ private class QueueConsumer implements Runnable { try { String message = queue.poll(1, TimeUnit.SECONDS); if(null != message) { - byte[] data = message.getBytes(UTF8); + byte[] data = message.getBytes(MESSAGE_CHARSET); if(sendBuffer.remaining() < (data.length + 1)) { blockingSend(); } diff --git a/src/test/java/com/timgroup/statsd/DummyStatsDServer.java b/src/test/java/com/timgroup/statsd/DummyStatsDServer.java index 4f13316..fa3f0e2 100644 --- a/src/test/java/com/timgroup/statsd/DummyStatsDServer.java +++ b/src/test/java/com/timgroup/statsd/DummyStatsDServer.java @@ -22,7 +22,7 @@ public void run() { try { final DatagramPacket packet = new DatagramPacket(new byte[1500], 1500); server.receive(packet); - for(String msg : new String(packet.getData()).split("\n")) { + for(String msg : new String(packet.getData(), NonBlockingStatsDClient.MESSAGE_CHARSET).split("\n")) { messagesReceived.add(msg.trim()); } } catch (IOException e) { From 1ea54f821b2209d63d9c87f0d91e0ed5f0aee7d2 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Sun, 7 Jun 2015 21:11:30 +0000 Subject: [PATCH 40/69] NOBUG : remove accidentally added .idea dir --- .gitignore | 3 +- .idea/uiDesigner.xml | 124 ------------------------------------------- 2 files changed, 2 insertions(+), 125 deletions(-) delete mode 100644 .idea/uiDesigner.xml diff --git a/.gitignore b/.gitignore index 03d1d14..74e5664 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bin build *.iml -/target/ \ No newline at end of file +/target/ +.idea diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From c4352628c8e12268b78b8b686e9f11bf247ec374 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Sun, 7 Jun 2015 21:14:27 +0000 Subject: [PATCH 41/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ce0b9b2..aae7992 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.12-SNAPSHOT + 2.0.12 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 7872952aa2d967adca1853417ad24d1ecf66d505 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Sun, 7 Jun 2015 21:14:27 +0000 Subject: [PATCH 42/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aae7992..a4fa425 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.12 + 2.0.13-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 918ce6b58bab8fcc60f4c15c5d977a757b77b71a Mon Sep 17 00:00:00 2001 From: Scott Reynolds Date: Thu, 11 Jun 2015 08:46:55 -0700 Subject: [PATCH 43/69] update readme to reflect latest release Summary: Lots of important changes happened since 2.0.7. But the README hasn't been updated to reflect that. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2cc9c2c..b44c325 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The client jar is distributed via maven central, and can be downloaded [here](ht com.indeed java-dogstatsd-client - 2.0.7 + 2.0.12 ``` From b2205feb90bac848ca2b84b49ff9a7e610fa54da Mon Sep 17 00:00:00 2001 From: Matt Pate Date: Fri, 7 Aug 2015 17:30:19 -0700 Subject: [PATCH 44/69] Sets NaN symbol format --- pom.xml | 6 ++++++ .../statsd/NonBlockingStatsDClient.java | 8 ++++++++ .../statsd/NonBlockingStatsDClientTest.java | 20 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/pom.xml b/pom.xml index a4fa425..44c4f77 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,12 @@ junit test + + org.powermock + powermock-module-junit4 + 1.6.2 + test +
    diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 90364ad..3faea42 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -5,6 +5,8 @@ import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.charset.Charset; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Locale; import java.util.concurrent.BlockingQueue; @@ -65,6 +67,12 @@ protected NumberFormat initialValue() { NumberFormat numberFormatter = NumberFormat.getInstance(Locale.US); numberFormatter.setGroupingUsed(false); numberFormatter.setMaximumFractionDigits(6); + + // we need to specify a value for Double.NaN that is recognized by dogStatsD + DecimalFormatSymbols symbols = ((DecimalFormat) numberFormatter).getDecimalFormatSymbols(); + symbols.setNaN("NaN"); + ((DecimalFormat) numberFormatter).setDecimalFormatSymbols(symbols); + return numberFormatter; } }; diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 9aab2cf..b6ecb23 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -3,13 +3,16 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.powermock.reflect.Whitebox; import java.net.SocketException; +import java.text.NumberFormat; import java.util.Locale; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class NonBlockingStatsDClientTest { @@ -400,4 +403,21 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains(String.format("_sc|my_check.name|1|d:1420740000|h:i-abcd1234|#key2:val2,key1:val1|m:%s", outputMessage))); } + + @Test(timeout=5000L) public void + number_formatters_handles_nan() throws Exception { + ThreadLocal NUMBER_FORMATTERS = Whitebox.getInternalState(NonBlockingStatsDClient.class, "NUMBER_FORMATTERS"); + String formattedValue = NUMBER_FORMATTERS.get().format(Double.NaN); + + assertTrue(formattedValue.equals("NaN")); + } + + @Test(timeout=5000L) public void + sends_nan_gauge_to_statsd() throws Exception { + client.recordGaugeValue("mygauge", Double.NaN); + + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.mygauge:NaN|g")); + } } From 2aeb88d78f1c6ff5ca58ec8c30544f6776522809 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Sun, 9 Aug 2015 11:50:16 +0300 Subject: [PATCH 45/69] DEVOPS-322 : fixed readme to reflect correct usage of recordExecutionTime() --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index b44c325..bb0d08d 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,7 @@ public class Foo { statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ statsd.recordHistogram("qux", 15.5) /* ...also floating-point */ - /* Compatibility note: Unlike upstream statsd, DataDog expects execution times to be a - * floating-point value in seconds, not a millisecond value. This library - * does the conversion from ms to fractional seconds. + /* expects times in milliseconds */ statsd.recordExecutionTime("bag", 25, "cluster:foo"); /* DataDog extension: cluster tag */ } From ccfd0f87b447dc0d9d57a3b3041b6b19e5a25dde Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Sun, 9 Aug 2015 15:13:39 +0300 Subject: [PATCH 46/69] DEVOPS-323 : defend against RuntimeException, and clean up tests --- pom.xml | 6 ------ .../com/timgroup/statsd/NonBlockingStatsDClient.java | 9 ++++++--- .../timgroup/statsd/NonBlockingStatsDClientTest.java | 11 ----------- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/pom.xml b/pom.xml index 44c4f77..a4fa425 100644 --- a/pom.xml +++ b/pom.xml @@ -62,12 +62,6 @@ junit test - - org.powermock - powermock-module-junit4 - 1.6.2 - test -
    diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 3faea42..8504f92 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -69,9 +69,12 @@ protected NumberFormat initialValue() { numberFormatter.setMaximumFractionDigits(6); // we need to specify a value for Double.NaN that is recognized by dogStatsD - DecimalFormatSymbols symbols = ((DecimalFormat) numberFormatter).getDecimalFormatSymbols(); - symbols.setNaN("NaN"); - ((DecimalFormat) numberFormatter).setDecimalFormatSymbols(symbols); + if (numberFormatter instanceof DecimalFormat) { // better safe than a runtime error + final DecimalFormat decimalFormat = (DecimalFormat) numberFormatter; + final DecimalFormatSymbols symbols = decimalFormat.getDecimalFormatSymbols(); + symbols.setNaN("NaN"); + decimalFormat.setDecimalFormatSymbols(symbols); + } return numberFormatter; } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index b6ecb23..296931c 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -3,16 +3,13 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.powermock.reflect.Whitebox; import java.net.SocketException; -import java.text.NumberFormat; import java.util.Locale; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public class NonBlockingStatsDClientTest { @@ -404,14 +401,6 @@ public void stop() throws Exception { outputMessage))); } - @Test(timeout=5000L) public void - number_formatters_handles_nan() throws Exception { - ThreadLocal NUMBER_FORMATTERS = Whitebox.getInternalState(NonBlockingStatsDClient.class, "NUMBER_FORMATTERS"); - String formattedValue = NUMBER_FORMATTERS.get().format(Double.NaN); - - assertTrue(formattedValue.equals("NaN")); - } - @Test(timeout=5000L) public void sends_nan_gauge_to_statsd() throws Exception { client.recordGaugeValue("mygauge", Double.NaN); From c3892d05253d3dea46d1e2afb96efe6a00d42147 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Tue, 22 Dec 2015 01:33:39 +0000 Subject: [PATCH 47/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a4fa425..566a72f 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.13-SNAPSHOT + 2.0.13 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From ca218a289a18dc04b180948a242c73ccd069b7b1 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Tue, 22 Dec 2015 01:33:39 +0000 Subject: [PATCH 48/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 566a72f..c18fb53 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.13 + 2.0.14-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 4f5f022338c305c78684b909687e20e404893a75 Mon Sep 17 00:00:00 2001 From: Matthew Dyer Date: Mon, 14 Mar 2016 16:12:22 +1100 Subject: [PATCH 49/69] Don't cache DNS resolution forever --- .../statsd/NonBlockingStatsDClient.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 8504f92..3f6fe4f 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -1,6 +1,7 @@ package com.timgroup.statsd; import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; @@ -82,7 +83,6 @@ protected NumberFormat initialValue() { private final String prefix; private final DatagramChannel clientChannel; - private final InetSocketAddress address; private final StatsDClientErrorHandler handler; private final String constantTagsRendered; @@ -191,11 +191,10 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port, String[ try { this.clientChannel = DatagramChannel.open(); - this.address = new InetSocketAddress(hostname, port); } catch (Exception e) { throw new StatsDClientException("Failed to start StatsD client", e); } - this.executor.submit(new QueueConsumer()); + this.executor.submit(new QueueConsumer(hostname,port)); } /** @@ -549,9 +548,18 @@ private void send(String message) { public static final Charset MESSAGE_CHARSET = Charset.forName("UTF-8"); + private class QueueConsumer implements Runnable { private final ByteBuffer sendBuffer = ByteBuffer.allocate(PACKET_SIZE_BYTES); + private String hostname; + private int port; + + public QueueConsumer(String hostname, int port) { + this.hostname = hostname; + this.port = port; + } + @Override public void run() { while(!executor.isShutdown()) { try { @@ -578,6 +586,9 @@ private class QueueConsumer implements Runnable { private void blockingSend() throws IOException { int sizeOfBuffer = sendBuffer.position(); sendBuffer.flip(); + + InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(this.hostname),this.port); + int sentBytes = clientChannel.send(sendBuffer, address); sendBuffer.limit(sendBuffer.capacity()); sendBuffer.rewind(); From 1be1607dd806ad4a76a3f91343d3ca4299f593a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=A4mer?= Date: Fri, 18 Mar 2016 14:35:22 +1100 Subject: [PATCH 50/69] Externalise DNS resolution on the NonBlockingStatsDClient. Restores the old behaviour to resolve the address at construction time and cache it for the lifetime of the client. --- .../statsd/NonBlockingStatsDClient.java | 103 +++++++++++++++--- 1 file changed, 87 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 3f6fe4f..47126f0 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.charset.Charset; @@ -11,6 +12,7 @@ import java.text.NumberFormat; import java.util.Locale; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; @@ -118,7 +120,7 @@ protected NumberFormat initialValue() { * if the client could not be started */ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws StatsDClientException { - this(prefix, hostname, port, null, NO_OP_HANDLER); + this(prefix, hostname, port, null, null); } /** @@ -143,7 +145,7 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws * if the client could not be started */ public NonBlockingStatsDClient(String prefix, String hostname, int port, String... constantTags) throws StatsDClientException { - this(prefix, hostname, port, constantTags, NO_OP_HANDLER); + this(prefix, hostname, port, constantTags, null); } /** @@ -166,17 +168,48 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port, String. * @param constantTags * tags to be added to all content sent * @param errorHandler - * handler to use when an exception occurs during usage + * handler to use when an exception occurs during usage, may be null to indicate noop * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(String prefix, String hostname, int port, String[] constantTags, StatsDClientErrorHandler errorHandler) throws StatsDClientException { + public NonBlockingStatsDClient(String prefix, final String hostname, final int port, String[] constantTags, StatsDClientErrorHandler errorHandler) throws StatsDClientException { + this(prefix, constantTags, errorHandler, staticStatsDAddressResolution(hostname, port)); + } + + /** + * Create a new StatsD client communicating with a StatsD instance on the + * specified host and port. All messages send via this client will have + * their keys prefixed with the specified string. The new client will + * attempt to open a connection to the StatsD server immediately upon + * instantiation, and may throw an exception if that a connection cannot + * be established. Once a client has been instantiated in this way, all + * exceptions thrown during subsequent usage are passed to the specified + * handler and then consumed, guaranteeing that failures in metrics will + * not affect normal code execution. + * + * @param prefix + * the prefix to apply to keys sent via this client + * @param constantTags + * tags to be added to all content sent + * @param errorHandler + * handler to use when an exception occurs during usage, may be null to indicate noop + * @param addressLookup + * yields the IP address and socket of the StatsD server + * @throws StatsDClientException + * if the client could not be started + */ + public NonBlockingStatsDClient(String prefix, String[] constantTags, StatsDClientErrorHandler errorHandler, Callable addressLookup) throws StatsDClientException { if(prefix != null && prefix.length() > 0) { this.prefix = String.format("%s.", prefix); } else { this.prefix = ""; } - this.handler = errorHandler; + if(errorHandler == null) { + this.handler = NO_OP_HANDLER; + } + else { + this.handler = errorHandler; + } /* Empty list should be null for faster comparison */ if(constantTags != null && constantTags.length == 0) { @@ -194,7 +227,7 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port, String[ } catch (Exception e) { throw new StatsDClientException("Failed to start StatsD client", e); } - this.executor.submit(new QueueConsumer(hostname,port)); + this.executor.submit(new QueueConsumer(addressLookup)); } /** @@ -552,12 +585,10 @@ private void send(String message) { private class QueueConsumer implements Runnable { private final ByteBuffer sendBuffer = ByteBuffer.allocate(PACKET_SIZE_BYTES); - private String hostname; - private int port; + private final Callable addressLookup; - public QueueConsumer(String hostname, int port) { - this.hostname = hostname; - this.port = port; + public QueueConsumer(Callable addressLookup) { + this.addressLookup = addressLookup; } @Override public void run() { @@ -565,16 +596,17 @@ public QueueConsumer(String hostname, int port) { try { String message = queue.poll(1, TimeUnit.SECONDS); if(null != message) { + InetSocketAddress address = this.addressLookup.call(); byte[] data = message.getBytes(MESSAGE_CHARSET); if(sendBuffer.remaining() < (data.length + 1)) { - blockingSend(); + blockingSend(address); } if(sendBuffer.position() > 0) { sendBuffer.put( (byte) '\n'); } sendBuffer.put(data); if(null == queue.peek()) { - blockingSend(); + blockingSend(address); } } } catch (Exception e) { @@ -583,12 +615,10 @@ public QueueConsumer(String hostname, int port) { } } - private void blockingSend() throws IOException { + private void blockingSend(InetSocketAddress address) throws IOException { int sizeOfBuffer = sendBuffer.position(); sendBuffer.flip(); - InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(this.hostname),this.port); - int sentBytes = clientChannel.send(sendBuffer, address); sendBuffer.limit(sendBuffer.capacity()); sendBuffer.rewind(); @@ -606,4 +636,45 @@ private void blockingSend() throws IOException { } } } + + /** + * Create dynamic lookup for the given host name and port. + * + * @param hostname the host name of the targeted StatsD server + * @param port the port of the targeted StatsD server + * @return a function to perform the lookup + * @see NonBlockingStatsDClient#NonBlockingStatsDClient(String, String[], StatsDClientErrorHandler, Callable) + */ + public static Callable volatileAddressResolution(final String hostname, final int port) { + return new Callable() { + @Override public InetSocketAddress call() throws Exception { + return new InetSocketAddress(InetAddress.getByName(hostname), port); + } + }; + } + + /** + * Lookup the address for the given host name and cache the result. + * + * @param hostname the host name of the targeted StatsD server + * @param port the port of the targeted StatsD server + * @return a function that cached the result of the lookup + * @throws Exception if the lookup fails, i.e. {@link UnknownHostException} + */ + public static Callable staticAddressResolution(String hostname, int port) throws Exception { + final InetSocketAddress address = volatileAddressResolution(hostname, port).call(); + return new Callable() { + @Override public InetSocketAddress call() throws Exception { + return address; + } + }; + } + + private static Callable staticStatsDAddressResolution(String hostname, int port) throws StatsDClientException { + try { + return staticAddressResolution(hostname, port); + } catch (Exception e) { + throw new StatsDClientException("Failed to lookup StatsD host", e); + } + } } From 5c1bf6a5e3bea8c870483ee7d4c18bcf7f422acf Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Tue, 22 Mar 2016 13:21:23 +0900 Subject: [PATCH 51/69] DEVOPS-657 : minor style fixes - added finalizers - replaced 'throws Exception' where possible - removes 'this.' where possible --- .../statsd/NonBlockingStatsDClient.java | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 47126f0..b1c8d75 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -172,7 +172,8 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port, String. * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(String prefix, final String hostname, final int port, String[] constantTags, StatsDClientErrorHandler errorHandler) throws StatsDClientException { + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final String[] constantTags, + final StatsDClientErrorHandler errorHandler) throws StatsDClientException { this(prefix, constantTags, errorHandler, staticStatsDAddressResolution(hostname, port)); } @@ -198,36 +199,37 @@ public NonBlockingStatsDClient(String prefix, final String hostname, final int p * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(String prefix, String[] constantTags, StatsDClientErrorHandler errorHandler, Callable addressLookup) throws StatsDClientException { - if(prefix != null && prefix.length() > 0) { + public NonBlockingStatsDClient(final String prefix, String[] constantTags, final StatsDClientErrorHandler errorHandler, + final Callable addressLookup) throws StatsDClientException { + if((prefix != null) && (prefix.length() > 0)) { this.prefix = String.format("%s.", prefix); } else { this.prefix = ""; } if(errorHandler == null) { - this.handler = NO_OP_HANDLER; + handler = NO_OP_HANDLER; } else { - this.handler = errorHandler; + handler = errorHandler; } /* Empty list should be null for faster comparison */ - if(constantTags != null && constantTags.length == 0) { + if((constantTags != null) && (constantTags.length == 0)) { constantTags = null; } if(constantTags != null) { - this.constantTagsRendered = tagString(constantTags, null); + constantTagsRendered = tagString(constantTags, null); } else { - this.constantTagsRendered = null; + constantTagsRendered = null; } try { - this.clientChannel = DatagramChannel.open(); + clientChannel = DatagramChannel.open(); } catch (Exception e) { throw new StatsDClientException("Failed to start StatsD client", e); } - this.executor.submit(new QueueConsumer(addressLookup)); + executor.submit(new QueueConsumer(addressLookup)); } /** @@ -587,17 +589,17 @@ private class QueueConsumer implements Runnable { private final Callable addressLookup; - public QueueConsumer(Callable addressLookup) { + QueueConsumer(final Callable addressLookup) { this.addressLookup = addressLookup; } @Override public void run() { while(!executor.isShutdown()) { try { - String message = queue.poll(1, TimeUnit.SECONDS); + final String message = queue.poll(1, TimeUnit.SECONDS); if(null != message) { - InetSocketAddress address = this.addressLookup.call(); - byte[] data = message.getBytes(MESSAGE_CHARSET); + final InetSocketAddress address = this.addressLookup.call(); + final byte[] data = message.getBytes(MESSAGE_CHARSET); if(sendBuffer.remaining() < (data.length + 1)) { blockingSend(address); } @@ -609,17 +611,17 @@ public QueueConsumer(Callable addressLookup) { blockingSend(address); } } - } catch (Exception e) { + } catch (final Exception e) { handler.handle(e); } } } - private void blockingSend(InetSocketAddress address) throws IOException { - int sizeOfBuffer = sendBuffer.position(); + private void blockingSend(final InetSocketAddress address) throws IOException { + final int sizeOfBuffer = sendBuffer.position(); sendBuffer.flip(); - int sentBytes = clientChannel.send(sendBuffer, address); + final int sentBytes = clientChannel.send(sendBuffer, address); sendBuffer.limit(sendBuffer.capacity()); sendBuffer.rewind(); @@ -647,7 +649,7 @@ private void blockingSend(InetSocketAddress address) throws IOException { */ public static Callable volatileAddressResolution(final String hostname, final int port) { return new Callable() { - @Override public InetSocketAddress call() throws Exception { + @Override public InetSocketAddress call() throws UnknownHostException { return new InetSocketAddress(InetAddress.getByName(hostname), port); } }; @@ -661,19 +663,19 @@ public static Callable volatileAddressResolution(final String * @return a function that cached the result of the lookup * @throws Exception if the lookup fails, i.e. {@link UnknownHostException} */ - public static Callable staticAddressResolution(String hostname, int port) throws Exception { + public static Callable staticAddressResolution(final String hostname, final int port) throws Exception { final InetSocketAddress address = volatileAddressResolution(hostname, port).call(); return new Callable() { - @Override public InetSocketAddress call() throws Exception { + @Override public InetSocketAddress call() { return address; } }; } - private static Callable staticStatsDAddressResolution(String hostname, int port) throws StatsDClientException { + private static Callable staticStatsDAddressResolution(final String hostname, final int port) throws StatsDClientException { try { return staticAddressResolution(hostname, port); - } catch (Exception e) { + } catch (final Exception e) { throw new StatsDClientException("Failed to lookup StatsD host", e); } } From 64359b55e596a6e934ea854d483972cfc0ab5ce7 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Tue, 29 Mar 2016 00:06:13 +0000 Subject: [PATCH 52/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c18fb53..71eaef2 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.14-SNAPSHOT + 2.0.14 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From da8777b478f150dcf229c4bf9e4d0657b1b7d385 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Tue, 29 Mar 2016 00:06:13 +0000 Subject: [PATCH 53/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 71eaef2..35393fc 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.14 + 2.0.15-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 9030b1a6556e1e929bc172b536e30646485609f3 Mon Sep 17 00:00:00 2001 From: jonson Date: Fri, 1 Apr 2016 16:08:44 -0700 Subject: [PATCH 54/69] Add support for dogstatsd set values. --- .../com/timgroup/statsd/NoOpStatsDClient.java | 1 + .../statsd/NonBlockingStatsDClient.java | 26 +++++++++++++++++++ .../com/timgroup/statsd/StatsDClient.java | 19 ++++++++++++++ .../statsd/NonBlockingStatsDClientTest.java | 20 ++++++++++++++ 4 files changed, 66 insertions(+) diff --git a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java index 0c5bc01..0c9ea45 100644 --- a/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NoOpStatsDClient.java @@ -27,4 +27,5 @@ public final class NoOpStatsDClient implements StatsDClient { @Override public void recordEvent(final Event event, final String... tags) { } @Override public void recordServiceCheckRun(ServiceCheck sc) { } @Override public void serviceCheck(ServiceCheck sc) { } + @Override public void recordSetValue(String aspect, String value, String... tags) { } } diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index b1c8d75..490c0d5 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -35,6 +35,7 @@ *
  • {@link #recordExecutionTime} - records an execution time in milliseconds for the specified named operation
  • *
  • {@link #recordHistogramValue} - records a value, to be tracked with average, maximum, and percentiles
  • *
  • {@link #recordEvent} - records an event
  • + *
  • {@link #recordSetValue} - records a value in a set
  • * * From the perspective of the application, these methods are non-blocking, with the resulting * IO operations being carried out in a separate thread. Furthermore, these methods are guaranteed @@ -577,6 +578,31 @@ public void serviceCheck(final ServiceCheck sc) { recordServiceCheckRun(sc); } + + /** + * Records a value for the specified set. + * + * Sets are used to count the number of unique elements in a group. If you want to track the number of + * unique visitor to your site, sets are a great way to do that. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the set + * @param value + * the value to track + * @param tags + * array of tags to be added to the data + */ + @Override + public void recordSetValue(String aspect, String value, String... tags) { + // documentation is light, but looking at dogstatsd source, we can send string values + // here instead of numbers + send(String.format("%s%s:%s|s%s", prefix, aspect, value, tagString(tags))); + } + private void send(String message) { queue.offer(message); } diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index 0c5a0c9..c687f3f 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -207,4 +207,23 @@ public interface StatsDClient { */ void serviceCheck(ServiceCheck sc); + /** + * Records a value for the specified set. + * + * Sets are used to count the number of unique elements in a group. If you want to track the number of + * unique visitor to your site, sets are a great way to do that. + * + *

    This method is a DataDog extension, and may not work with other servers.

    + * + *

    This method is non-blocking and is guaranteed not to throw an exception.

    + * + * @param aspect + * the name of the set + * @param value + * the value to track + * @param tags + * array of tags to be added to the data + */ + void recordSetValue(String aspect, String value, String... tags); + } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 296931c..a8c94dc 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -409,4 +409,24 @@ public void stop() throws Exception { assertThat(server.messagesReceived(), contains("my.prefix.mygauge:NaN|g")); } + + @Test(timeout=5000L) public void + sends_set_to_statsd() throws Exception { + client.recordSetValue("myset", "myuserid"); + + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.myset:myuserid|s")); + + } + + @Test(timeout=5000L) public void + sends_set_to_statsd_with_tags() throws Exception { + client.recordSetValue("myset", "myuserid", "foo:bar", "baz"); + + server.waitForMessage(); + + assertThat(server.messagesReceived(), contains("my.prefix.myset:myuserid|s|#baz,foo:bar")); + + } } From eba2c74488b0b23e654d70cc94b2c268cfa682f1 Mon Sep 17 00:00:00 2001 From: jonson Date: Mon, 4 Apr 2016 08:14:07 -0700 Subject: [PATCH 55/69] Add link to dogstatsd sets extension. --- src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java | 2 ++ src/main/java/com/timgroup/statsd/StatsDClient.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 490c0d5..3cd90b0 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -595,6 +595,8 @@ public void serviceCheck(final ServiceCheck sc) { * the value to track * @param tags * array of tags to be added to the data + * + * @see http://docs.datadoghq.com/guides/dogstatsd/#sets */ @Override public void recordSetValue(String aspect, String value, String... tags) { diff --git a/src/main/java/com/timgroup/statsd/StatsDClient.java b/src/main/java/com/timgroup/statsd/StatsDClient.java index c687f3f..383f216 100644 --- a/src/main/java/com/timgroup/statsd/StatsDClient.java +++ b/src/main/java/com/timgroup/statsd/StatsDClient.java @@ -223,6 +223,8 @@ public interface StatsDClient { * the value to track * @param tags * array of tags to be added to the data + * + * @see http://docs.datadoghq.com/guides/dogstatsd/#sets */ void recordSetValue(String aspect, String value, String... tags); From 94a3ad3e0b971d322b8002003f9f5a5be3048034 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Tue, 5 Apr 2016 16:17:55 +0900 Subject: [PATCH 56/69] NOBUG : minor style adjustments and added final modifiers --- .../statsd/NonBlockingStatsDClient.java | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 3cd90b0..42d9980 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -53,7 +53,7 @@ public final class NonBlockingStatsDClient implements StatsDClient { private static final int PACKET_SIZE_BYTES = 1500; private static final StatsDClientErrorHandler NO_OP_HANDLER = new StatsDClientErrorHandler() { - @Override public void handle(Exception e) { /* No-op */ } + @Override public void handle(final Exception e) { /* No-op */ } }; /** @@ -68,7 +68,7 @@ protected NumberFormat initialValue() { // Always create the formatter for the US locale in order to avoid this bug: // https://github.com/indeedeng/java-dogstatsd-client/issues/3 - NumberFormat numberFormatter = NumberFormat.getInstance(Locale.US); + final NumberFormat numberFormatter = NumberFormat.getInstance(Locale.US); numberFormatter.setGroupingUsed(false); numberFormatter.setMaximumFractionDigits(6); @@ -91,8 +91,8 @@ protected NumberFormat initialValue() { private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() { final ThreadFactory delegate = Executors.defaultThreadFactory(); - @Override public Thread newThread(Runnable r) { - Thread result = delegate.newThread(r); + @Override public Thread newThread(final Runnable r) { + final Thread result = delegate.newThread(r); result.setName("StatsD-" + result.getName()); result.setDaemon(true); return result; @@ -120,7 +120,7 @@ protected NumberFormat initialValue() { * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(String prefix, String hostname, int port) throws StatsDClientException { + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port) throws StatsDClientException { this(prefix, hostname, port, null, null); } @@ -145,7 +145,7 @@ public NonBlockingStatsDClient(String prefix, String hostname, int port) throws * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(String prefix, String hostname, int port, String... constantTags) throws StatsDClientException { + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final String... constantTags) throws StatsDClientException { this(prefix, hostname, port, constantTags, null); } @@ -202,7 +202,7 @@ public NonBlockingStatsDClient(final String prefix, final String hostname, final */ public NonBlockingStatsDClient(final String prefix, String[] constantTags, final StatsDClientErrorHandler errorHandler, final Callable addressLookup) throws StatsDClientException { - if((prefix != null) && (prefix.length() > 0)) { + if((prefix != null) && (!prefix.isEmpty())) { this.prefix = String.format("%s.", prefix); } else { this.prefix = ""; @@ -227,7 +227,7 @@ public NonBlockingStatsDClient(final String prefix, String[] constantTags, final try { clientChannel = DatagramChannel.open(); - } catch (Exception e) { + } catch (final Exception e) { throw new StatsDClientException("Failed to start StatsD client", e); } executor.submit(new QueueConsumer(addressLookup)); @@ -243,7 +243,7 @@ public void stop() { executor.shutdown(); executor.awaitTermination(30, TimeUnit.SECONDS); } - catch (Exception e) { + catch (final Exception e) { handler.handle(e); } finally { @@ -251,7 +251,7 @@ public void stop() { try { clientChannel.close(); } - catch (IOException e) { + catch (final IOException e) { handler.handle(e); } } @@ -262,15 +262,15 @@ public void stop() { * Generate a suffix conveying the given tag list to the client */ static String tagString(final String[] tags, final String tagPrefix) { - StringBuilder sb; + final StringBuilder sb; if(tagPrefix != null) { - if(tags == null || tags.length == 0) { + if((tags == null) || (tags.length == 0)) { return tagPrefix; } sb = new StringBuilder(tagPrefix); sb.append(","); } else { - if(tags == null || tags.length == 0) { + if((tags == null) || (tags.length == 0)) { return ""; } sb = new StringBuilder("|#"); @@ -305,7 +305,7 @@ String tagString(final String[] tags) { * array of tags to be added to the data */ @Override - public void count(String aspect, long delta, String... tags) { + public void count(final String aspect, final long delta, final String... tags) { send(String.format("%s%s:%d|c%s", prefix, aspect, delta, tagString(tags))); } @@ -320,7 +320,7 @@ public void count(String aspect, long delta, String... tags) { * array of tags to be added to the data */ @Override - public void incrementCounter(String aspect, String... tags) { + public void incrementCounter(final String aspect, final String... tags) { count(aspect, 1, tags); } @@ -328,7 +328,7 @@ public void incrementCounter(String aspect, String... tags) { * Convenience method equivalent to {@link #incrementCounter(String, String[])}. */ @Override - public void increment(String aspect, String... tags) { + public void increment(final String aspect, final String... tags) { incrementCounter(aspect, tags); } @@ -343,7 +343,7 @@ public void increment(String aspect, String... tags) { * array of tags to be added to the data */ @Override - public void decrementCounter(String aspect, String... tags) { + public void decrementCounter(final String aspect, final String... tags) { count(aspect, -1, tags); } @@ -351,7 +351,7 @@ public void decrementCounter(String aspect, String... tags) { * Convenience method equivalent to {@link #decrementCounter(String, String[])}. */ @Override - public void decrement(String aspect, String... tags) { + public void decrement(final String aspect, final String... tags) { decrementCounter(aspect, tags); } @@ -368,7 +368,7 @@ public void decrement(String aspect, String... tags) { * array of tags to be added to the data */ @Override - public void recordGaugeValue(String aspect, double value, String... tags) { + public void recordGaugeValue(final String aspect, final double value, final String... tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ send(String.format("%s%s:%s|g%s", prefix, aspect, NUMBER_FORMATTERS.get().format(value), tagString(tags))); @@ -378,7 +378,7 @@ public void recordGaugeValue(String aspect, double value, String... tags) { * Convenience method equivalent to {@link #recordGaugeValue(String, double, String[])}. */ @Override - public void gauge(String aspect, double value, String... tags) { + public void gauge(final String aspect, final double value, final String... tags) { recordGaugeValue(aspect, value, tags); } @@ -396,7 +396,7 @@ public void gauge(String aspect, double value, String... tags) { * array of tags to be added to the data */ @Override - public void recordGaugeValue(String aspect, long value, String... tags) { + public void recordGaugeValue(final String aspect, final long value, final String... tags) { send(String.format("%s%s:%d|g%s", prefix, aspect, value, tagString(tags))); } @@ -404,7 +404,7 @@ public void recordGaugeValue(String aspect, long value, String... tags) { * Convenience method equivalent to {@link #recordGaugeValue(String, long, String[])}. */ @Override - public void gauge(String aspect, long value, String... tags) { + public void gauge(final String aspect, final long value, final String... tags) { recordGaugeValue(aspect, value, tags); } @@ -421,7 +421,7 @@ public void gauge(String aspect, long value, String... tags) { * array of tags to be added to the data */ @Override - public void recordExecutionTime(String aspect, long timeInMs, String... tags) { + public void recordExecutionTime(final String aspect, final long timeInMs, final String... tags) { send(String.format("%s%s:%d|ms%s", prefix, aspect, timeInMs, tagString(tags))); } @@ -429,7 +429,7 @@ public void recordExecutionTime(String aspect, long timeInMs, String... tags) { * Convenience method equivalent to {@link #recordExecutionTime(String, long, String[])}. */ @Override - public void time(String aspect, long value, String... tags) { + public void time(final String aspect, final long value, final String... tags) { recordExecutionTime(aspect, value, tags); } @@ -446,7 +446,7 @@ public void time(String aspect, long value, String... tags) { * array of tags to be added to the data */ @Override - public void recordHistogramValue(String aspect, double value, String... tags) { + public void recordHistogramValue(final String aspect, final double value, final String... tags) { /* Intentionally using %s rather than %f here to avoid * padding with extra 0s to represent precision */ send(String.format("%s%s:%s|h%s", prefix, aspect, NUMBER_FORMATTERS.get().format(value), tagString(tags))); @@ -456,7 +456,7 @@ public void recordHistogramValue(String aspect, double value, String... tags) { * Convenience method equivalent to {@link #recordHistogramValue(String, double, String[])}. */ @Override - public void histogram(String aspect, double value, String... tags) { + public void histogram(final String aspect, final double value, final String... tags) { recordHistogramValue(aspect, value, tags); } @@ -473,7 +473,7 @@ public void histogram(String aspect, double value, String... tags) { * array of tags to be added to the data */ @Override - public void recordHistogramValue(String aspect, long value, String... tags) { + public void recordHistogramValue(final String aspect, final long value, final String... tags) { send(String.format("%s%s:%d|h%s", prefix, aspect, value, tagString(tags))); } @@ -481,7 +481,7 @@ public void recordHistogramValue(String aspect, long value, String... tags) { * Convenience method equivalent to {@link #recordHistogramValue(String, long, String[])}. */ @Override - public void histogram(String aspect, long value, String... tags) { + public void histogram(final String aspect, final long value, final String... tags) { recordHistogramValue(aspect, value, tags); } @@ -599,13 +599,13 @@ public void serviceCheck(final ServiceCheck sc) { * @see http://docs.datadoghq.com/guides/dogstatsd/#sets */ @Override - public void recordSetValue(String aspect, String value, String... tags) { + public void recordSetValue(final String aspect, final String value, final String... tags) { // documentation is light, but looking at dogstatsd source, we can send string values // here instead of numbers send(String.format("%s%s:%s|s%s", prefix, aspect, value, tagString(tags))); } - private void send(String message) { + private void send(final String message) { queue.offer(message); } @@ -626,7 +626,7 @@ private class QueueConsumer implements Runnable { try { final String message = queue.poll(1, TimeUnit.SECONDS); if(null != message) { - final InetSocketAddress address = this.addressLookup.call(); + final InetSocketAddress address = addressLookup.call(); final byte[] data = message.getBytes(MESSAGE_CHARSET); if(sendBuffer.remaining() < (data.length + 1)) { blockingSend(address); From 0ed8d9150228edbc7604a60f6f30320134bfa351 Mon Sep 17 00:00:00 2001 From: Sean Freitag Date: Tue, 12 Apr 2016 10:50:04 -0500 Subject: [PATCH 57/69] Wiring in a queueSize constructor parameter for NonBlockingStatsDClient. --- README.md | 1 + .../statsd/NonBlockingStatsDClient.java | 48 +++++++++++++++---- .../statsd/NonBlockingStatsDClientTest.java | 4 +- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index bb0d08d..0b32336 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ public class Foo { "my.prefix", /* prefix to any stats; may be null or empty string */ "statsd-host", /* common case: localhost */ 8125, /* port */ + 10000, /* Maximum queue size before blocking, so that we prevent OOM */ new String[] {"tag:value"} /* DataDog extension: Constant tags, always applied */ ); diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 42d9980..a9a1fcd 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -99,7 +99,7 @@ protected NumberFormat initialValue() { } }); - private final BlockingQueue queue = new LinkedBlockingQueue(); + private final BlockingQueue queue; /** * Create a new StatsD client communicating with a StatsD instance on the @@ -121,7 +121,32 @@ protected NumberFormat initialValue() { * if the client could not be started */ public NonBlockingStatsDClient(final String prefix, final String hostname, final int port) throws StatsDClientException { - this(prefix, hostname, port, null, null); + this(prefix, hostname, port, Integer.MAX_VALUE); + } + + /** + * Create a new StatsD client communicating with a StatsD instance on the + * specified host and port. All messages send via this client will have + * their keys prefixed with the specified string. The new client will + * attempt to open a connection to the StatsD server immediately upon + * instantiation, and may throw an exception if that a connection cannot + * be established. Once a client has been instantiated in this way, all + * exceptions thrown during subsequent usage are consumed, guaranteeing + * that failures in metrics will not affect normal code execution. + * + * @param prefix + * the prefix to apply to keys sent via this client + * @param hostname + * the host name of the targeted StatsD server + * @param port + * the port of the targeted StatsD server + * @param queueSize + * the maximum amount of unprocessed messages in the BlockingQueue. + * @throws StatsDClientException + * if the client could not be started + */ + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final int queueSize) throws StatsDClientException { + this(prefix, hostname, port, queueSize, null, null); } /** @@ -142,11 +167,13 @@ public NonBlockingStatsDClient(final String prefix, final String hostname, final * the port of the targeted StatsD server * @param constantTags * tags to be added to all content sent + * @param queueSize + * the maximum amount of unprocessed messages in the BlockingQueue. * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final String... constantTags) throws StatsDClientException { - this(prefix, hostname, port, constantTags, null); + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final int queueSize, final String... constantTags) throws StatsDClientException { + this(prefix, hostname, port, queueSize, constantTags, null); } /** @@ -170,12 +197,14 @@ public NonBlockingStatsDClient(final String prefix, final String hostname, final * tags to be added to all content sent * @param errorHandler * handler to use when an exception occurs during usage, may be null to indicate noop + * @param queueSize + * the maximum amount of unprocessed messages in the BlockingQueue. * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final String[] constantTags, - final StatsDClientErrorHandler errorHandler) throws StatsDClientException { - this(prefix, constantTags, errorHandler, staticStatsDAddressResolution(hostname, port)); + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final int queueSize, + final String[] constantTags, final StatsDClientErrorHandler errorHandler) throws StatsDClientException { + this(prefix, queueSize, constantTags, errorHandler, staticStatsDAddressResolution(hostname, port)); } /** @@ -197,10 +226,12 @@ public NonBlockingStatsDClient(final String prefix, final String hostname, final * handler to use when an exception occurs during usage, may be null to indicate noop * @param addressLookup * yields the IP address and socket of the StatsD server + * @param queueSize + * the maximum amount of unprocessed messages in the BlockingQueue. * @throws StatsDClientException * if the client could not be started */ - public NonBlockingStatsDClient(final String prefix, String[] constantTags, final StatsDClientErrorHandler errorHandler, + public NonBlockingStatsDClient(final String prefix, final int queueSize, String[] constantTags, final StatsDClientErrorHandler errorHandler, final Callable addressLookup) throws StatsDClientException { if((prefix != null) && (!prefix.isEmpty())) { this.prefix = String.format("%s.", prefix); @@ -230,6 +261,7 @@ public NonBlockingStatsDClient(final String prefix, String[] constantTags, final } catch (final Exception e) { throw new StatsDClientException("Failed to start StatsD client", e); } + queue = new LinkedBlockingQueue(queueSize); executor.submit(new QueueConsumer(addressLookup)); } diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index a8c94dc..087d339 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -258,7 +258,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_gauge_mixed_tags() throws Exception { - final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, new String[] {"instance:foo", "app:bar"}); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, Integer.MAX_VALUE, "instance:foo", "app:bar"); empty_prefix_client.gauge("value", 423, "baz"); server.waitForMessage(); @@ -268,7 +268,7 @@ public void stop() throws Exception { @Test(timeout=5000L) public void sends_gauge_constant_tags_only() throws Exception { - final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, new String[] {"instance:foo", "app:bar"}); + final NonBlockingStatsDClient empty_prefix_client = new NonBlockingStatsDClient("my.prefix", "localhost", STATSD_SERVER_PORT, Integer.MAX_VALUE, "instance:foo", "app:bar"); empty_prefix_client.gauge("value", 423); server.waitForMessage(); From 043086bef2f8511c61c1bdc67fb56a8fd6a440f7 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Sun, 17 Apr 2016 21:54:02 +0900 Subject: [PATCH 58/69] COMMON-2075 : escape newlines in event text --- .../java/com/timgroup/statsd/NonBlockingStatsDClient.java | 8 ++++++-- .../com/timgroup/statsd/NonBlockingStatsDClientTest.java | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index a9a1fcd..0e6b51a 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -564,12 +564,16 @@ private String eventMap(final Event event) { */ @Override public void recordEvent(final Event event, final String... tags) { - final String title = prefix + event.getTitle(); - final String text = event.getText(); + final String title = escapeEventTitle(prefix + event.getTitle()); + final String text = escapeEventTitle(event.getText()); send(String.format("_e{%d,%d}:%s|%s%s%s", title.length(), text.length(), title, text, eventMap(event), tagString(tags))); } + private String escapeEventTitle(final String title) { + return title.replace("\n", "\\n"); + } + /** * Records a run status for the specified named service check. * diff --git a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java index 087d339..95799d1 100644 --- a/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java +++ b/src/test/java/com/timgroup/statsd/NonBlockingStatsDClientTest.java @@ -300,7 +300,7 @@ public void stop() throws Exception { final Event event = Event.builder() .withTitle("title1") - .withText("text1") + .withText("text1\nline2") .withDate(1234567000) .withHostname("host1") .withPriority(Event.Priority.LOW) @@ -310,7 +310,7 @@ public void stop() throws Exception { client.recordEvent(event); server.waitForMessage(); - assertThat(server.messagesReceived(), contains("_e{16,5}:my.prefix.title1|text1|d:1234567|h:host1|k:key1|p:low|t:error")); + assertThat(server.messagesReceived(), contains("_e{16,12}:my.prefix.title1|text1\\nline2|d:1234567|h:host1|k:key1|p:low|t:error")); } @Test(timeout=5000L) public void From 08c8a6ca95307fc994e7c27b0d6eb8c544236efd Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Mon, 18 Apr 2016 05:57:56 +0900 Subject: [PATCH 59/69] COMMON-2075 : rename method to be more accurate --- .../java/com/timgroup/statsd/NonBlockingStatsDClient.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 0e6b51a..84ba388 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -564,13 +564,13 @@ private String eventMap(final Event event) { */ @Override public void recordEvent(final Event event, final String... tags) { - final String title = escapeEventTitle(prefix + event.getTitle()); - final String text = escapeEventTitle(event.getText()); + final String title = escapeEventString(prefix + event.getTitle()); + final String text = escapeEventString(event.getText()); send(String.format("_e{%d,%d}:%s|%s%s%s", title.length(), text.length(), title, text, eventMap(event), tagString(tags))); } - private String escapeEventTitle(final String title) { + private String escapeEventString(final String title) { return title.replace("\n", "\\n"); } From ff808588074e8a53782c93218763a8036dd1d202 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Wed, 20 Apr 2016 01:01:07 +0000 Subject: [PATCH 60/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 35393fc..8a6e74c 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.15-SNAPSHOT + 2.0.15 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 1f2ccb6eb169f1bb7d7d396f246f0698e2957933 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Wed, 20 Apr 2016 01:01:07 +0000 Subject: [PATCH 61/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a6e74c..dcdce74 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.15 + 2.0.16-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 6598b0d89ee9dc04cb00034ee60869c22a9ca718 Mon Sep 17 00:00:00 2001 From: Avishai Weissberg Date: Wed, 20 Apr 2016 11:28:26 +0900 Subject: [PATCH 62/69] DEVOPS-657 : fix broken compatibility by re-adding removed c'tors --- .../statsd/NonBlockingStatsDClient.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 84ba388..cd0c0ae 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -149,6 +149,31 @@ public NonBlockingStatsDClient(final String prefix, final String hostname, final this(prefix, hostname, port, queueSize, null, null); } + /** + * Create a new StatsD client communicating with a StatsD instance on the + * specified host and port. All messages send via this client will have + * their keys prefixed with the specified string. The new client will + * attempt to open a connection to the StatsD server immediately upon + * instantiation, and may throw an exception if that a connection cannot + * be established. Once a client has been instantiated in this way, all + * exceptions thrown during subsequent usage are consumed, guaranteeing + * that failures in metrics will not affect normal code execution. + * + * @param prefix + * the prefix to apply to keys sent via this client + * @param hostname + * the host name of the targeted StatsD server + * @param port + * the port of the targeted StatsD server + * @param constantTags + * tags to be added to all content sent + * @throws StatsDClientException + * if the client could not be started + */ + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, final String... constantTags) throws StatsDClientException { + this(prefix, hostname, port, Integer.MAX_VALUE, constantTags, null); + } + /** * Create a new StatsD client communicating with a StatsD instance on the * specified host and port. All messages send via this client will have @@ -176,6 +201,35 @@ public NonBlockingStatsDClient(final String prefix, final String hostname, final this(prefix, hostname, port, queueSize, constantTags, null); } + /** + * Create a new StatsD client communicating with a StatsD instance on the + * specified host and port. All messages send via this client will have + * their keys prefixed with the specified string. The new client will + * attempt to open a connection to the StatsD server immediately upon + * instantiation, and may throw an exception if that a connection cannot + * be established. Once a client has been instantiated in this way, all + * exceptions thrown during subsequent usage are passed to the specified + * handler and then consumed, guaranteeing that failures in metrics will + * not affect normal code execution. + * + * @param prefix + * the prefix to apply to keys sent via this client + * @param hostname + * the host name of the targeted StatsD server + * @param port + * the port of the targeted StatsD server + * @param constantTags + * tags to be added to all content sent + * @param errorHandler + * handler to use when an exception occurs during usage, may be null to indicate noop + * @throws StatsDClientException + * if the client could not be started + */ + public NonBlockingStatsDClient(final String prefix, final String hostname, final int port, + final String[] constantTags, final StatsDClientErrorHandler errorHandler) throws StatsDClientException { + this(prefix, Integer.MAX_VALUE, constantTags, errorHandler, staticStatsDAddressResolution(hostname, port)); + } + /** * Create a new StatsD client communicating with a StatsD instance on the * specified host and port. All messages send via this client will have From 9e6b4e62bdd656a0ed997185dc40d1561195bfcb Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Wed, 20 Apr 2016 02:30:49 +0000 Subject: [PATCH 63/69] [maven-release-plugin] prepare release java-dogstatsd-client-2.0.16 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dcdce74..d6c1576 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.16-SNAPSHOT + 2.0.16 A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 549b81083c70580db22c75e71d787eec5cf592b0 Mon Sep 17 00:00:00 2001 From: Release Engineering Date: Wed, 20 Apr 2016 02:30:49 +0000 Subject: [PATCH 64/69] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d6c1576..36f1061 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ java-dogstatsd-client jar java-dogstatsd-client - 2.0.16 + 2.0.17-SNAPSHOT A tiny library allowing Java applications to communicate with DataDog statsd instances easily. https://github.com/indeedeng/java-dogstatsd-client From 158a2f96a24fa26ca165f97f4a4a4e458f7009b6 Mon Sep 17 00:00:00 2001 From: Ilan Rabinovitch Date: Mon, 13 Jun 2016 14:02:10 -0700 Subject: [PATCH 65/69] Minor corrections on capitalization of Datadog Minor corrections on capitalization of Datadog --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0b32336..8a79b69 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ java-dogstatsd-client A statsd client library implemented in Java. Allows for Java applications to easily communicate with statsd. -This version is forked from the upstream [java-statsd-client](https://github.com/youdevise/java-statsd-client) project, adding support for [DataDog](http://datadoghq.com/) extensions for use with [dogstatsd](http://docs.datadoghq.com/guides/dogstatsd/). +This version is forked from the upstream [java-statsd-client](https://github.com/youdevise/java-statsd-client) project, adding support for [Datadog](http://datadoghq.com/) extensions for use with [dogstatsd](http://docs.datadoghq.com/guides/dogstatsd/). This version also adds support for empty or null prefixes, to allow a client to send arbitrary statistic names. @@ -32,19 +32,19 @@ public class Foo { "statsd-host", /* common case: localhost */ 8125, /* port */ 10000, /* Maximum queue size before blocking, so that we prevent OOM */ - new String[] {"tag:value"} /* DataDog extension: Constant tags, always applied */ + new String[] {"tag:value"} /* Datadog extension: Constant tags, always applied */ ); public static final void main(String[] args) { statsd.incrementCounter("foo"); statsd.recordGaugeValue("bar", 100); - statsd.recordGaugeValue("baz", 0.01); /* DataDog extension: support for floating-point gauges */ - statsd.recordHistogram("qux", 15) /* DataDog extension: histograms */ + statsd.recordGaugeValue("baz", 0.01); /* Datadog extension: support for floating-point gauges */ + statsd.recordHistogram("qux", 15) /* Datadog extension: histograms */ statsd.recordHistogram("qux", 15.5) /* ...also floating-point */ /* expects times in milliseconds */ - statsd.recordExecutionTime("bag", 25, "cluster:foo"); /* DataDog extension: cluster tag */ + statsd.recordExecutionTime("bag", 25, "cluster:foo"); /* Datadog extension: cluster tag */ } } ``` From 00d96f14ab44879cc80419cf7fe8731da6082e05 Mon Sep 17 00:00:00 2001 From: Mingyu Liu Date: Thu, 23 Jun 2016 21:56:19 -0700 Subject: [PATCH 66/69] Update maven repository link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a79b69..8d3de91 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This version also adds support for empty or null prefixes, to allow a client to Downloads --------- -The client jar is distributed via maven central, and can be downloaded [here](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.timgroup%20a%3Ajava-statsd-client). +The client jar is distributed via maven central, and can be downloaded [here](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.indeed%20a%3Ajava-dogstatsd-client). ```xml From 4f11defc7a78a51cbc8cac704f21f450c8f43383 Mon Sep 17 00:00:00 2001 From: Dan Rollo Date: Thu, 30 Jun 2016 10:35:43 -0400 Subject: [PATCH 67/69] Fix syntax errors in example code. --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8a79b69..090852e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The client jar is distributed via maven central, and can be downloaded [here](ht com.indeed java-dogstatsd-client - 2.0.12 + 2.0.16 ``` @@ -31,7 +31,6 @@ public class Foo { "my.prefix", /* prefix to any stats; may be null or empty string */ "statsd-host", /* common case: localhost */ 8125, /* port */ - 10000, /* Maximum queue size before blocking, so that we prevent OOM */ new String[] {"tag:value"} /* Datadog extension: Constant tags, always applied */ ); @@ -39,8 +38,8 @@ public class Foo { statsd.incrementCounter("foo"); statsd.recordGaugeValue("bar", 100); statsd.recordGaugeValue("baz", 0.01); /* Datadog extension: support for floating-point gauges */ - statsd.recordHistogram("qux", 15) /* Datadog extension: histograms */ - statsd.recordHistogram("qux", 15.5) /* ...also floating-point */ + statsd.recordHistogramValue("qux", 15); /* Datadog extension: histograms */ + statsd.recordHistogramValue("qux", 15.5); /* ...also floating-point */ /* expects times in milliseconds */ From 8fd18a9ef12c375e63c9737a591c1d05158c7906 Mon Sep 17 00:00:00 2001 From: Ilan Rabinovitch Date: Wed, 17 Aug 2016 01:11:10 -0700 Subject: [PATCH 68/69] Update readme to direct folks to new merged repo Update readme to direct folks to new merged repo --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 42839e8..734fa1f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# Project Moved + +This project has merged with [datadog/java-dogstatsd-client](http://github.com/datadog/java-dogstatsd-client). This repository primarily exists for historical purposes. Please file issues and pull requests at [datadog/java-dogstatsd-client](http://github.com/datadog/java-dogstatsd-client). + + java-dogstatsd-client ================== From 1ec40103c834fc05468a3812c924a25e59bc8a87 Mon Sep 17 00:00:00 2001 From: Ilan Rabinovitch Date: Wed, 17 Aug 2016 01:15:01 -0700 Subject: [PATCH 69/69] new issue and PR templates --- .github/ISSUE_TEMPLATE.md | 1 + .github/PULL_REQUEST_TEMPLATE.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..1804c8c --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1 @@ +This project has merged with datadog/java-dogstatsd-client and now lives in a new home at: http://datadog/java-dogstatsd-client. This repository primarily exists for historical purposes. Please file new issues and pull requests at datadog/java-dogstatsd-client. \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..1804c8c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1 @@ +This project has merged with datadog/java-dogstatsd-client and now lives in a new home at: http://datadog/java-dogstatsd-client. This repository primarily exists for historical purposes. Please file new issues and pull requests at datadog/java-dogstatsd-client. \ No newline at end of file