All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.timgroup.statsd.StatsDClient Maven / Gradle / Ivy

Go to download

A tiny library allowing Java applications to communicate with statsd instances easily.

There is a newer version: 3.1.0
Show newest version
package com.timgroup.statsd;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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: *

    *
  • {@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
  • *
* 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 * 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 StatsDClient { private static final StatsDClientErrorHandler NO_OP_HANDLER = new StatsDClientErrorHandler() { @Override public void handle(Exception e) { /* No-op */ } }; private final String prefix; private final DatagramSocket clientSocket; private final StatsDClientErrorHandler handler; private final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() { final ThreadFactory delegate = Executors.defaultThreadFactory(); @Override public Thread newThread(Runnable r) { Thread result = delegate.newThread(r); result.setName("StatsD-" + result.getName()); return result; } }); /** * 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 * @throws StatsDClientException * if the client could not be started */ public StatsDClient(String prefix, String hostname, int port) throws StatsDClientException { this(prefix, hostname, port, 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 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 errorHandler * handler to use when an exception occurs during usage * @throws StatsDClientException * if the client could not be started */ public StatsDClient(String prefix, String hostname, int port, StatsDClientErrorHandler errorHandler) throws StatsDClientException { this.prefix = prefix; this.handler = errorHandler; try { this.clientSocket = new DatagramSocket(); this.clientSocket.connect(new InetSocketAddress(hostname, port)); } catch (Exception e) { throw new StatsDClientException("Failed to start StatsD client", e); } } /** * Cleanly shut down this StatsD client. This method may throw an exception if * the socket cannot be closed. */ public void stop() { try { executor.shutdown(); executor.awaitTermination(30, TimeUnit.SECONDS); } catch (Exception e) { handler.handle(e); } finally { if (clientSocket != null) { clientSocket.close(); } } } /** * 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 */ 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 */ public void incrementCounter(String aspect) { count(aspect, 1); } /** * Convenience method equivalent to {@link #incrementCounter(String)}. */ 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 */ public void decrementCounter(String aspect) { count(aspect, -1); } /** * Convenience method equivalent to {@link #decrementCounter(String)}. */ 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 */ public void recordGaugeValue(String aspect, int value) { send(String.format("%s.%s:%d|g", prefix, aspect, value)); } /** * Convenience method equivalent to {@link #recordGaugeValue(String)}. */ 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 */ public void recordExecutionTime(String aspect, int timeInMs) { send(String.format("%s.%s:%d|ms", prefix, aspect, timeInMs)); } /** * Convenience method equivalent to {@link #recordExecutionTime(String)}. */ public void time(String aspect, int value) { recordExecutionTime(aspect, value); } private void send(final String message) { try { executor.execute(new Runnable() { @Override public void run() { blockingSend(message); } }); } 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); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy