Skip to content

Commit

Permalink
Added tests and simple buffered messenger
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbodart committed Apr 17, 2016
1 parent e61ec4f commit d538c53
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 75 deletions.
27 changes: 27 additions & 0 deletions src/com/googlecode/utterlyidle/statsd/BufferedMessenger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.googlecode.utterlyidle.statsd;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import static com.googlecode.totallylazy.Sequences.sequence;

public class BufferedMessenger implements Messenger {
private final Messenger messenger;
private final List<String> buffer = new CopyOnWriteArrayList<>();

public BufferedMessenger(Messenger messenger) {
this.messenger = messenger;
}

@Override
public void message(Iterable<? extends String> values) throws IOException {
buffer.addAll(sequence(values));
}

@Override
public void close() throws IOException {
messenger.message(buffer);
buffer.clear();
}
}
23 changes: 23 additions & 0 deletions src/com/googlecode/utterlyidle/statsd/Messenger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.googlecode.utterlyidle.statsd;

import java.io.Closeable;
import java.io.IOException;

import static com.googlecode.totallylazy.Sequences.cons;
import static com.googlecode.totallylazy.Sequences.sequence;

public interface Messenger extends Closeable {
void message(Iterable<? extends String> values) throws IOException;

default void message(String head, String... tail) throws IOException {
message(cons(head, sequence(tail)));
}

@Override
default void close() throws IOException {
}

static Messenger messager() throws IOException {
return value -> { };
}
}
119 changes: 47 additions & 72 deletions src/com/googlecode/utterlyidle/statsd/StatsDClient.java
Original file line number Diff line number Diff line change
@@ -1,121 +1,96 @@
package com.googlecode.utterlyidle.statsd;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.DatagramChannel;

import static com.googlecode.totallylazy.Bytes.bytes;
import static java.lang.String.format;
import static java.nio.ByteBuffer.wrap;
/*
Taken from https://github.com/b/statsd_spec

/**
* Taken from https://github.com/b/statsd_spec
*/
public interface StatsDClient extends Closeable {
public interface StatsDClient {
static StatsDClient statsDClient(String host, int port) throws IOException {
return statsDClient(new InetSocketAddress(host, port));
}

static StatsDClient statsDClient(SocketAddress socketAddress) throws IOException {
return statsDClient(Messager.messager(socketAddress));
return statsDClient(UdpMessenger.udpMessager(socketAddress));
}

static StatsDClient statsDClient(final Messager messager) {
return () -> messager;
static StatsDClient statsDClient(final Messenger messenger) {
return () -> messenger;
}

Messager messager();

/*
A gauge is an instantaneous measurement of a value, like the gas gauge in a car. It differs from a counter by being
calculated at the client rather than the server. Valid gauge values are in the range [0, 2^64^)
Messenger messager();

<metric name>:<value>|g
/**
* A gauge is an instantaneous measurement of a value, like the gas gauge in a car. It differs from a counter by being
* calculated at the client rather than the server. Valid gauge values are in the range [0, 2^64^)
* <p>
* metric name:value|g
*/
default void gauge(String name, long value) throws IOException {
assert value >= 0;
messager().message(format("%s:%d|g", name, value));
}

/*
A counter is a gauge calculated at the server. Metrics sent by the client increment or decrement the value of the
gauge rather than giving its current value. Counters may also have an associated sample rate, given as a decimal of
the number of samples per event count. For example, a sample rate of 1/10 would be exported as 0.1. Valid counter
values are in the range (-2^63^, 2^63^).
<metric name>:<value>|c[|@<sample rate>]
*/
/**
* A counter is a gauge calculated at the server. Metrics sent by the client increment or decrement the value of the
* gauge rather than giving its current value. Counters may also have an associated sample rate, given as a decimal of
* the number of samples per event count. For example, a sample rate of 1/10 would be exported as 0.1. Valid counter
* values are in the range (-2^63^, 2^63^).
* <p>
* metric name:value|c
*/
default void counter(String name, long value) throws IOException {
messager().message(format("%s:%d|c", name, value));
}

/**
* A counter is a gauge calculated at the server. Metrics sent by the client increment or decrement the value of the
* gauge rather than giving its current value. Counters may also have an associated sample rate, given as a decimal of
* the number of samples per event count. For example, a sample rate of 1/10 would be exported as 0.1. Valid counter
* values are in the range (-2^63^, 2^63^).
* <p>
* metric name:value|c|@sample rate
*/
default void counter(String name, long value, float sampleRate) throws IOException {
messager().message(format("%s:%d|c|@%f", name, value, sampleRate));
}

/*
A timer is a measure of the number of milliseconds elapsed between a start and end time, for example the time to
complete rendering of a web page for a user. Valid timer values are in the range [0, 2^64^).
<metric name>:<value>|ms
*/
/**
* A timer is a measure of the number of milliseconds elapsed between a start and end time, for example the time to
* complete rendering of a web page for a user. Valid timer values are in the range [0, 2^64^).
* <p>
* metric name:value|ms
*/
default void timer(String name, long value) throws IOException {
assert value >= 0;
messager().message(format("%s:%d|ms", name, value));
}

/*
A histogram is a measure of the distribution of timer values over time, calculated at the server. As the data
exported for timers and histograms is the same, this is currently an alias for a timer. Valid histogram values are
in the range [0, 2^64^).
<metric name>:<value>|h
*/
/**
* A histogram is a measure of the distribution of timer values over time, calculated at the server. As the data
* exported for timers and histograms is the same, this is currently an alias for a timer. Valid histogram values are
* in the range [0, 2^64^).
* <p>
* metric name:value|h
*/
default void histogram(String name, long value) throws IOException {
assert value >= 0;
messager().message(format("%s:%d|h", name, value));
}

/*
A meter measures the rate of events over time, calculated at the server. They may also be thought of as
increment-only counters. Valid meter values are in the range [0, 2^64^).
<metric name>:<value>|m
/**
* A meter measures the rate of events over time, calculated at the server. They may also be thought of as
* increment-only counters. Valid meter values are in the range [0, 2^64^).
* <p>
* metric name:value|m
*/
default void meter(String name, long value) throws IOException {
assert value >= 0;
messager().message(format("%s:%d|m", name, value));
}

@Override
default void close() throws IOException {
messager().close();
}

interface Messager extends Closeable {
void message(String value) throws IOException;

@Override
default void close() throws IOException{}

static Messager messager() throws IOException {
return value -> {};
}

static Messager messager(SocketAddress socketAddress) throws IOException {
DatagramChannel channel = DatagramChannel.open().connect(socketAddress);
return new Messager() {
@Override
public void message(String value) throws IOException {
channel.write(wrap(bytes(value + '\n')));
}

@Override
public void close() throws IOException {
channel.close();
}
};
}
}
}
38 changes: 38 additions & 0 deletions src/com/googlecode/utterlyidle/statsd/UdpMessenger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.googlecode.utterlyidle.statsd;

import com.googlecode.totallylazy.LazyException;

import java.io.IOException;
import java.net.SocketAddress;
import java.nio.channels.DatagramChannel;

import static com.googlecode.totallylazy.Bytes.bytes;
import static com.googlecode.totallylazy.Sequences.sequence;
import static java.nio.ByteBuffer.wrap;

public class UdpMessenger implements Messenger {
private final DatagramChannel channel;

public UdpMessenger(DatagramChannel channel) {
this.channel = channel;
}


public static UdpMessenger udpMessager(SocketAddress socketAddress) {
try {
return new UdpMessenger(DatagramChannel.open().connect(socketAddress));
} catch (IOException e) {
throw LazyException.lazyException(e);
}
}

@Override
public void message(Iterable<? extends String> values) throws IOException {
channel.write(wrap(bytes(sequence(values).toString("\n"))));
}

@Override
public void close() throws IOException {
channel.close();
}
}
29 changes: 26 additions & 3 deletions test/com/googlecode/utterlyidle/statsd/StatsDClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,40 @@
import static com.googlecode.totallylazy.predicates.Predicates.is;
import static com.googlecode.utterlyidle.statsd.StatsDClient.statsDClient;

@Ignore("Manual test currently")
public class StatsDClientTest {
List<String> messages = new ArrayList<>();
StatsDClient client = statsDClient(messages::add);
private List<String> messages = new ArrayList<>();
private StatsDClient client = statsDClient(values -> messages.addAll(sequence(values)));

@Test
public void supportsGauge() throws Exception {
client.gauge("foo.bar", 1);
assertThat(messages, is(sequence("foo.bar:1|g")));
}

@Test
public void supportsCounter() throws Exception {
client.counter("foo.bar", 1);
assertThat(messages, is(sequence("foo.bar:1|c")));
}

@Test
public void supportsCounterWithSample() throws Exception {
client.counter("foo.bar", 1, 0.5f);
assertThat(messages, is(sequence("foo.bar:1|c|@0.500000")));
}

@Test
public void supportsTimer() throws Exception {
client.timer("foo.bar", 1);
assertThat(messages, is(sequence("foo.bar:1|ms")));
}

@Test
public void supportsHistogram() throws Exception {
client.histogram("foo.bar", 1);
assertThat(messages, is(sequence("foo.bar:1|h")));
}

@Test
public void supportsMeter() throws Exception {
client.meter("foo.bar", 1);
Expand Down

0 comments on commit d538c53

Please sign in to comment.