diff --git a/gradle/ext.gradle b/gradle/ext.gradle index 2c679b2..df63612 100644 --- a/gradle/ext.gradle +++ b/gradle/ext.gradle @@ -1,7 +1,7 @@ ext { user = 'xbib' name = 'metrics' - description = 'A stripped-down version of Coda Hale Metrics' + description = 'A stripped-down and modified version of Coda Hale Metrics' scmUrl = 'https://github.com/' + user + '/' + name scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' scmDeveloperConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' diff --git a/src/main/java/org/xbib/metrics/Clock.java b/src/main/java/org/xbib/metrics/Clock.java index dcd2dde..8562ac7 100644 --- a/src/main/java/org/xbib/metrics/Clock.java +++ b/src/main/java/org/xbib/metrics/Clock.java @@ -1,20 +1,17 @@ package org.xbib.metrics; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; - /** - * An abstraction for how time passes. It is passed to {@link Sampler} to track timing. + * An interface for how time passes. It is passed to {@link Sampler} to track timing. */ -public abstract class Clock { +public interface Clock { /** * The default clock to use. * * @return the default {@link Clock} instance - * @see Clock.UserTimeClock + * @see UserTimeClock */ - public static Clock defaultClock() { + static Clock defaultClock() { return UserTimeClock.DEFAULT; } @@ -23,40 +20,13 @@ public abstract class Clock { * * @return time tick in nanoseconds */ - public abstract long getTick(); + long getTick(); /** * Returns the current time in milliseconds. * * @return time in milliseconds */ - public long getTime() { - return System.currentTimeMillis(); - } - - /** - * A clock implementation which returns the current time in epoch nanoseconds. - */ - public static class UserTimeClock extends Clock { - @Override - public long getTick() { - return System.nanoTime(); - } - - static final Clock DEFAULT = new UserTimeClock(); - } - - /** - * A clock implementation which returns the current thread's CPU time. - */ - public static class CpuTimeClock extends Clock { - private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean(); - - @Override - public long getTick() { - return THREAD_MX_BEAN.getCurrentThreadCpuTime(); - } - } - + long getTime(); } diff --git a/src/main/java/org/xbib/metrics/CpuTimeClock.java b/src/main/java/org/xbib/metrics/CpuTimeClock.java new file mode 100644 index 0000000..05a7669 --- /dev/null +++ b/src/main/java/org/xbib/metrics/CpuTimeClock.java @@ -0,0 +1,21 @@ +package org.xbib.metrics; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; + +/** + * A clock implementation which returns the current thread's CPU time. + */ +class CpuTimeClock implements Clock { + private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean(); + + @Override + public long getTick() { + return THREAD_MX_BEAN.getCurrentThreadCpuTime(); + } + + @Override + public long getTime() { + return System.currentTimeMillis(); + } +} diff --git a/src/main/java/org/xbib/metrics/ExpWeightedMovingAverage.java b/src/main/java/org/xbib/metrics/ExpWeightedMovingAverage.java index 45b7fc7..4f30f24 100644 --- a/src/main/java/org/xbib/metrics/ExpWeightedMovingAverage.java +++ b/src/main/java/org/xbib/metrics/ExpWeightedMovingAverage.java @@ -15,7 +15,8 @@ public class ExpWeightedMovingAverage { private static final double M5_ALPHA = 1 - Math.exp(-5 / 60.0 / 5); private static final double M15_ALPHA = 1 - Math.exp(-5 / 60.0 / 15); private final LongAdder uncounted = new LongAdder(); - private final double alpha, interval; + private final double alpha; + private final double interval; private volatile boolean initialized = false; private volatile double rate = 0.0; diff --git a/src/main/java/org/xbib/metrics/ExponentiallyDecayingReservoir.java b/src/main/java/org/xbib/metrics/ExponentiallyDecayingReservoir.java index f6e1bb8..c0b2325 100644 --- a/src/main/java/org/xbib/metrics/ExponentiallyDecayingReservoir.java +++ b/src/main/java/org/xbib/metrics/ExponentiallyDecayingReservoir.java @@ -72,10 +72,12 @@ public class ExponentiallyDecayingReservoir implements Reservoir { this.nextScaleTime = new AtomicLong(clock.getTick() + RESCALE_THRESHOLD); } + @Override public int size() { return (int) min(size, count.get()); } + @Override public void update(long value) { update(value, currentTimeInSeconds()); } @@ -119,6 +121,7 @@ public class ExponentiallyDecayingReservoir implements Reservoir { } } + @Override public Snapshot getSnapshot() { lockForRegularUsage(); try { diff --git a/src/main/java/org/xbib/metrics/Gauge.java b/src/main/java/org/xbib/metrics/Gauge.java index 3f23f18..f3f53ad 100644 --- a/src/main/java/org/xbib/metrics/Gauge.java +++ b/src/main/java/org/xbib/metrics/Gauge.java @@ -14,6 +14,7 @@ package org.xbib.metrics; * * @param the type of the metric's value */ +@FunctionalInterface public interface Gauge extends Metric { /** * Returns the metric's current value. diff --git a/src/main/java/org/xbib/metrics/Histogram.java b/src/main/java/org/xbib/metrics/Histogram.java index 2a6916e..4f4beda 100644 --- a/src/main/java/org/xbib/metrics/Histogram.java +++ b/src/main/java/org/xbib/metrics/Histogram.java @@ -40,7 +40,7 @@ public class Histogram implements Metric, Sampling, Count { @Override public void inc(String index, String type, String id) { - + // not used } @Override @@ -55,7 +55,7 @@ public class Histogram implements Metric, Sampling, Count { @Override public void dec(String index, String type, String id) { - + // not used } /** diff --git a/src/main/java/org/xbib/metrics/Meter.java b/src/main/java/org/xbib/metrics/Meter.java index e7458f4..04839fd 100644 --- a/src/main/java/org/xbib/metrics/Meter.java +++ b/src/main/java/org/xbib/metrics/Meter.java @@ -46,12 +46,7 @@ public class Meter implements Metered { public void spawn(long intervalSeconds) { this.future = Executors.newScheduledThreadPool(1) - .scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - tickIfNecessary(); - } - }, intervalSeconds, intervalSeconds, TimeUnit.SECONDS); + .scheduleAtFixedRate(this::tickIfNecessary, intervalSeconds, intervalSeconds, TimeUnit.SECONDS); } public void stop() { diff --git a/src/main/java/org/xbib/metrics/MetricFilter.java b/src/main/java/org/xbib/metrics/MetricFilter.java index d18915d..0be8511 100644 --- a/src/main/java/org/xbib/metrics/MetricFilter.java +++ b/src/main/java/org/xbib/metrics/MetricFilter.java @@ -3,16 +3,12 @@ package org.xbib.metrics; /** * A filter used to determine whether or not a metric should be reported, among other things. */ +@FunctionalInterface public interface MetricFilter { /** * Matches all metrics, regardless of type or name. */ - MetricFilter ALL = new MetricFilter() { - @Override - public boolean matches(MetricName name, Metric metric) { - return true; - } - }; + MetricFilter ALL = (name, metric) -> true; /** * Returns {@code true} if the metric matches the filter; {@code false} otherwise. diff --git a/src/main/java/org/xbib/metrics/MetricName.java b/src/main/java/org/xbib/metrics/MetricName.java index 34b150a..0ef8668 100644 --- a/src/main/java/org/xbib/metrics/MetricName.java +++ b/src/main/java/org/xbib/metrics/MetricName.java @@ -41,7 +41,7 @@ public class MetricName implements Comparable { **/ public static MetricName join(MetricName... parts) { final StringBuilder nameBuilder = new StringBuilder(); - final Map tags = new HashMap(); + final Map tags = new HashMap<>(); boolean first = true; @@ -92,16 +92,13 @@ public class MetricName implements Comparable { if (name == null || name.isEmpty()) { continue; } - if (first) { first = false; } else { builder.append(SEPARATOR); } - builder.append(name); } - return builder.toString(); } @@ -109,7 +106,6 @@ public class MetricName implements Comparable { if (tags == null || tags.isEmpty()) { return EMPTY_TAGS; } - return Collections.unmodifiableMap(tags); } @@ -132,7 +128,6 @@ public class MetricName implements Comparable { */ public MetricName resolve(String p) { final String next; - if (p != null && !p.isEmpty()) { if (key != null && !key.isEmpty()) { next = key + SEPARATOR + p; @@ -142,7 +137,6 @@ public class MetricName implements Comparable { } else { next = this.key; } - return new MetricName(next, tags); } @@ -153,9 +147,9 @@ public class MetricName implements Comparable { * @return A newly created metric name with the specified tags associated with it. */ public MetricName tagged(Map add) { - final Map tags = new HashMap(add); - tags.putAll(this.tags); - return new MetricName(key, tags); + final Map map = new HashMap<>(add); + map.putAll(this.tags); + return new MetricName(key, map); } /** @@ -171,17 +165,13 @@ public class MetricName implements Comparable { if (pairs == null) { return this; } - if (pairs.length % 2 != 0) { throw new IllegalArgumentException("Argument count must be even"); } - - final Map add = new HashMap(); - + final Map add = new HashMap<>(); for (int i = 0; i < pairs.length; i += 2) { add.put(pairs[i], pairs[i + 1]); } - return tagged(add); } @@ -189,9 +179,7 @@ public class MetricName implements Comparable { public String toString() { if (tags.isEmpty()) { return key; - //return key + "{}"; } - return key + tags; } @@ -209,17 +197,13 @@ public class MetricName implements Comparable { if (this == obj) { return true; } - if (obj == null) { return false; } - if (getClass() != obj.getClass()) { return false; } - MetricName other = (MetricName) obj; - if (key == null) { if (other.key != null) { return false; @@ -227,23 +211,15 @@ public class MetricName implements Comparable { } else if (!key.equals(other.key)) { return false; } - return tags.equals(other.tags); - } @Override public int compareTo(MetricName o) { - if (o == null) { - return -1; - } - int c = compareName(key, o.getKey()); - if (c != 0) { return c; } - return compareTags(tags, o.getTags()); } @@ -251,15 +227,12 @@ public class MetricName implements Comparable { if (left == null && right == null) { return 0; } - if (left == null) { return 1; } - if (right == null) { return -1; } - return left.compareTo(right); } @@ -267,45 +240,35 @@ public class MetricName implements Comparable { if (left == null && right == null) { return 0; } - if (left == null) { return 1; } - if (right == null) { return -1; } - final Iterable keys = uniqueSortedKeys(left, right); - - for (final String key : keys) { - final String a = left.get(key); - final String b = right.get(key); - + for (final String s : keys) { + final String a = left.get(s); + final String b = right.get(s); if (a == null && b == null) { continue; } - if (a == null) { return -1; } - if (b == null) { return 1; } - int c = a.compareTo(b); - if (c != 0) { return c; } } - return 0; } private Iterable uniqueSortedKeys(Map left, Map right) { - final Set set = new TreeSet(left.keySet()); + final Set set = new TreeSet<>(left.keySet()); set.addAll(right.keySet()); return set; } diff --git a/src/main/java/org/xbib/metrics/MetricRegistry.java b/src/main/java/org/xbib/metrics/MetricRegistry.java index 501d3b1..43842cb 100644 --- a/src/main/java/org/xbib/metrics/MetricRegistry.java +++ b/src/main/java/org/xbib/metrics/MetricRegistry.java @@ -10,12 +10,15 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; /** * A registry of metric instances. */ public class MetricRegistry implements MetricSet { + private static final Logger logger = Logger.getLogger(MetricRegistry.class.getName()); private final ConcurrentMap metrics; private final List listeners; @@ -23,7 +26,7 @@ public class MetricRegistry implements MetricSet { * Creates a new {@link MetricRegistry}. */ public MetricRegistry() { - this(new ConcurrentHashMap()); + this(new ConcurrentHashMap<>()); } /** @@ -35,7 +38,7 @@ public class MetricRegistry implements MetricSet { */ protected MetricRegistry(ConcurrentMap metricsMap) { this.metrics = metricsMap; - this.listeners = new CopyOnWriteArrayList(); + this.listeners = new CopyOnWriteArrayList<>(); } /** @@ -68,7 +71,9 @@ public class MetricRegistry implements MetricSet { } final String[] parts = new String[length + 1]; parts[0] = name; - System.arraycopy(names, 0, parts, 1, length); + if (names != null) { + System.arraycopy(names, 0, parts, 1, length); + } return MetricName.build(parts); } @@ -80,7 +85,7 @@ public class MetricRegistry implements MetricSet { * @see #register(MetricName, Metric) */ @SuppressWarnings("unchecked") - public T register(String name, T metric) throws IllegalArgumentException { + public T register(String name, T metric) { return register(MetricName.build(name), metric); } @@ -94,7 +99,7 @@ public class MetricRegistry implements MetricSet { * @throws IllegalArgumentException if the name is already registered */ @SuppressWarnings("unchecked") - public T register(MetricName name, T metric) throws IllegalArgumentException { + public T register(MetricName name, T metric) { if (metric instanceof MetricSet) { registerAll(name, (MetricSet) metric); } else { @@ -115,7 +120,7 @@ public class MetricRegistry implements MetricSet { * @param metrics a set of metrics * @throws IllegalArgumentException if any of the names are already registered */ - public void registerAll(MetricSet metrics) throws IllegalArgumentException { + public void registerAll(MetricSet metrics) { registerAll(null, metrics); } @@ -368,6 +373,7 @@ public class MetricRegistry implements MetricSet { try { return register(name, builder.newMetric()); } catch (IllegalArgumentException e) { + logger.log(Level.WARNING, e.getMessage(), e); final Metric added = metrics.get(name); if (builder.isInstance(added)) { return (T) added; @@ -379,7 +385,7 @@ public class MetricRegistry implements MetricSet { @SuppressWarnings("unchecked") private SortedMap getMetrics(Class klass, MetricFilter filter) { - final TreeMap timers = new TreeMap(); + final TreeMap timers = new TreeMap<>(); for (Map.Entry entry : metrics.entrySet()) { if (klass.isInstance(entry.getValue()) && filter.matches(entry.getKey(), entry.getValue())) { @@ -433,11 +439,8 @@ public class MetricRegistry implements MetricSet { } } - private void registerAll(MetricName prefix, MetricSet metrics) throws IllegalArgumentException { - if (prefix == null) { - prefix = MetricName.EMPTY; - } - + private void registerAll(MetricName prefixName, MetricSet metrics) { + MetricName prefix = prefixName == null ? MetricName.EMPTY : prefixName; for (Map.Entry entry : metrics.getMetrics().entrySet()) { if (entry.getValue() instanceof MetricSet) { registerAll(MetricName.join(prefix, entry.getKey()), (MetricSet) entry.getValue()); diff --git a/src/main/java/org/xbib/metrics/MetricSet.java b/src/main/java/org/xbib/metrics/MetricSet.java index 10b5662..7a6ead4 100644 --- a/src/main/java/org/xbib/metrics/MetricSet.java +++ b/src/main/java/org/xbib/metrics/MetricSet.java @@ -7,6 +7,7 @@ import java.util.Map; * * @see MetricRegistry#registerAll(MetricSet) */ +@FunctionalInterface public interface MetricSet extends Metric { /** * A map of metric names to metrics. diff --git a/src/main/java/org/xbib/metrics/Sampling.java b/src/main/java/org/xbib/metrics/Sampling.java index 0600d38..793225e 100644 --- a/src/main/java/org/xbib/metrics/Sampling.java +++ b/src/main/java/org/xbib/metrics/Sampling.java @@ -3,6 +3,7 @@ package org.xbib.metrics; /** * An object which samples values. */ +@FunctionalInterface public interface Sampling { /** * Returns a snapshot of the values. diff --git a/src/main/java/org/xbib/metrics/Snapshot.java b/src/main/java/org/xbib/metrics/Snapshot.java index 5628245..c6e1ca3 100644 --- a/src/main/java/org/xbib/metrics/Snapshot.java +++ b/src/main/java/org/xbib/metrics/Snapshot.java @@ -3,9 +3,9 @@ package org.xbib.metrics; import java.io.OutputStream; /** - * A statistical snapshot of a {@link Snapshot}. + * A {@link Snapshot}. */ -public abstract class Snapshot { +public interface Snapshot { /** * Returns the value at the given quantile. @@ -13,109 +13,97 @@ public abstract class Snapshot { * @param quantile a given quantile, in {@code [0..1]} * @return the value in the distribution at {@code quantile} */ - public abstract double getValue(double quantile); + double getValue(double quantile); /** * Returns the entire set of values in the snapshot. * * @return the entire set of values */ - public abstract long[] getValues(); + long[] getValues(); /** * Returns the number of values in the snapshot. * * @return the number of values */ - public abstract int size(); + int size(); /** * Returns the median value in the distribution. * * @return the median value */ - public double getMedian() { - return getValue(0.5); - } + double getMedian(); /** * Returns the value at the 75th percentile in the distribution. * * @return the value at the 75th percentile */ - public double get75thPercentile() { - return getValue(0.75); - } + double get75thPercentile(); /** * Returns the value at the 95th percentile in the distribution. * * @return the value at the 95th percentile */ - public double get95thPercentile() { - return getValue(0.95); - } + double get95thPercentile(); /** * Returns the value at the 98th percentile in the distribution. * * @return the value at the 98th percentile */ - public double get98thPercentile() { - return getValue(0.98); - } + double get98thPercentile(); /** * Returns the value at the 99th percentile in the distribution. * * @return the value at the 99th percentile */ - public double get99thPercentile() { - return getValue(0.99); - } + double get99thPercentile(); /** * Returns the value at the 99.9th percentile in the distribution. * * @return the value at the 99.9th percentile */ - public double get999thPercentile() { - return getValue(0.999); - } + double get999thPercentile(); /** * Returns the highest value in the snapshot. * * @return the highest value */ - public abstract long getMax(); + long getMax(); /** * Returns the arithmetic mean of the values in the snapshot. * * @return the arithmetic mean */ - public abstract double getMean(); + double getMean(); /** * Returns the lowest value in the snapshot. * * @return the lowest value */ - public abstract long getMin(); + long getMin(); /** * Returns the standard deviation of the values in the snapshot. * * @return the standard value */ - public abstract double getStdDev(); + double getStdDev(); /** * Writes the values of the snapshot to the given stream. * * @param output an output stream */ - public abstract void dump(OutputStream output); + void dump(OutputStream output); } diff --git a/src/main/java/org/xbib/metrics/UserTimeClock.java b/src/main/java/org/xbib/metrics/UserTimeClock.java new file mode 100644 index 0000000..3b229d4 --- /dev/null +++ b/src/main/java/org/xbib/metrics/UserTimeClock.java @@ -0,0 +1,20 @@ +package org.xbib.metrics; + +/** + * A clock implementation which returns the current time in epoch nanoseconds. + */ +class UserTimeClock implements Clock { + + static final Clock DEFAULT = new UserTimeClock(); + + @Override + public long getTick() { + return System.nanoTime(); + } + + @Override + public long getTime() { + return System.currentTimeMillis(); + } + +} \ No newline at end of file diff --git a/src/main/java/org/xbib/metrics/WeightedSnapshot.java b/src/main/java/org/xbib/metrics/WeightedSnapshot.java index 6c096c4..493a291 100644 --- a/src/main/java/org/xbib/metrics/WeightedSnapshot.java +++ b/src/main/java/org/xbib/metrics/WeightedSnapshot.java @@ -6,12 +6,11 @@ import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; -import java.util.Comparator; /** * A statistical snapshot of a {@link WeightedSnapshot}. */ -public class WeightedSnapshot extends Snapshot { +public class WeightedSnapshot implements Snapshot { private final long[] values; private final double[] normWeights; @@ -25,31 +24,28 @@ public class WeightedSnapshot extends Snapshot { public WeightedSnapshot(Collection values) { final WeightedSample[] copy = values.toArray(new WeightedSample[]{}); - Arrays.sort(copy, new Comparator() { - @Override - public int compare(WeightedSample o1, WeightedSample o2) { - if (o1.value > o2.value) { - return 1; - } - if (o1.value < o2.value) { - return -1; - } - return 0; + Arrays.sort(copy, (o1, o2) -> { + if (o1.value > o2.value) { + return 1; } + if (o1.value < o2.value) { + return -1; + } + return 0; }); this.values = new long[copy.length]; this.normWeights = new double[copy.length]; this.quantiles = new double[copy.length]; - double sumWeight = 0; + double sumWeight = 0.0f; for (WeightedSample sample : copy) { sumWeight += sample.weight; } for (int i = 0; i < copy.length; i++) { this.values[i] = copy[i].value; - this.normWeights[i] = copy[i].weight / sumWeight; + this.normWeights[i] = safeDivide(copy[i].weight, sumWeight); } for (int i = 1; i < copy.length; i++) { @@ -57,6 +53,88 @@ public class WeightedSnapshot extends Snapshot { } } + private static double safeDivide(double dividend, double divisor) { + if (Double.compare(divisor, Double.NaN) == 0) { + return Double.NaN; + } + if (Double.compare(dividend, Double.NaN) == 0) { + return Double.NaN; + } + if (Double.compare(divisor, 0.0) == 0) { + if (Double.compare(dividend, 0.0) == -1) { + return Double.NEGATIVE_INFINITY; + } + return Double.POSITIVE_INFINITY; + } + if (Double.compare(divisor, -0.0) == 0) { + if (Double.compare(dividend, -0.0) == 1) { + return Double.NEGATIVE_INFINITY; + } + return Double.POSITIVE_INFINITY; + } + return dividend / divisor; + } + + /** + * Returns the median value in the distribution. + * + * @return the median value + */ + @Override + public double getMedian() { + return getValue(0.5); + } + + /** + * Returns the value at the 75th percentile in the distribution. + * + * @return the value at the 75th percentile + */ + @Override + public double get75thPercentile() { + return getValue(0.75); + } + + /** + * Returns the value at the 95th percentile in the distribution. + * + * @return the value at the 95th percentile + */ + @Override + public double get95thPercentile() { + return getValue(0.95); + } + + /** + * Returns the value at the 98th percentile in the distribution. + * + * @return the value at the 98th percentile + */ + @Override + public double get98thPercentile() { + return getValue(0.98); + } + + /** + * Returns the value at the 99th percentile in the distribution. + * + * @return the value at the 99th percentile + */ + @Override + public double get99thPercentile() { + return getValue(0.99); + } + + /** + * Returns the value at the 99.9th percentile in the distribution. + * + * @return the value at the 99.9th percentile + */ + @Override + public double get999thPercentile() { + return getValue(0.999); + } + /** * Returns the value at the given quantile. *