package com.codahale.metrics;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

A registry of metric instances.
/** * A registry of metric instances. */
public class MetricRegistry implements MetricSet {
Concatenates elements to form a dotted name, eliding any null values or empty strings.
Params:
  • name – the first element of the name
  • names – the remaining elements of the name
Returns:name and names concatenated by periods
/** * Concatenates elements to form a dotted name, eliding any null values or empty strings. * * @param name the first element of the name * @param names the remaining elements of the name * @return {@code name} and {@code names} concatenated by periods */
public static String name(String name, String... names) { final StringBuilder builder = new StringBuilder(); append(builder, name); if (names != null) { for (String s : names) { append(builder, s); } } return builder.toString(); }
Concatenates a class name and elements to form a dotted name, eliding any null values or empty strings.
Params:
  • klass – the first element of the name
  • names – the remaining elements of the name
Returns:klass and names concatenated by periods
/** * Concatenates a class name and elements to form a dotted name, eliding any null values or * empty strings. * * @param klass the first element of the name * @param names the remaining elements of the name * @return {@code klass} and {@code names} concatenated by periods */
public static String name(Class<?> klass, String... names) { return name(klass.getName(), names); } private static void append(StringBuilder builder, String part) { if (part != null && !part.isEmpty()) { if (builder.length() > 0) { builder.append('.'); } builder.append(part); } } private final ConcurrentMap<String, Metric> metrics; private final List<MetricRegistryListener> listeners;
Creates a new MetricRegistry.
/** * Creates a new {@link MetricRegistry}. */
public MetricRegistry() { this.metrics = buildMap(); this.listeners = new CopyOnWriteArrayList<>(); }
Creates a new ConcurrentMap implementation for use inside the registry. Override this to create a MetricRegistry with space- or time-bounded metric lifecycles, for example.
Returns:a new ConcurrentMap
/** * Creates a new {@link ConcurrentMap} implementation for use inside the registry. Override this * to create a {@link MetricRegistry} with space- or time-bounded metric lifecycles, for * example. * * @return a new {@link ConcurrentMap} */
protected ConcurrentMap<String, Metric> buildMap() { return new ConcurrentHashMap<>(); }
Given a Metric, registers it under the given name.
Params:
  • name – the name of the metric
  • metric – the metric
Type parameters:
  • <T> – the type of the metric
Throws:
Returns:metric
/** * Given a {@link Metric}, registers it under the given name. * * @param name the name of the metric * @param metric the metric * @param <T> the type of the metric * @return {@code metric} * @throws IllegalArgumentException if the name is already registered */
@SuppressWarnings("unchecked") public <T extends Metric> T register(String name, T metric) throws IllegalArgumentException { if (metric instanceof MetricRegistry) { final MetricRegistry childRegistry = (MetricRegistry)metric; final String childName = name; childRegistry.addListener(new MetricRegistryListener() { @Override public void onGaugeAdded(String name, Gauge<?> gauge) { register(name(childName, name), gauge); } @Override public void onGaugeRemoved(String name) { remove(name(childName, name)); } @Override public void onCounterAdded(String name, Counter counter) { register(name(childName, name), counter); } @Override public void onCounterRemoved(String name) { remove(name(childName, name)); } @Override public void onHistogramAdded(String name, Histogram histogram) { register(name(childName, name), histogram); } @Override public void onHistogramRemoved(String name) { remove(name(childName, name)); } @Override public void onMeterAdded(String name, Meter meter) { register(name(childName, name), meter); } @Override public void onMeterRemoved(String name) { remove(name(childName, name)); } @Override public void onTimerAdded(String name, Timer timer) { register(name(childName, name), timer); } @Override public void onTimerRemoved(String name) { remove(name(childName, name)); } }); } else if (metric instanceof MetricSet) { registerAll(name, (MetricSet) metric); } else { final Metric existing = metrics.putIfAbsent(name, metric); if (existing == null) { onMetricAdded(name, metric); } else { throw new IllegalArgumentException("A metric named " + name + " already exists"); } } return metric; }
Given a metric set, registers them.
Params:
  • metrics – a set of metrics
Throws:
/** * Given a metric set, registers them. * * @param metrics a set of metrics * @throws IllegalArgumentException if any of the names are already registered */
public void registerAll(MetricSet metrics) throws IllegalArgumentException { registerAll(null, metrics); }
Return the Counter registered under this name; or create and register a new Counter if none is registered.
Params:
  • name – the name of the metric
Returns:a new or pre-existing Counter
/** * Return the {@link Counter} registered under this name; or create and register * a new {@link Counter} if none is registered. * * @param name the name of the metric * @return a new or pre-existing {@link Counter} */
public Counter counter(String name) { return getOrAdd(name, MetricBuilder.COUNTERS); }
Return the Counter registered under this name; or create and register a new Counter using the provided MetricSupplier if none is registered.
Params:
  • name – the name of the metric
  • supplier – a MetricSupplier that can be used to manufacture a counter.
Returns:a new or pre-existing Counter
/** * Return the {@link Counter} registered under this name; or create and register * a new {@link Counter} using the provided MetricSupplier if none is registered. * * @param name the name of the metric * @param supplier a MetricSupplier that can be used to manufacture a counter. * @return a new or pre-existing {@link Counter} */
public Counter counter(String name, final MetricSupplier<Counter> supplier) { return getOrAdd(name, new MetricBuilder<Counter>() { @Override public Counter newMetric() { return supplier.newMetric(); } @Override public boolean isInstance(Metric metric) { return Counter.class.isInstance(metric); } }); }
Return the Histogram registered under this name; or create and register a new Histogram if none is registered.
Params:
  • name – the name of the metric
Returns:a new or pre-existing Histogram
/** * Return the {@link Histogram} registered under this name; or create and register * a new {@link Histogram} if none is registered. * * @param name the name of the metric * @return a new or pre-existing {@link Histogram} */
public Histogram histogram(String name) { return getOrAdd(name, MetricBuilder.HISTOGRAMS); }
Return the Histogram registered under this name; or create and register a new Histogram using the provided MetricSupplier if none is registered.
Params:
  • name – the name of the metric
  • supplier – a MetricSupplier that can be used to manufacture a histogram
Returns:a new or pre-existing Histogram
/** * Return the {@link Histogram} registered under this name; or create and register * a new {@link Histogram} using the provided MetricSupplier if none is registered. * * @param name the name of the metric * @param supplier a MetricSupplier that can be used to manufacture a histogram * @return a new or pre-existing {@link Histogram} */
public Histogram histogram(String name, final MetricSupplier<Histogram> supplier) { return getOrAdd(name, new MetricBuilder<Histogram>() { @Override public Histogram newMetric() { return supplier.newMetric(); } @Override public boolean isInstance(Metric metric) { return Histogram.class.isInstance(metric); } }); }
Return the Meter registered under this name; or create and register a new Meter if none is registered.
Params:
  • name – the name of the metric
Returns:a new or pre-existing Meter
/** * Return the {@link Meter} registered under this name; or create and register * a new {@link Meter} if none is registered. * * @param name the name of the metric * @return a new or pre-existing {@link Meter} */
public Meter meter(String name) { return getOrAdd(name, MetricBuilder.METERS); }
Return the Meter registered under this name; or create and register a new Meter using the provided MetricSupplier if none is registered.
Params:
  • name – the name of the metric
  • supplier – a MetricSupplier that can be used to manufacture a Meter
Returns:a new or pre-existing Meter
/** * Return the {@link Meter} registered under this name; or create and register * a new {@link Meter} using the provided MetricSupplier if none is registered. * * @param name the name of the metric * @param supplier a MetricSupplier that can be used to manufacture a Meter * @return a new or pre-existing {@link Meter} */
public Meter meter(String name, final MetricSupplier<Meter> supplier) { return getOrAdd(name, new MetricBuilder<Meter>() { @Override public Meter newMetric() { return supplier.newMetric(); } @Override public boolean isInstance(Metric metric) { return Meter.class.isInstance(metric); } }); }
Return the Timer registered under this name; or create and register a new Timer if none is registered.
Params:
  • name – the name of the metric
Returns:a new or pre-existing Timer
/** * Return the {@link Timer} registered under this name; or create and register * a new {@link Timer} if none is registered. * * @param name the name of the metric * @return a new or pre-existing {@link Timer} */
public Timer timer(String name) { return getOrAdd(name, MetricBuilder.TIMERS); }
Return the Timer registered under this name; or create and register a new Timer using the provided MetricSupplier if none is registered.
Params:
  • name – the name of the metric
  • supplier – a MetricSupplier that can be used to manufacture a Timer
Returns:a new or pre-existing Timer
/** * Return the {@link Timer} registered under this name; or create and register * a new {@link Timer} using the provided MetricSupplier if none is registered. * * @param name the name of the metric * @param supplier a MetricSupplier that can be used to manufacture a Timer * @return a new or pre-existing {@link Timer} */
public Timer timer(String name, final MetricSupplier<Timer> supplier) { return getOrAdd(name, new MetricBuilder<Timer>() { @Override public Timer newMetric() { return supplier.newMetric(); } @Override public boolean isInstance(Metric metric) { return Timer.class.isInstance(metric); } }); }
Return the Gauge registered under this name; or create and register a new Gauge using the provided MetricSupplier if none is registered.
Params:
  • name – the name of the metric
  • supplier – a MetricSupplier that can be used to manufacture a Gauge
Returns:a new or pre-existing Gauge
/** * Return the {@link Gauge} registered under this name; or create and register * a new {@link Gauge} using the provided MetricSupplier if none is registered. * * @param name the name of the metric * @param supplier a MetricSupplier that can be used to manufacture a Gauge * @return a new or pre-existing {@link Gauge} */
@SuppressWarnings("rawtypes") public Gauge gauge(String name, final MetricSupplier<Gauge> supplier) { return getOrAdd(name, new MetricBuilder<Gauge>() { @Override public Gauge newMetric() { return supplier.newMetric(); } @Override public boolean isInstance(Metric metric) { return Gauge.class.isInstance(metric); } }); }
Removes the metric with the given name.
Params:
  • name – the name of the metric
Returns:whether or not the metric was removed
/** * Removes the metric with the given name. * * @param name the name of the metric * @return whether or not the metric was removed */
public boolean remove(String name) { final Metric metric = metrics.remove(name); if (metric != null) { onMetricRemoved(name, metric); return true; } return false; }
Removes all metrics which match the given filter.
Params:
  • filter – a filter
/** * Removes all metrics which match the given filter. * * @param filter a filter */
public void removeMatching(MetricFilter filter) { for (Map.Entry<String, Metric> entry : metrics.entrySet()) { if (filter.matches(entry.getKey(), entry.getValue())) { remove(entry.getKey()); } } }
Adds a MetricRegistryListener to a collection of listeners that will be notified on metric creation. Listeners will be notified in the order in which they are added.

N.B.: The listener will be notified of all existing metrics when it first registers.

Params:
  • listener – the listener that will be notified
/** * Adds a {@link MetricRegistryListener} to a collection of listeners that will be notified on * metric creation. Listeners will be notified in the order in which they are added. * <p> * <b>N.B.:</b> The listener will be notified of all existing metrics when it first registers. * * @param listener the listener that will be notified */
public void addListener(MetricRegistryListener listener) { listeners.add(listener); for (Map.Entry<String, Metric> entry : metrics.entrySet()) { notifyListenerOfAddedMetric(listener, entry.getValue(), entry.getKey()); } }
Removes a MetricRegistryListener from this registry's collection of listeners.
Params:
  • listener – the listener that will be removed
/** * Removes a {@link MetricRegistryListener} from this registry's collection of listeners. * * @param listener the listener that will be removed */
public void removeListener(MetricRegistryListener listener) { listeners.remove(listener); }
Returns a set of the names of all the metrics in the registry.
Returns:the names of all the metrics
/** * Returns a set of the names of all the metrics in the registry. * * @return the names of all the metrics */
public SortedSet<String> getNames() { return Collections.unmodifiableSortedSet(new TreeSet<>(metrics.keySet())); }
Returns a map of all the gauges in the registry and their names.
Returns:all the gauges in the registry
/** * Returns a map of all the gauges in the registry and their names. * * @return all the gauges in the registry */
@SuppressWarnings("rawtypes") public SortedMap<String, Gauge> getGauges() { return getGauges(MetricFilter.ALL); }
Returns a map of all the gauges in the registry and their names which match the given filter.
Params:
  • filter – the metric filter to match
Returns:all the gauges in the registry
/** * Returns a map of all the gauges in the registry and their names which match the given filter. * * @param filter the metric filter to match * @return all the gauges in the registry */
@SuppressWarnings("rawtypes") public SortedMap<String, Gauge> getGauges(MetricFilter filter) { return getMetrics(Gauge.class, filter); }
Returns a map of all the counters in the registry and their names.
Returns:all the counters in the registry
/** * Returns a map of all the counters in the registry and their names. * * @return all the counters in the registry */
public SortedMap<String, Counter> getCounters() { return getCounters(MetricFilter.ALL); }
Returns a map of all the counters in the registry and their names which match the given filter.
Params:
  • filter – the metric filter to match
Returns:all the counters in the registry
/** * Returns a map of all the counters in the registry and their names which match the given * filter. * * @param filter the metric filter to match * @return all the counters in the registry */
public SortedMap<String, Counter> getCounters(MetricFilter filter) { return getMetrics(Counter.class, filter); }
Returns a map of all the histograms in the registry and their names.
Returns:all the histograms in the registry
/** * Returns a map of all the histograms in the registry and their names. * * @return all the histograms in the registry */
public SortedMap<String, Histogram> getHistograms() { return getHistograms(MetricFilter.ALL); }
Returns a map of all the histograms in the registry and their names which match the given filter.
Params:
  • filter – the metric filter to match
Returns:all the histograms in the registry
/** * Returns a map of all the histograms in the registry and their names which match the given * filter. * * @param filter the metric filter to match * @return all the histograms in the registry */
public SortedMap<String, Histogram> getHistograms(MetricFilter filter) { return getMetrics(Histogram.class, filter); }
Returns a map of all the meters in the registry and their names.
Returns:all the meters in the registry
/** * Returns a map of all the meters in the registry and their names. * * @return all the meters in the registry */
public SortedMap<String, Meter> getMeters() { return getMeters(MetricFilter.ALL); }
Returns a map of all the meters in the registry and their names which match the given filter.
Params:
  • filter – the metric filter to match
Returns:all the meters in the registry
/** * Returns a map of all the meters in the registry and their names which match the given filter. * * @param filter the metric filter to match * @return all the meters in the registry */
public SortedMap<String, Meter> getMeters(MetricFilter filter) { return getMetrics(Meter.class, filter); }
Returns a map of all the timers in the registry and their names.
Returns:all the timers in the registry
/** * Returns a map of all the timers in the registry and their names. * * @return all the timers in the registry */
public SortedMap<String, Timer> getTimers() { return getTimers(MetricFilter.ALL); }
Returns a map of all the timers in the registry and their names which match the given filter.
Params:
  • filter – the metric filter to match
Returns:all the timers in the registry
/** * Returns a map of all the timers in the registry and their names which match the given filter. * * @param filter the metric filter to match * @return all the timers in the registry */
public SortedMap<String, Timer> getTimers(MetricFilter filter) { return getMetrics(Timer.class, filter); } @SuppressWarnings("unchecked") private <T extends Metric> T getOrAdd(String name, MetricBuilder<T> builder) { final Metric metric = metrics.get(name); if (builder.isInstance(metric)) { return (T) metric; } else if (metric == null) { try { return register(name, builder.newMetric()); } catch (IllegalArgumentException e) { final Metric added = metrics.get(name); if (builder.isInstance(added)) { return (T) added; } } } throw new IllegalArgumentException(name + " is already used for a different type of metric"); } @SuppressWarnings("unchecked") private <T extends Metric> SortedMap<String, T> getMetrics(Class<T> klass, MetricFilter filter) { final TreeMap<String, T> timers = new TreeMap<>(); for (Map.Entry<String, Metric> entry : metrics.entrySet()) { if (klass.isInstance(entry.getValue()) && filter.matches(entry.getKey(), entry.getValue())) { timers.put(entry.getKey(), (T) entry.getValue()); } } return Collections.unmodifiableSortedMap(timers); } private void onMetricAdded(String name, Metric metric) { for (MetricRegistryListener listener : listeners) { notifyListenerOfAddedMetric(listener, metric, name); } } private void notifyListenerOfAddedMetric(MetricRegistryListener listener, Metric metric, String name) { if (metric instanceof Gauge) { listener.onGaugeAdded(name, (Gauge<?>) metric); } else if (metric instanceof Counter) { listener.onCounterAdded(name, (Counter) metric); } else if (metric instanceof Histogram) { listener.onHistogramAdded(name, (Histogram) metric); } else if (metric instanceof Meter) { listener.onMeterAdded(name, (Meter) metric); } else if (metric instanceof Timer) { listener.onTimerAdded(name, (Timer) metric); } else { throw new IllegalArgumentException("Unknown metric type: " + metric.getClass()); } } private void onMetricRemoved(String name, Metric metric) { for (MetricRegistryListener listener : listeners) { notifyListenerOfRemovedMetric(name, metric, listener); } } private void notifyListenerOfRemovedMetric(String name, Metric metric, MetricRegistryListener listener) { if (metric instanceof Gauge) { listener.onGaugeRemoved(name); } else if (metric instanceof Counter) { listener.onCounterRemoved(name); } else if (metric instanceof Histogram) { listener.onHistogramRemoved(name); } else if (metric instanceof Meter) { listener.onMeterRemoved(name); } else if (metric instanceof Timer) { listener.onTimerRemoved(name); } else { throw new IllegalArgumentException("Unknown metric type: " + metric.getClass()); } }
Given a metric set, registers them with the given prefix prepended to their names.
Params:
  • prefix – a name prefix
  • metrics – a set of metrics
Throws:
/** * Given a metric set, registers them with the given prefix prepended to their names. * * @param prefix a name prefix * @param metrics a set of metrics * @throws IllegalArgumentException if any of the names are already registered */
public void registerAll(String prefix, MetricSet metrics) throws IllegalArgumentException { for (Map.Entry<String, Metric> entry : metrics.getMetrics().entrySet()) { if (entry.getValue() instanceof MetricSet) { registerAll(name(prefix, entry.getKey()), (MetricSet) entry.getValue()); } else { register(name(prefix, entry.getKey()), entry.getValue()); } } } @Override public Map<String, Metric> getMetrics() { return Collections.unmodifiableMap(metrics); } @FunctionalInterface public interface MetricSupplier<T extends Metric> { T newMetric(); }
A quick and easy way of capturing the notion of default metrics.
/** * A quick and easy way of capturing the notion of default metrics. */
private interface MetricBuilder<T extends Metric> { MetricBuilder<Counter> COUNTERS = new MetricBuilder<Counter>() { @Override public Counter newMetric() { return new Counter(); } @Override public boolean isInstance(Metric metric) { return Counter.class.isInstance(metric); } }; MetricBuilder<Histogram> HISTOGRAMS = new MetricBuilder<Histogram>() { @Override public Histogram newMetric() { return new Histogram(new ExponentiallyDecayingReservoir()); } @Override public boolean isInstance(Metric metric) { return Histogram.class.isInstance(metric); } }; MetricBuilder<Meter> METERS = new MetricBuilder<Meter>() { @Override public Meter newMetric() { return new Meter(); } @Override public boolean isInstance(Metric metric) { return Meter.class.isInstance(metric); } }; MetricBuilder<Timer> TIMERS = new MetricBuilder<Timer>() { @Override public Timer newMetric() { return new Timer(); } @Override public boolean isInstance(Metric metric) { return Timer.class.isInstance(metric); } }; T newMetric(); boolean isInstance(Metric metric); } }