mirror of
https://github.com/elastic/logstash.git
synced 2025-04-24 22:57:16 -04:00
Metrics: Fix RubyTimestamp serialization
This change requires setting the and retrieving the value with different types. The Gauge interface has been update to allow for setting / getting using different types. Fixes #7719 Fixes #7720
This commit is contained in:
parent
c4983e509f
commit
eaaec59380
11 changed files with 130 additions and 12 deletions
|
@ -31,7 +31,11 @@ public enum MetricType {
|
|||
/**
|
||||
* A gauge backed by a {@link org.jruby.RubyHash} type. Note - Java consumers should not use this, exist for legacy Ruby code.
|
||||
*/
|
||||
GAUGE_RUBYHASH("gauge/rubyhash");
|
||||
GAUGE_RUBYHASH("gauge/rubyhash"),
|
||||
/**
|
||||
* A gauge backed by a {@link org.logstash.ext.JrubyTimestampExtLibrary.RubyTimestamp} type. Note - Java consumers should not use this, exist for legacy Ruby code.
|
||||
*/
|
||||
GAUGE_RUBYTIMESTAMP("gauge/rubytimestamp");
|
||||
|
||||
private final String type;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
/**
|
||||
* A {@link GaugeMetric} that is backed by a {@link Boolean}
|
||||
*/
|
||||
public class BooleanGauge extends AbstractMetric<Boolean> implements GaugeMetric<Boolean> {
|
||||
public class BooleanGauge extends AbstractMetric<Boolean> implements GaugeMetric<Boolean,Boolean> {
|
||||
|
||||
private volatile Boolean value;
|
||||
|
||||
|
|
|
@ -6,13 +6,14 @@ import org.logstash.instrument.metrics.Metric;
|
|||
/**
|
||||
* A {@link Metric} to set/get a value. A Gauge is useful for measuring a single value that may change over time, but does not carry any additional semantics beyond simply setting
|
||||
* and getting the value.
|
||||
* @param <T> The backing Java type for the gauge. For example, a text gauge is backed by a {@link String}
|
||||
* @param <G> The backing Java type for getting the gauge. For example, a text gauge should return a {@link String}
|
||||
* @param <S> The backing Java type for setting the gauge. For example, a text gauge is set with a {@link String}
|
||||
*/
|
||||
public interface GaugeMetric<T> extends Metric<T> {
|
||||
public interface GaugeMetric<G,S> extends Metric<G> {
|
||||
|
||||
/**
|
||||
* Sets the value
|
||||
* @param value The value to set
|
||||
*/
|
||||
void set(T value);
|
||||
void set(S value);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,10 @@ package org.logstash.instrument.metrics.gauge;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jruby.RubyHash;
|
||||
import org.logstash.Timestamp;
|
||||
import org.logstash.ext.JrubyTimestampExtLibrary.RubyTimestamp;
|
||||
import org.logstash.instrument.metrics.AbstractMetric;
|
||||
import org.logstash.instrument.metrics.MetricType;
|
||||
import org.logstash.instrument.metrics.counter.CounterMetric;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -13,7 +14,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>
|
||||
*/
|
||||
public class LazyDelegatingGauge extends AbstractMetric<Object> implements GaugeMetric<Object> {
|
||||
public class LazyDelegatingGauge extends AbstractMetric<Object> implements GaugeMetric<Object,Object> {
|
||||
|
||||
private final static Logger LOGGER = LogManager.getLogger(LazyDelegatingGauge.class);
|
||||
|
||||
|
@ -89,6 +90,8 @@ public class LazyDelegatingGauge extends AbstractMetric<Object> implements Gauge
|
|||
lazyMetric = new BooleanGauge(nameSpaces, key, (Boolean) value);
|
||||
} else if (value instanceof RubyHash) {
|
||||
lazyMetric = new RubyHashGauge(nameSpaces, key, (RubyHash) value);
|
||||
} else if (value instanceof RubyTimestamp) {
|
||||
lazyMetric = new RubyTimeStampGauge(nameSpaces, 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);
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.List;
|
|||
/**
|
||||
* A {@link GaugeMetric} that is backed by a {@link Number}
|
||||
*/
|
||||
public class NumericGauge extends AbstractMetric<Number> implements GaugeMetric<Number> {
|
||||
public class NumericGauge extends AbstractMetric<Number> implements GaugeMetric<Number,Number> {
|
||||
|
||||
private volatile Number value;
|
||||
|
||||
|
|
|
@ -4,13 +4,14 @@ import org.jruby.RubyHash;
|
|||
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 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.
|
||||
*/
|
||||
public class RubyHashGauge extends AbstractMetric<RubyHash> implements GaugeMetric<RubyHash> {
|
||||
public class RubyHashGauge extends AbstractMetric<RubyHash> implements GaugeMetric<RubyHash,RubyHash> {
|
||||
|
||||
private volatile RubyHash value;
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package org.logstash.instrument.metrics.gauge;
|
||||
|
||||
import org.logstash.Timestamp;
|
||||
import org.logstash.bivalues.BiValues;
|
||||
import org.logstash.ext.JrubyTimestampExtLibrary.RubyTimestamp;
|
||||
import org.logstash.instrument.metrics.AbstractMetric;
|
||||
import org.logstash.instrument.metrics.MetricType;
|
||||
|
||||
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.
|
||||
*/
|
||||
public class RubyTimeStampGauge extends AbstractMetric<Timestamp> implements GaugeMetric<Timestamp, RubyTimestamp> {
|
||||
|
||||
private volatile Timestamp value;
|
||||
|
||||
/**
|
||||
* Constructor - protected so that Ruby may sub class proxy and discourage usage from Java, null initial value
|
||||
*
|
||||
* @param nameSpace The namespace for this metric
|
||||
* @param key The key <i>(with in the namespace)</i> for this metric
|
||||
*/
|
||||
protected RubyTimeStampGauge(List<String> nameSpace, String key) {
|
||||
this(nameSpace, key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected RubyTimeStampGauge(List<String> nameSpace, String key, RubyTimestamp initialValue) {
|
||||
super(nameSpace, key);
|
||||
this.value = initialValue == null ? null : initialValue.getTimestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricType getType() {
|
||||
return MetricType.GAUGE_RUBYTIMESTAMP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timestamp getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(RubyTimestamp value) {
|
||||
this.value = value == null ? null : value.getTimestamp();
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
/**
|
||||
* A {@link GaugeMetric} that is backed by a {@link String}
|
||||
*/
|
||||
public class TextGauge extends AbstractMetric<String> implements GaugeMetric<String> {
|
||||
public class TextGauge extends AbstractMetric<String> implements GaugeMetric<String,String> {
|
||||
|
||||
private volatile String value;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ 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.
|
||||
*/
|
||||
public class UnknownGauge extends AbstractMetric<Object> implements GaugeMetric<Object> {
|
||||
public class UnknownGauge extends AbstractMetric<Object> implements GaugeMetric<Object,Object> {
|
||||
|
||||
private volatile Object value;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ public class MetricTypeTest {
|
|||
nameMap.put(MetricType.GAUGE_NUMERIC, "gauge/numeric");
|
||||
nameMap.put(MetricType.GAUGE_UNKNOWN, "gauge/unknown");
|
||||
nameMap.put(MetricType.GAUGE_RUBYHASH, "gauge/rubyhash");
|
||||
nameMap.put(MetricType.GAUGE_RUBYTIMESTAMP, "gauge/rubytimestamp");
|
||||
|
||||
//ensure we are testing all of the enumerations
|
||||
assertThat(EnumSet.allOf(MetricType.class).size()).isEqualTo(nameMap.size());
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.logstash.instrument.metrics.gauge;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.logstash.Timestamp;
|
||||
import org.logstash.ext.JrubyTimestampExtLibrary.RubyTimestamp;
|
||||
import org.logstash.instrument.metrics.MetricType;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RubyTimeStampGauge}
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RubyTimeStampGaugeTest {
|
||||
|
||||
@Mock
|
||||
private RubyTimestamp rubyTimestamp;
|
||||
|
||||
private final Timestamp timestamp = new Timestamp();
|
||||
|
||||
@Before
|
||||
public void _setup() {
|
||||
when(rubyTimestamp.getTimestamp()).thenReturn(timestamp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getValue() {
|
||||
RubyTimeStampGauge gauge = new RubyTimeStampGauge(Collections.singletonList("foo"), "bar", rubyTimestamp);
|
||||
assertThat(gauge.getValue()).isEqualTo(rubyTimestamp.getTimestamp());
|
||||
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYTIMESTAMP);
|
||||
|
||||
//Null initialize
|
||||
gauge = new RubyTimeStampGauge(Collections.singletonList("foo"), "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));
|
||||
gauge.set(rubyTimestamp);
|
||||
assertThat(gauge.getValue()).isEqualTo(rubyTimestamp.getTimestamp());
|
||||
assertThat(gauge.getType()).isEqualTo(MetricType.GAUGE_RUBYTIMESTAMP);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue