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

com.codahale.metrics.MetricRegistry Maven / Gradle / Ivy

Go to download

Metrics is a Java library which gives you unparalleled insight into what your code does in production. Metrics provides a powerful toolkit of ways to measure the behavior of critical components in your production environment.

There is a newer version: 4.2.28
Show newest version
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.
 */
public class MetricRegistry implements MetricSet {
    /**
     * 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.
     *
     * @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 metrics;
    private final List listeners;

    /**
     * Creates a new {@link MetricRegistry}.
     */
    public MetricRegistry() {
        this.metrics = buildMap();
        this.listeners = new CopyOnWriteArrayList<>();
    }

    /**
     * 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 buildMap() {
        return new ConcurrentHashMap<>();
    }

    /**
     * Given a {@link Gauge}, registers it under the given name and returns it
     *
     * @param name the name of the gauge
     * @param   the type of the gauge's value
     * @return the registered {@link Gauge}
     * @since 4.2.10
     */
    public  Gauge registerGauge(String name, Gauge metric) throws IllegalArgumentException {
        return register(name, metric);
    }

    /**
     * Given a {@link Metric}, registers it under the given name.
     *
     * @param name   the name of the metric
     * @param metric the metric
     * @param     the type of the metric
     * @return {@code metric}
     * @throws IllegalArgumentException if the name is already registered or metric variable is null
     */
    @SuppressWarnings("unchecked")
    public  T register(String name, T metric) throws IllegalArgumentException {

        if (metric == null) {
            throw new NullPointerException("metric == null");
        }

        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.
     *
     * @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 {@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 {@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 supplier) {
        return getOrAdd(name, new MetricBuilder() {
            @Override
            public Counter newMetric() {
                return supplier.newMetric();
            }

            @Override
            public boolean isInstance(Metric metric) {
                return Counter.class.isInstance(metric);
            }
        });
    }

    /**
     * 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 {@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 supplier) {
        return getOrAdd(name, new MetricBuilder() {
            @Override
            public Histogram newMetric() {
                return supplier.newMetric();
            }

            @Override
            public boolean isInstance(Metric metric) {
                return Histogram.class.isInstance(metric);
            }
        });
    }

    /**
     * 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 {@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 supplier) {
        return getOrAdd(name, new MetricBuilder() {
            @Override
            public Meter newMetric() {
                return supplier.newMetric();
            }

            @Override
            public boolean isInstance(Metric metric) {
                return Meter.class.isInstance(metric);
            }
        });
    }

    /**
     * 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 {@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 supplier) {
        return getOrAdd(name, new MetricBuilder() {
            @Override
            public Timer newMetric() {
                return supplier.newMetric();
            }

            @Override
            public boolean isInstance(Metric metric) {
                return Timer.class.isInstance(metric);
            }
        });
    }

    /**
     * Return the {@link Gauge} registered under this name; or create and register
     * a new {@link SettableGauge} if none is registered.
     *
     * @param name the name of the metric
     * @return a pre-existing {@link Gauge} or a new {@link SettableGauge}
     * @since 4.2
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public  T gauge(String name) {
        return (T) getOrAdd(name, MetricBuilder.GAUGES);
    }

    /**
     * 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  T gauge(String name, final MetricSupplier supplier) {
        return getOrAdd(name, new MetricBuilder() {
            @Override
            public T newMetric() {
                return supplier.newMetric();
            }

            @Override
            public boolean isInstance(Metric metric) {
                return Gauge.class.isInstance(metric);
            }
        });
    }


    /**
     * 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.
     *
     * @param filter a filter
     */
    public void removeMatching(MetricFilter filter) {
        for (Map.Entry entry : metrics.entrySet()) {
            if (filter.matches(entry.getKey(), entry.getValue())) {
                remove(entry.getKey());
            }
        }
    }

    /**
     * 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.
     * 

* N.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 entry : metrics.entrySet()) { notifyListenerOfAddedMetric(listener, entry.getValue(), entry.getKey()); } } /** * 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. * * @return the names of all the metrics */ public SortedSet getNames() { return Collections.unmodifiableSortedSet(new TreeSet<>(metrics.keySet())); } /** * Returns a map of all the gauges in the registry and their names. * * @return all the gauges in the registry */ @SuppressWarnings("rawtypes") public SortedMap getGauges() { return getGauges(MetricFilter.ALL); } /** * 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 getGauges(MetricFilter filter) { return getMetrics(Gauge.class, filter); } /** * Returns a map of all the counters in the registry and their names. * * @return all the counters in the registry */ public SortedMap getCounters() { return getCounters(MetricFilter.ALL); } /** * 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 getCounters(MetricFilter filter) { return getMetrics(Counter.class, filter); } /** * Returns a map of all the histograms in the registry and their names. * * @return all the histograms in the registry */ public SortedMap getHistograms() { return getHistograms(MetricFilter.ALL); } /** * 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 getHistograms(MetricFilter filter) { return getMetrics(Histogram.class, filter); } /** * Returns a map of all the meters in the registry and their names. * * @return all the meters in the registry */ public SortedMap getMeters() { return getMeters(MetricFilter.ALL); } /** * 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 getMeters(MetricFilter filter) { return getMetrics(Meter.class, filter); } /** * Returns a map of all the timers in the registry and their names. * * @return all the timers in the registry */ public SortedMap getTimers() { return getTimers(MetricFilter.ALL); } /** * 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 getTimers(MetricFilter filter) { return getMetrics(Timer.class, filter); } @SuppressWarnings("unchecked") private T getOrAdd(String name, MetricBuilder 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 SortedMap getMetrics(Class klass, MetricFilter filter) { final TreeMap timers = new TreeMap<>(); for (Map.Entry 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. * * @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 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 getMetrics() { return Collections.unmodifiableMap(metrics); } @FunctionalInterface public interface MetricSupplier { T newMetric(); } /** * A quick and easy way of capturing the notion of default metrics. */ private interface MetricBuilder { MetricBuilder COUNTERS = new MetricBuilder() { @Override public Counter newMetric() { return new Counter(); } @Override public boolean isInstance(Metric metric) { return Counter.class.isInstance(metric); } }; MetricBuilder HISTOGRAMS = new MetricBuilder() { @Override public Histogram newMetric() { return new Histogram(new ExponentiallyDecayingReservoir()); } @Override public boolean isInstance(Metric metric) { return Histogram.class.isInstance(metric); } }; MetricBuilder METERS = new MetricBuilder() { @Override public Meter newMetric() { return new Meter(); } @Override public boolean isInstance(Metric metric) { return Meter.class.isInstance(metric); } }; MetricBuilder TIMERS = new MetricBuilder() { @Override public Timer newMetric() { return new Timer(); } @Override public boolean isInstance(Metric metric) { return Timer.class.isInstance(metric); } }; @SuppressWarnings("rawtypes") MetricBuilder GAUGES = new MetricBuilder() { @Override public Gauge newMetric() { return new DefaultSettableGauge<>(); } @Override public boolean isInstance(Metric metric) { return Gauge.class.isInstance(metric); } }; T newMetric(); boolean isInstance(Metric metric); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy