Metrics: Clean up, remove and deprecate in support of pure Java based metrics.

This changes the following:
* DRY Gauge metrics
* Remove Namespace from metrics API (never used, not needed)
* Introduce a 'dirty' flag. This will be used to assist with serialization (in a later commit).
* Change getKey to getName in the API
* Deprecate (only from Java) the future non-supported Guage types.
* Remove NumericGauge and replace with LongGuage and DoubleGuage.
* Bring code coverage back to 100%

Note this change is internally non-passive, however the Java metrics API (recently introduced in 6.0) has not been advertised as a re-usable asset.

Changes in support of #7788

Fixes #7872
This commit is contained in:
Jake Landis 2017-08-01 16:09:58 -05:00
parent 88a301d120
commit 977dc84f3a
28 changed files with 444 additions and 318 deletions

View file

@ -5,7 +5,7 @@ module LogStash module Instrument module MetricType
class Counter < LongCounter
def initialize(namespaces, key)
super(namespaces, key.to_s)
super(key.to_s)
end

View file

@ -12,18 +12,15 @@ import java.util.List;
* @param <T> The underlying type for this metric. For example {@link Long} for Counter, or {@link String} for Gauge.
*/
public abstract class AbstractMetric<T> implements Metric<T> {
final protected String key;
final protected List<String> nameSpace;
final protected String name;
/**
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
*/
protected AbstractMetric(final List<String> nameSpace, final String key) {
this.nameSpace = nameSpace;
this.key = key;
protected AbstractMetric(final String name) {
this.name = name;
}
@Override
@ -34,18 +31,13 @@ public abstract class AbstractMetric<T> implements Metric<T> {
@Override
public String toString() {
return String.format("%s - namespace: %s key: %s value:%s", this.getClass().getName(), Arrays.toString(nameSpace.toArray()), this.key, getValue() == null ? "null" :
return String.format("%s - name: %s value:%s", this.getClass().getName(), this.name, getValue() == null ? "null" :
getValue().toString());
}
@Override
public List<String> getNameSpaces() {
return this.nameSpace;
}
@Override
public String getKey() {
return this.key;
public String getName() {
return this.name;
}
}

View file

@ -1,7 +1,5 @@
package org.logstash.instrument.metrics;
import java.util.List;
/**
* Top level contract for metrics within Logstash.
*
@ -11,38 +9,11 @@ import java.util.List;
public interface Metric<T> {
/**
* The list of namespaces this metric belongs to, for compatibility with Ruby code. Java consumers should use #getNameSpaces()
* This metric's name. May be used for display purposes.
*
* @return List of namespaces
* @deprecated
* @return The name of this metric.
*/
default List<String> namespaces() {
return getNameSpaces();
}
/**
* The list of namespaces this metric belongs to.
*
* @return List of namespaces
*/
List<String> getNameSpaces();
/**
* This metric's key (or name), exists for access through Ruby code. Java consumers should use #getKey()
*
* @return This metric's key
* @deprecated
*/
default String key() {
return getKey();
}
/**
* This metric's key (or name)
*
* @return List of namespaces
*/
String getKey();
String getName();
/**
* This should be equal to #getValue, exists for passivity with legacy Ruby code. Java consumers should use #getValue().
@ -88,4 +59,18 @@ public interface Metric<T> {
return getType().asString();
}
/**
* Determine if this metric has a value explicitly set.
* @return true if this metric has been set to a specific value, false if it is the default state
* @deprecated - This will be removed in the next release.
*/
boolean isDirty();
/**
* Sets the dirty state of this metric. A metric is dirty if it is anything other then it's default state.
*
* @param dirty the dirty state
* @deprecated - This will be removed in the next release.
*/
void setDirty(boolean dirty);
}

View file

@ -21,9 +21,13 @@ public enum MetricType {
*/
GAUGE_BOOLEAN("gauge/boolean"),
/**
* A gauge backed by a {@link Number} type
* A gauge backed by a {@link Double} type
*/
GAUGE_NUMERIC("gauge/numeric"),
GAUGE_DOUBLE("gauge/double"),
/**
* A gauge backed by a {@link Long} type
*/
GAUGE_LONG("gauge/long"),
/**
* A gauge backed by a {@link Object} type.
*/

View file

@ -16,7 +16,7 @@ public interface CounterMetric<T extends Number> extends Metric<T> {
/**
* Increments the counter by the value specified. <i>The caller should be careful to avoid incrementing by values so large as to overflow the underlying type.</i>
* @param by The value which to increment by.
* @param by The value which to increment by. Can not be negative.
*/
void increment(T by) ;
}

View file

@ -12,18 +12,19 @@ import java.util.concurrent.atomic.LongAdder;
*/
public class LongCounter extends AbstractMetric<Long> implements CounterMetric<Long> {
private final LongAdder longAdder;
private static final IllegalArgumentException NEGATIVE_COUNT_EXCEPTION = new IllegalArgumentException("Counters can not be incremented by negative values");
private LongAdder longAdder;
private volatile boolean dirty;
/**
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
*/
public LongCounter(List<String> nameSpace, String key) {
super(nameSpace, key);
public LongCounter(String name) {
super(name);
longAdder = new LongAdder();
}
}
@Override
public MetricType getType() {
@ -35,32 +36,40 @@ public class LongCounter extends AbstractMetric<Long> implements CounterMetric<L
return longAdder.longValue();
}
@Override
public boolean isDirty() {
return dirty;
}
@Override
public void setDirty(boolean dirty){
this.dirty = dirty;
}
@Override
public void increment() {
increment(1l);
}
/**
* {@inheritDoc}
* throws {@link UnsupportedOperationException} if attempt is made to increment by a negative value
*/
@Override
public void increment(Long by) {
if (by < 0) {
throw new UnsupportedOperationException("Counters can not be incremented by negative values");
throw NEGATIVE_COUNT_EXCEPTION;
}
longAdder.add(by);
dirty = true;
}
/**
* Optimized version of {@link #increment(Long)} to avoid auto-boxing.
* throws {@link UnsupportedOperationException} if attempt is made to increment by a negative value
* @param by The value which to increment by. Can not be negative.
*/
public void increment(long by) {
if (by < 0) {
throw new UnsupportedOperationException("Counters can not be incremented by negative values");
throw NEGATIVE_COUNT_EXCEPTION;
}
longAdder.add(by);
dirty = true;
}
}

View file

@ -0,0 +1,59 @@
package org.logstash.instrument.metrics.gauge;
import org.logstash.instrument.metrics.AbstractMetric;
/**
* Abstract {@link GaugeMetric} to hold the gauge value and handle the dirty state. Simplifies the contract by requiring the both the getter and setter to be the same type.
* @param <T> The type to set and get this gauge.
*/
public abstract class AbstractGaugeMetric<T> extends AbstractMetric<T> implements GaugeMetric<T,T>{
private volatile boolean dirty;
private volatile T value;
/**
* Constructor
*
* @param name The name of this metric. This value may be used for display purposes.
*/
protected AbstractGaugeMetric(String name) {
super(name);
}
/**
* Constructor
*
* @param name The name of this metric. This value may be used for display purposes.
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
*/
public AbstractGaugeMetric(String name, T initialValue) {
super(name);
this.value = initialValue;
setDirty(true);
}
@Override
public boolean isDirty() {
return dirty;
}
@Override
public void setDirty(boolean dirty){
this.dirty = dirty;
}
@Override
public T getValue() {
return value;
}
@Override
public void set(T value) {
this.value = value;
setDirty(true);
}
}

View file

@ -1,38 +1,30 @@
package org.logstash.instrument.metrics.gauge;
import org.logstash.instrument.metrics.AbstractMetric;
import org.logstash.instrument.metrics.MetricType;
import org.logstash.instrument.metrics.counter.CounterMetric;
import java.util.List;
/**
* A {@link GaugeMetric} that is backed by a {@link Boolean}
*/
public class BooleanGauge extends AbstractMetric<Boolean> implements GaugeMetric<Boolean,Boolean> {
private volatile Boolean value;
public class BooleanGauge extends AbstractGaugeMetric<Boolean> {
/**
* Constructor - null initial value
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
*/
public BooleanGauge(List<String> nameSpace, String key) {
this(nameSpace, key, null);
public BooleanGauge(String name) {
super(name);
}
/**
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
*/
public BooleanGauge(List<String> nameSpace, String key, Boolean initialValue) {
super(nameSpace, key);
this.value = initialValue;
public BooleanGauge(String name, Boolean initialValue) {
super(name, initialValue);
}
@Override
@ -40,14 +32,4 @@ public class BooleanGauge extends AbstractMetric<Boolean> implements GaugeMetric
return MetricType.GAUGE_BOOLEAN;
}
@Override
public Boolean getValue() {
return value;
}
@Override
public void set(Boolean value) {
this.value = value;
}
}

View file

@ -0,0 +1,35 @@
package org.logstash.instrument.metrics.gauge;
import org.logstash.instrument.metrics.MetricType;
/**
* A {@link GaugeMetric} that is backed by a {@link Double}
*/
public class DoubleGauge extends AbstractGaugeMetric<Double> {
/**
* Constructor
*
* @param name The name of this metric. This value may be used for display purposes.
*/
public DoubleGauge(String name) {
super(name);
}
/**
* Constructor
*
* @param name The name of this metric. This value may be used for display purposes.
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
*/
public DoubleGauge(String name, Double initialValue) {
super(name, initialValue);
}
@Override
public MetricType getType() {
return MetricType.GAUGE_DOUBLE;
}
}

View file

@ -16,4 +16,6 @@ public interface GaugeMetric<G,S> extends Metric<G> {
* @param value The value to set
*/
void set(S value);
}

View file

@ -13,6 +13,7 @@ import java.util.List;
/**
* A lazy proxy to a more specific typed {@link GaugeMetric}. The metric will only be initialized if the initial value is set, or once the {@code set} operation is called.
* <p><strong>Intended only for use with Ruby's duck typing, Java consumers should use the specific typed {@link GaugeMetric}</strong></p>
* @deprecated - there are no plans to replace this.
*/
public class LazyDelegatingGauge extends AbstractMetric<Object> implements GaugeMetric<Object,Object> {
@ -28,6 +29,7 @@ public class LazyDelegatingGauge extends AbstractMetric<Object> implements Gauge
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @deprecated - there are no plans to replace this
*/
public LazyDelegatingGauge(final List<String> nameSpace, final String key) {
this(nameSpace, key, null);
@ -39,9 +41,10 @@ public class LazyDelegatingGauge extends AbstractMetric<Object> implements Gauge
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
* @deprecated - there are no plans to replace this
*/
protected LazyDelegatingGauge(List<String> nameSpace, String key, Object initialValue) {
super(nameSpace, key);
super(key);
this.nameSpaces = nameSpace;
this.key = key;
if (initialValue != null) {
@ -65,6 +68,11 @@ public class LazyDelegatingGauge extends AbstractMetric<Object> implements Gauge
return lazyMetric == null ? null : lazyMetric.getValue();
}
@Override
public boolean isDirty() {
return lazyMetric == null ? false : lazyMetric.isDirty();
}
@Override
public void set(Object value) {
if (lazyMetric == null) {
@ -74,6 +82,11 @@ public class LazyDelegatingGauge extends AbstractMetric<Object> implements Gauge
}
}
@Override
public void setDirty(boolean dirty) {
lazyMetric.setDirty(dirty);
}
/**
* Instantiates the metric based on the type used to set this Gauge
*
@ -82,21 +95,24 @@ public class LazyDelegatingGauge extends AbstractMetric<Object> implements Gauge
private synchronized void wakeMetric(Object value) {
if (lazyMetric == null && value != null) {
//"quack quack"
if (value instanceof Number) {
lazyMetric = new NumericGauge(nameSpaces, key, (Number) value);
} else if (value instanceof String) {
lazyMetric = new TextGauge(nameSpaces, key, (String) value);
if (value instanceof String) {
lazyMetric = new TextGauge(key, (String) value);
} else if (value instanceof Long) {
lazyMetric = new LongGauge(key, (Long) value);
} else if (value instanceof Double) {
lazyMetric = new DoubleGauge(key, (Double) value);
} else if (value instanceof Boolean) {
lazyMetric = new BooleanGauge(nameSpaces, key, (Boolean) value);
lazyMetric = new BooleanGauge(key, (Boolean) value);
} else if (value instanceof RubyHash) {
lazyMetric = new RubyHashGauge(nameSpaces, key, (RubyHash) value);
lazyMetric = new RubyHashGauge(key, (RubyHash) value);
} else if (value instanceof RubyTimestamp) {
lazyMetric = new RubyTimeStampGauge(nameSpaces, key, ((RubyTimestamp) value));
lazyMetric = new RubyTimeStampGauge(key, ((RubyTimestamp) value));
} else {
LOGGER.warn("A gauge metric of an unknown type ({}) has been create for key: {}, namespace:{}. This may result in invalid serialization. It is recommended to " +
"log an issue to the responsible developer/development team.", value.getClass().getCanonicalName(), key, nameSpaces);
lazyMetric = new UnknownGauge(nameSpaces, key, value);
lazyMetric = new UnknownGauge(key, value);
}
lazyMetric.setDirty(true);
}
}

View file

@ -0,0 +1,36 @@
package org.logstash.instrument.metrics.gauge;
import org.logstash.instrument.metrics.MetricType;
/**
* A {@link GaugeMetric} that is backed by a {@link Long}
*/
public class LongGauge extends AbstractGaugeMetric<Long> {
/**
* Constructor
*
* @param name The name of this metric. This value may be used for display purposes.
*/
public LongGauge(String name) {
super(name);
}
/**
* Constructor
*
* @param name The name of this metric. This value may be used for display purposes.
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
*/
public LongGauge(String name, Long initialValue) {
super(name, initialValue);
}
@Override
public MetricType getType() {
return MetricType.GAUGE_LONG;
}
}

View file

@ -1,52 +0,0 @@
package org.logstash.instrument.metrics.gauge;
import org.logstash.instrument.metrics.AbstractMetric;
import org.logstash.instrument.metrics.MetricType;
import java.util.List;
/**
* A {@link GaugeMetric} that is backed by a {@link Number}
*/
public class NumericGauge extends AbstractMetric<Number> implements GaugeMetric<Number,Number> {
private volatile Number value;
/**
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
*/
public NumericGauge(List<String> nameSpace, String key) {
this(nameSpace, key, null);
}
/**
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
*/
public NumericGauge(List<String> nameSpace, String key, Number initialValue) {
super(nameSpace, key);
this.value = initialValue;
}
@Override
public MetricType getType() {
return MetricType.GAUGE_NUMERIC;
}
@Override
public Number getValue() {
return value;
}
@Override
public void set(Number value) {
this.value = value;
}
}

View file

@ -10,31 +10,29 @@ import java.util.List;
/**
* A {@link GaugeMetric} that is backed by a {@link RubyHash}. Note - This should not be used directly from Java code and exists for passivity with legacy Ruby code. Depending
* on the types in in the {@link RubyHash} there are no guarantees serializing properly.
* @deprecated - There are no plans to replace this.
*/
public class RubyHashGauge extends AbstractMetric<RubyHash> implements GaugeMetric<RubyHash,RubyHash> {
private volatile RubyHash value;
public class RubyHashGauge extends AbstractGaugeMetric<RubyHash> {
/**
* Constructor - protected so that Ruby may sub class proxy and discourage usage from Java, null initial value
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
* @deprecated - There are no plans to replace this.
*/
protected RubyHashGauge(List<String> nameSpace, String key) {
this(nameSpace, key, null);
protected RubyHashGauge(String name) {
super(name);
}
/**
* Constructor - protected so that Ruby may sub class proxy and discourage usage from Java
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
* @deprecated - There are no plans to replace this.
*/
protected RubyHashGauge(List<String> nameSpace, String key, RubyHash initialValue) {
super(nameSpace, key);
this.value = initialValue;
protected RubyHashGauge(String name, RubyHash initialValue) {
super(name, initialValue);
}
@Override
@ -42,14 +40,4 @@ public class RubyHashGauge extends AbstractMetric<RubyHash> implements GaugeMetr
return MetricType.GAUGE_RUBYHASH;
}
@Override
public RubyHash getValue() {
return value;
}
@Override
public void set(RubyHash value) {
this.value = value;
}
}

View file

@ -11,31 +11,35 @@ import java.util.List;
/**
* A {@link GaugeMetric} that is set by a {@link RubyTimestamp}, and retrieved/serialized as a {@link Timestamp}. Note - This should not be used directly from Java code and
* exists for passivity with legacy Ruby code.
* @deprecated - There are no plans to replace this.
*/
public class RubyTimeStampGauge extends AbstractMetric<Timestamp> implements GaugeMetric<Timestamp, RubyTimestamp> {
private volatile Timestamp value;
private volatile boolean dirty;
/**
* Constructor - protected so that Ruby may sub class proxy and discourage usage from Java, null initial value
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @deprecated - There are no plans to replace this.
*/
protected RubyTimeStampGauge(List<String> nameSpace, String key) {
this(nameSpace, key, null);
public RubyTimeStampGauge(String key) {
super(key);
}
/**
* Constructor - protected so that Ruby may sub class proxy and discourage usage from Java
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
* @deprecated - There are no plans to replace this.
*/
protected RubyTimeStampGauge(List<String> nameSpace, String key, RubyTimestamp initialValue) {
super(nameSpace, key);
protected RubyTimeStampGauge(String key, RubyTimestamp initialValue) {
super(key);
this.value = initialValue == null ? null : initialValue.getTimestamp();
setDirty(true);
}
@Override
@ -48,8 +52,19 @@ public class RubyTimeStampGauge extends AbstractMetric<Timestamp> implements Gau
return value;
}
@Override
public boolean isDirty() {
return dirty;
}
@Override
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
@Override
public void set(RubyTimestamp value) {
this.value = value == null ? null : value.getTimestamp();
setDirty(true);
}
}

View file

@ -1,38 +1,30 @@
package org.logstash.instrument.metrics.gauge;
import org.logstash.instrument.metrics.AbstractMetric;
import org.logstash.instrument.metrics.MetricType;
import java.util.List;
/**
* A {@link GaugeMetric} that is backed by a {@link String}
*/
public class TextGauge extends AbstractMetric<String> implements GaugeMetric<String,String> {
private volatile String value;
public class TextGauge extends AbstractGaugeMetric<String> {
/**
* Constructor - null initial value
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
*/
public TextGauge(List<String> nameSpace, String key) {
this(nameSpace, key, null);
public TextGauge(String name) {
super(name);
}
/**
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
*/
public TextGauge(List<String> nameSpace, String key, String initialValue) {
super(nameSpace, key);
this.value = initialValue;
public TextGauge(String name, String initialValue) {
super(name, initialValue);
}
@Override
@ -40,15 +32,4 @@ public class TextGauge extends AbstractMetric<String> implements GaugeMetric<Str
return MetricType.GAUGE_TEXT;
}
@Override
public String getValue() {
return value;
}
@Override
public void set(String value) {
this.value = value;
}
}

View file

@ -1,52 +1,36 @@
package org.logstash.instrument.metrics.gauge;
import org.logstash.instrument.metrics.AbstractMetric;
import org.logstash.instrument.metrics.MetricType;
import java.util.List;
/**
* A {@link GaugeMetric} that is backed by a {@link Object}. Note - A stronger typed {@link GaugeMetric} should be used since this makes no guarantees of serializing properly.
* @deprecated - There are no plans to replace this.
*/
public class UnknownGauge extends AbstractMetric<Object> implements GaugeMetric<Object,Object> {
private volatile Object value;
public class UnknownGauge extends AbstractGaugeMetric<Object> {
/**
* Constructor - null initial value
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
* @deprecated - There are no plans to replace this.
*/
public UnknownGauge(List<String> nameSpace, String key) {
this(nameSpace, key, null);
public UnknownGauge(String name) {
super(name);
}
/**
* Constructor
*
* @param nameSpace The namespace for this metric
* @param key The key <i>(with in the namespace)</i> for this metric
* @param name The name of this metric. This value may be used for display purposes.
* @param initialValue The initial value for this {@link GaugeMetric}, may be null
* @deprecated - There are no plans to replace this.
*/
public UnknownGauge(List<String> nameSpace, String key, Object initialValue) {
super(nameSpace, key);
this.value = initialValue;
public UnknownGauge(String name, Object initialValue) {
super(name, initialValue);
}
@Override
public MetricType getType() {
return MetricType.GAUGE_UNKNOWN;
}
@Override
public Object getValue() {
return value;
}
@Override
public void set(Object value) {
this.value = value;
}
}

View file

@ -24,7 +24,8 @@ public class MetricTypeTest {
nameMap.put(MetricType.COUNTER_LONG, "counter/long");
nameMap.put(MetricType.GAUGE_TEXT, "gauge/text");
nameMap.put(MetricType.GAUGE_BOOLEAN, "gauge/boolean");
nameMap.put(MetricType.GAUGE_NUMERIC, "gauge/numeric");
nameMap.put(MetricType.GAUGE_LONG, "gauge/long");
nameMap.put(MetricType.GAUGE_DOUBLE, "gauge/double");
nameMap.put(MetricType.GAUGE_UNKNOWN, "gauge/unknown");
nameMap.put(MetricType.GAUGE_RUBYHASH, "gauge/rubyhash");
nameMap.put(MetricType.GAUGE_RUBYTIMESTAMP, "gauge/rubytimestamp");

View file

@ -19,7 +19,7 @@ public class LongCounterTest {
@Before
public void _setup() {
longCounter = new LongCounter(Collections.singletonList("foo"), "bar");
longCounter = new LongCounter("bar");
}
@Test
@ -29,12 +29,11 @@ public class LongCounterTest {
@Test
public void increment() {
longCounter.increment();
assertThat(longCounter.getValue()).isEqualTo(INITIAL_VALUE + 1);
}
@Test(expected = UnsupportedOperationException.class)
@Test(expected = IllegalArgumentException.class)
public void incrementByNegativeValue() {
longCounter.increment(-100l);
}
@ -43,17 +42,23 @@ public class LongCounterTest {
public void incrementByValue() {
longCounter.increment(100l);
assertThat(longCounter.getValue()).isEqualTo(INITIAL_VALUE + 100);
longCounter.increment(Long.valueOf(100));
assertThat(longCounter.getValue()).isEqualTo(INITIAL_VALUE + 200);
}
@Test
public void noInitialValue() {
LongCounter counter = new LongCounter(Collections.singletonList("foo"), "bar");
LongCounter counter = new LongCounter("bar");
assertThat(counter.isDirty()).isFalse();
counter.increment();
assertThat(counter.isDirty()).isTrue();
assertThat(counter.getValue()).isEqualTo(1l);
counter.setDirty(false);
assertThat(counter.isDirty()).isFalse();
}
@Test
@SuppressWarnings( "deprecation" )
@SuppressWarnings("deprecation")
public void type() {
assertThat(longCounter.type()).isEqualTo(MetricType.COUNTER_LONG.asString());
}

View file

@ -13,23 +13,29 @@ import static org.assertj.core.api.Assertions.assertThat;
public class BooleanGaugeTest {
@Test
public void getValue() {
BooleanGauge gauge = new BooleanGauge(Collections.singletonList("foo"), "bar", true);
BooleanGauge gauge = new BooleanGauge("bar", true);
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isTrue();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_BOOLEAN);
//Null initialize
gauge = new BooleanGauge(Collections.singletonList("foo"), "bar");
gauge = new BooleanGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_BOOLEAN);
}
@Test
public void set() {
BooleanGauge gauge = new BooleanGauge(Collections.singletonList("foo"), "bar");
BooleanGauge gauge = new BooleanGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.isDirty()).isFalse();
gauge.set(true);
assertThat(gauge.getValue()).isTrue();
gauge.set(false);
assertThat(gauge.getValue()).isFalse();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_BOOLEAN);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.getValue()).isFalse();
}
}

View file

@ -0,0 +1,39 @@
package org.logstash.instrument.metrics.gauge;
import org.junit.Test;
import org.logstash.instrument.metrics.MetricType;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link DoubleGauge}
*/
public class DoubleGaugeTest {
@Test
public void getValue() {
DoubleGauge gauge = new DoubleGauge("bar", 123.0);
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isEqualTo(123.0);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_DOUBLE);
//Null
gauge = new DoubleGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_DOUBLE);
}
@Test
public void set() {
DoubleGauge gauge = new DoubleGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.isDirty()).isFalse();
gauge.set(123.0);
assertThat(gauge.getValue()).isEqualTo(123.0);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_DOUBLE);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.isDirty()).isFalse();
}
}

View file

@ -4,6 +4,8 @@ import org.jruby.RubyHash;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.logstash.Timestamp;
import org.logstash.ext.JrubyTimestampExtLibrary;
import org.logstash.instrument.metrics.MetricType;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@ -23,20 +25,32 @@ public class LazyDelegatingGaugeTest {
@Mock
RubyHash rubyHash;
@Mock
private JrubyTimestampExtLibrary.RubyTimestamp rubyTimestamp;
private final Timestamp timestamp = new Timestamp();
private static final String RUBY_HASH_AS_STRING = "{}";
@Before
public void _setup() {
//hacky workaround using the toString method to avoid mocking the Ruby runtime
when(rubyHash.toString()).thenReturn(RUBY_HASH_AS_STRING);
when(rubyTimestamp.getTimestamp()).thenReturn(timestamp);
}
@Test
public void getValue() {
//Numeric
//Long
LazyDelegatingGauge gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar", 99l);
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isEqualTo(99l);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LONG);
//Double
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar", 99.0);
assertThat(gauge.getValue()).isEqualTo(99.0);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_DOUBLE);
//Boolean
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar", true);
@ -53,6 +67,11 @@ public class LazyDelegatingGaugeTest {
assertThat(gauge.getValue().toString()).isEqualTo(RUBY_HASH_AS_STRING);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYHASH);
//Ruby Timestamp
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar", rubyTimestamp);
assertThat(gauge.getValue()).isEqualTo(timestamp);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYTIMESTAMP);
//Unknown
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar", Collections.singleton("value"));
assertThat(gauge.getValue()).isEqualTo(Collections.singleton("value"));
@ -68,13 +87,23 @@ public class LazyDelegatingGaugeTest {
@Test
public void set() {
//Numeric
//Long
LazyDelegatingGauge gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar");
assertThat(gauge.isDirty()).isFalse();
gauge.set(99l);
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isEqualTo(99l);
gauge.set(199l);
assertThat(gauge.getValue()).isEqualTo(199l);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LONG);
//Double
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar");
gauge.set(99.0);
assertThat(gauge.getValue()).isEqualTo(99.0);
gauge.set(199.01);
assertThat(gauge.getValue()).isEqualTo(199.01);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_DOUBLE);
//Boolean
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar");
@ -98,6 +127,12 @@ public class LazyDelegatingGaugeTest {
assertThat(gauge.getValue().toString()).isEqualTo(RUBY_HASH_AS_STRING);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYHASH);
//Ruby Timestamp
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar");
gauge.set(rubyTimestamp);
assertThat(gauge.getValue()).isEqualTo(timestamp);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYTIMESTAMP);
//Unknown
gauge = new LazyDelegatingGauge(Collections.singletonList("foo"), "bar");
gauge.set(Collections.singleton("value"));
@ -119,6 +154,9 @@ public class LazyDelegatingGaugeTest {
gauge.set(null);
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_TEXT);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.isDirty()).isFalse();
}
}

View file

@ -0,0 +1,39 @@
package org.logstash.instrument.metrics.gauge;
import org.junit.Test;
import org.logstash.instrument.metrics.MetricType;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link LongGauge}
*/
public class LongGaugeTest {
@Test
public void getValue() {
LongGauge gauge = new LongGauge("bar", 99l);
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isEqualTo(99);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LONG);
//Null
gauge = new LongGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LONG);
}
@Test
public void set() {
LongGauge gauge = new LongGauge("bar");
assertThat(gauge.isDirty()).isFalse();
assertThat(gauge.getValue()).isNull();
gauge.set(123l);
assertThat(gauge.getValue()).isEqualTo(123);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_LONG);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.isDirty()).isFalse();
}
}

View file

@ -1,58 +0,0 @@
package org.logstash.instrument.metrics.gauge;
import org.junit.Test;
import org.logstash.instrument.metrics.MetricType;
import java.math.BigInteger;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link NumericGauge}
*/
public class NumericGaugeTest {
@Test
public void getValue() {
//Long
NumericGauge gauge = new NumericGauge(Collections.singletonList("foo"), "bar", 99l);
assertThat(gauge.getValue()).isEqualTo(99l);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
//Float
gauge = new NumericGauge(Collections.singletonList("foo"), "bar", 123.0f);
assertThat(gauge.getValue()).isEqualTo(123.0f);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
//Null
gauge = new NumericGauge(Collections.singletonList("foo"), "bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
}
@Test
public void set() {
//Long
NumericGauge gauge = new NumericGauge(Collections.singletonList("foo"), "bar");
gauge.set(99l);
assertThat(gauge.getValue()).isEqualTo(99l);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
//Float
gauge = new NumericGauge(Collections.singletonList("foo"), "bar");
gauge.set(123.0f);
assertThat(gauge.getValue()).isEqualTo(123.0f);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
//Null
gauge = new NumericGauge(Collections.singletonList("foo"), "bar");
gauge.set(BigInteger.TEN);
assertThat(gauge.getValue()).isEqualTo(BigInteger.TEN);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_NUMERIC);
}
}

View file

@ -33,12 +33,13 @@ public class RubyHashGaugeTest {
@Test
public void getValue() {
RubyHashGauge gauge = new RubyHashGauge(Collections.singletonList("foo"), "bar", rubyHash);
RubyHashGauge gauge = new RubyHashGauge("bar", rubyHash);
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue().toString()).isEqualTo(RUBY_HASH_AS_STRING);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYHASH);
//Null initialize
final RubyHashGauge gauge2 = new RubyHashGauge(Collections.singletonList("foo"), "bar");
final RubyHashGauge gauge2 = new RubyHashGauge("bar");
Throwable thrown = catchThrowable(() -> {
gauge2.getValue().toString();
});
@ -48,10 +49,14 @@ public class RubyHashGaugeTest {
@Test
public void set() {
RubyHashGauge gauge = new RubyHashGauge(Collections.singletonList("foo"), "bar");
RubyHashGauge gauge = new RubyHashGauge("bar");
assertThat(gauge.isDirty()).isFalse();
gauge.set(rubyHash);
assertThat(gauge.getValue().toString()).isEqualTo(RUBY_HASH_AS_STRING);
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYHASH);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.isDirty()).isFalse();
}
}

View file

@ -33,21 +33,26 @@ public class RubyTimeStampGaugeTest {
@Test
public void getValue() {
RubyTimeStampGauge gauge = new RubyTimeStampGauge(Collections.singletonList("foo"), "bar", rubyTimestamp);
RubyTimeStampGauge gauge = new RubyTimeStampGauge("bar", rubyTimestamp);
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isEqualTo(rubyTimestamp.getTimestamp());
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYTIMESTAMP);
//Null initialize
gauge = new RubyTimeStampGauge(Collections.singletonList("foo"), "bar");
gauge = new RubyTimeStampGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYTIMESTAMP);
}
@Test
public void set() {
RubyTimeStampGauge gauge = new RubyTimeStampGauge(Collections.singletonList("foo"), "bar", Mockito.mock(RubyTimestamp.class));
RubyTimeStampGauge gauge = new RubyTimeStampGauge("bar");
assertThat(gauge.isDirty()).isFalse();
gauge.set(rubyTimestamp);
assertThat(gauge.getValue()).isEqualTo(rubyTimestamp.getTimestamp());
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYTIMESTAMP);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.isDirty()).isFalse();
}
}

View file

@ -13,21 +13,26 @@ import static org.assertj.core.api.Assertions.assertThat;
public class TextGaugeTest {
@Test
public void getValue() {
TextGauge gauge = new TextGauge(Collections.singletonList("foo"), "bar", "baz");
TextGauge gauge = new TextGauge("bar", "baz");
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isEqualTo("baz");
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_TEXT);
//Null initialize
gauge = new TextGauge(Collections.singletonList("foo"), "bar");
gauge = new TextGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_TEXT);
}
@Test
public void set() {
TextGauge gauge = new TextGauge(Collections.singletonList("foo"), "bar");
TextGauge gauge = new TextGauge("bar");
assertThat(gauge.isDirty()).isFalse();
gauge.set("baz");
assertThat(gauge.getValue()).isEqualTo("baz");
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_TEXT);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.isDirty()).isFalse();
}
}

View file

@ -15,23 +15,28 @@ public class UnknownGaugeTest {
@Test
public void getValue() {
UnknownGauge gauge = new UnknownGauge(Collections.singletonList("foo"), "bar", URI.create("baz"));
UnknownGauge gauge = new UnknownGauge("bar", URI.create("baz"));
assertThat(gauge.isDirty()).isTrue();
assertThat(gauge.getValue()).isEqualTo(URI.create("baz"));
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_UNKNOWN);
//Null initialize
gauge = new UnknownGauge(Collections.singletonList("foo"), "bar");
gauge = new UnknownGauge("bar");
assertThat(gauge.getValue()).isNull();
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_UNKNOWN);
}
@Test
public void set() {
UnknownGauge gauge = new UnknownGauge(Collections.singletonList("foo"), "bar");
UnknownGauge gauge = new UnknownGauge("bar");
assertThat(gauge.isDirty()).isFalse();
gauge.set(URI.create("baz"));
assertThat(gauge.getValue()).isEqualTo(URI.create("baz"));
gauge.set(URI.create("fizzbuzz"));
assertThat(gauge.getValue()).isEqualTo(URI.create("fizzbuzz"));
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_UNKNOWN);
assertThat(gauge.isDirty()).isTrue();
gauge.setDirty(false);
assertThat(gauge.isDirty()).isFalse();
}
}