timeable) {
+ Timer timer = startTimer();
+ try {
+ return timeable.call();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ timer.observeDuration();
+ }
+ }
+
/**
* Get the value of the Summary.
*
* Warning: The definition of {@link Value} is subject to change.
*/
public Value get() {
- return new Value(count.sum(), sum.sum(), quantiles, quantileValues);
+ return new Value(count, sum, quantiles, quantileValues);
}
+
}
// Convenience methods.
+
/**
* Observe the given amount on the summary with no labels.
*/
public void observe(double amt) {
noLabelsChild.observe(amt);
}
+
/**
* Start a timer to track a duration on the summary with no labels.
*
@@ -323,7 +370,7 @@ public Timer startTimer() {
* @param timeable Code that is being timed
* @return Measured duration in seconds for timeable to complete.
*/
- public double time(Runnable timeable){
+ public double time(Runnable timeable) {
return noLabelsChild.time(timeable);
}
@@ -333,7 +380,7 @@ public double time(Runnable timeable){
* @param timeable Code that is being timed
* @return Result returned by callable.
*/
- public E time(Callable timeable){
+ public E time(Callable timeable) {
return noLabelsChild.time(timeable);
}
@@ -349,19 +396,22 @@ public Child.Value get() {
@Override
public List collect() {
List samples = new ArrayList();
- for(Map.Entry, Child> c: children.entrySet()) {
- Child.Value v = c.getValue().get();
+ for (Map.Entry, Child> child : children.entrySet()) {
+ Child.Value value = child.getValue().get();
List labelNamesWithQuantile = new ArrayList(labelNames);
labelNamesWithQuantile.add("quantile");
- for(Map.Entry q : v.quantiles.entrySet()) {
- List labelValuesWithQuantile = new ArrayList(c.getKey());
- labelValuesWithQuantile.add(doubleToGoString(q.getKey()));
- samples.add(new MetricFamilySamples.Sample(fullname, labelNamesWithQuantile, labelValuesWithQuantile, q.getValue()));
+ for (Map.Entry quantile : value.quantiles.entrySet()) {
+ List labelValuesWithQuantile = new ArrayList(child.getKey());
+ labelValuesWithQuantile.add(doubleToGoString(quantile.getKey()));
+ samples.add(new MetricFamilySamples.Sample(fullname, labelNamesWithQuantile, labelValuesWithQuantile, quantile.getValue()));
+ }
+ if (!value.quantiles.isEmpty()) {
+ samples.add(new MetricFamilySamples.Sample(fullname + "_min", labelNames, child.getKey(), value.min));
+ samples.add(new MetricFamilySamples.Sample(fullname + "_max", labelNames, child.getKey(), value.max));
}
- samples.add(new MetricFamilySamples.Sample(fullname + "_count", labelNames, c.getKey(), v.count));
- samples.add(new MetricFamilySamples.Sample(fullname + "_sum", labelNames, c.getKey(), v.sum));
+ samples.add(new MetricFamilySamples.Sample(fullname + "_count", labelNames, child.getKey(), value.count));
+ samples.add(new MetricFamilySamples.Sample(fullname + "_sum", labelNames, child.getKey(), value.sum));
}
-
return familySamplesList(Type.SUMMARY, samples);
}
diff --git a/simpleclient/src/main/java/io/prometheus/client/TimeWindowQuantiles.java b/simpleclient/src/main/java/io/prometheus/client/TimeWindowQuantiles.java
index cc60bc39b..a2a32e214 100644
--- a/simpleclient/src/main/java/io/prometheus/client/TimeWindowQuantiles.java
+++ b/simpleclient/src/main/java/io/prometheus/client/TimeWindowQuantiles.java
@@ -1,54 +1,99 @@
package io.prometheus.client;
-import io.prometheus.client.CKMSQuantiles.Quantile;
+import org.HdrHistogram.ConcurrentDoubleHistogram;
+
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
/**
- * Wrapper around CKMSQuantiles.
- *
- * Maintains a ring buffer of CKMSQuantiles to provide quantiles over a sliding windows of time.
+ * Wrapper around HdrHistogram.
+ *
+ * Maintains a ring buffer of HdrHistogram to provide quantiles over a sliding windows of time.
*/
class TimeWindowQuantiles {
- private final Quantile[] quantiles;
- private final CKMSQuantiles[] ringBuffer;
- private int currentBucket;
- private long lastRotateTimestampMillis;
- private final long durationBetweenRotatesMillis;
+ private final long highestToLowestValueRatio;
+ private final int numberOfSignificantValueDigits;
+ private final AtomicReference buckets;
+ private final AtomicLong lastRotateTimestampNanos;
+ private final long durationBetweenRotatesNanos;
- public TimeWindowQuantiles(Quantile[] quantiles, long maxAgeSeconds, int ageBuckets) {
- this.quantiles = quantiles;
- this.ringBuffer = new CKMSQuantiles[ageBuckets];
+ public TimeWindowQuantiles(long highestToLowestValueRatio, int numberOfSignificantValueDigits, long maxAgeSeconds, int ageBuckets) {
+ this.highestToLowestValueRatio = highestToLowestValueRatio;
+ this.numberOfSignificantValueDigits = numberOfSignificantValueDigits;
+ ConcurrentDoubleHistogram[] emptyBuckets = new ConcurrentDoubleHistogram[ageBuckets];
for (int i = 0; i < ageBuckets; i++) {
- this.ringBuffer[i] = new CKMSQuantiles(quantiles);
+ emptyBuckets[i] = createBucket();
}
- this.currentBucket = 0;
- this.lastRotateTimestampMillis = System.currentTimeMillis();
- this.durationBetweenRotatesMillis = TimeUnit.SECONDS.toMillis(maxAgeSeconds) / ageBuckets;
+ this.buckets = new AtomicReference(emptyBuckets);
+ this.lastRotateTimestampNanos = new AtomicLong(System.nanoTime());
+ this.durationBetweenRotatesNanos = TimeUnit.SECONDS.toNanos(maxAgeSeconds) / ageBuckets;
+ }
+
+ private ConcurrentDoubleHistogram createBucket() {
+ ConcurrentDoubleHistogram bucket = new ConcurrentDoubleHistogram(highestToLowestValueRatio, numberOfSignificantValueDigits);
+ bucket.setAutoResize(true);
+
+ return bucket;
+ }
+
+ public double get(double quantile) {
+ // On concurrent `get` and `rotate`, it is acceptable to `get` the sample from an outdated `bucket`.
+ ConcurrentDoubleHistogram currentBucket = getCurrentBucket();
+ return currentBucket.getTotalCount() == 0 ? Double.NaN : currentBucket.getValueAtPercentile(quantile * 100.0);
+ }
+
+ public double getMin() {
+ ConcurrentDoubleHistogram currentBucket = getCurrentBucket();
+ return currentBucket.getTotalCount() == 0 ? Double.NaN : currentBucket.getMinValue();
}
- public synchronized double get(double q) {
- CKMSQuantiles currentBucket = rotate();
- return currentBucket.get(q);
+ public double getMax() {
+ ConcurrentDoubleHistogram currentBucket = getCurrentBucket();
+ return currentBucket.getTotalCount() == 0 ? Double.NaN : currentBucket.getMaxValue();
}
- public synchronized void insert(double value) {
+ public void insert(double value) {
+ // On concurrent `insert` and `rotate`, it should be acceptable to lose the measurement in the newest `bucket`.
rotate();
- for (CKMSQuantiles ckmsQuantiles : ringBuffer) {
- ckmsQuantiles.insert(value);
+
+ for (ConcurrentDoubleHistogram bucket : buckets.get()) {
+ bucket.recordValue(value);
}
}
- private CKMSQuantiles rotate() {
- long timeSinceLastRotateMillis = System.currentTimeMillis() - lastRotateTimestampMillis;
- while (timeSinceLastRotateMillis > durationBetweenRotatesMillis) {
- ringBuffer[currentBucket] = new CKMSQuantiles(quantiles);
- if (++currentBucket >= ringBuffer.length) {
- currentBucket = 0;
+ private ConcurrentDoubleHistogram getCurrentBucket() {
+ rotate();
+
+ return buckets.get()[0]; // oldest bucket
+ }
+
+ private void rotate() {
+ // On concurrent `rotate` and `rotate`:
+ // - `currentTime` is cached to reduce thread contention.
+ // - `lastRotate` is used to ensure the correct number of rotations.
+
+ // Correctness is guaranteed by `volatile` memory access ordering and visibility semantics.
+ // Note that it is not possible for other threads to read partially initialized `buckets`.
+ // In other words the `volatile` write to `buckets` propagates preceding `plain` writes to `buckets[i]`.
+ long currentTime = System.nanoTime();
+ long lastRotate = lastRotateTimestampNanos.get();
+ while (currentTime - lastRotate > durationBetweenRotatesNanos) {
+ if (lastRotateTimestampNanos.compareAndSet(lastRotate, lastRotate + durationBetweenRotatesNanos)) {
+ // rotate buckets (atomic)
+ ConcurrentDoubleHistogram[] oldBuckets = buckets.get();
+ int ageBuckets = oldBuckets.length;
+ ConcurrentDoubleHistogram[] newBuckets = new ConcurrentDoubleHistogram[ageBuckets];
+ newBuckets[ageBuckets - 1] = createBucket(); // newest bucket
+ System.arraycopy(oldBuckets, 1, newBuckets, 0, ageBuckets - 1); // older buckets
+ while (!buckets.compareAndSet(oldBuckets, newBuckets)) {
+ oldBuckets = buckets.get();
+ System.arraycopy(oldBuckets, 1, newBuckets, 0, ageBuckets - 1); // older buckets
+ }
}
- timeSinceLastRotateMillis -= durationBetweenRotatesMillis;
- lastRotateTimestampMillis += durationBetweenRotatesMillis;
+ lastRotate = lastRotateTimestampNanos.get();
}
- return ringBuffer[currentBucket];
}
+
}
diff --git a/simpleclient/src/test/java/io/prometheus/client/CounterTest.java b/simpleclient/src/test/java/io/prometheus/client/CounterTest.java
index 16d025f73..6c2805e6a 100644
--- a/simpleclient/src/test/java/io/prometheus/client/CounterTest.java
+++ b/simpleclient/src/test/java/io/prometheus/client/CounterTest.java
@@ -1,11 +1,12 @@
package io.prometheus.client;
-import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
-import org.junit.Test;
-import org.junit.Before;
+
+import static org.junit.Assert.assertEquals;
public class CounterTest {
@@ -38,9 +39,9 @@ public void testIncrement() {
assertEquals(8.0, getValue(), .001);
assertEquals(8.0, noLabels.get(), .001);
}
-
- @Test(expected=IllegalArgumentException.class)
- public void testNegativeIncrementFails() {
+
+ @Test
+ public void testNegativeIncrementSucceeds() {
noLabels.inc(-1);
}
diff --git a/simpleclient/src/test/java/io/prometheus/client/SummaryTest.java b/simpleclient/src/test/java/io/prometheus/client/SummaryTest.java
index 06e1f9d9b..e8f2f85be 100644
--- a/simpleclient/src/test/java/io/prometheus/client/SummaryTest.java
+++ b/simpleclient/src/test/java/io/prometheus/client/SummaryTest.java
@@ -14,28 +14,32 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-
public class SummaryTest {
- CollectorRegistry registry;
- Summary noLabels, labels, labelsAndQuantiles, noLabelsAndQuantiles;
+ private CollectorRegistry registry;
+
+ private Summary noLabels, labels, noLabelsAndQuantiles, labelsAndQuantiles;
@Before
public void setUp() {
registry = new CollectorRegistry();
- noLabels = Summary.build().name("nolabels").help("help").register(registry);
- labels = Summary.build().name("labels").help("help").labelNames("l").register(registry);
+
+ noLabels = Summary.build()
+ .name("no_labels").help("help")
+ .register(registry);
+ labels = Summary.build()
+ .name("labels").help("help")
+ .labelNames("l")
+ .register(registry);
noLabelsAndQuantiles = Summary.build()
- .quantile(0.5, 0.05)
- .quantile(0.9, 0.01)
- .quantile(0.99, 0.001)
- .name("no_labels_and_quantiles").help("help").register(registry);
+ .name("no_labels_and_quantiles").help("help")
+ .quantile(0.5).quantile(0.9).quantile(0.99)
+ .register(registry);
labelsAndQuantiles = Summary.build()
- .quantile(0.5, 0.05)
- .quantile(0.9, 0.01)
- .quantile(0.99, 0.001)
- .labelNames("l")
- .name("labels_and_quantiles").help("help").register(registry);
+ .name("labels_and_quantiles").help("help")
+ .labelNames("l")
+ .quantile(0.5).quantile(0.9).quantile(0.99)
+ .register(registry);
}
@After
@@ -43,87 +47,168 @@ public void tearDown() {
SimpleTimer.defaultTimeProvider = new SimpleTimer.TimeProvider();
}
- private double getCount() {
- return registry.getSampleValue("nolabels_count").doubleValue();
+ private Double getCount() {
+ return registry.getSampleValue("no_labels_count");
+ }
+
+ private Double getSum() {
+ return registry.getSampleValue("no_labels_sum");
+ }
+
+ private Double getMin() {
+ return registry.getSampleValue("no_labels_min");
}
- private double getSum() {
- return registry.getSampleValue("nolabels_sum").doubleValue();
+
+ private Double getMax() {
+ return registry.getSampleValue("no_labels_max");
}
- private double getNoLabelQuantile(double q) {
- return registry.getSampleValue("no_labels_and_quantiles", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(q)}).doubleValue();
+
+ private Double getCount(String labelValue) {
+ return registry.getSampleValue("labels_count", new String[]{"l"}, new String[]{labelValue});
}
- private double getLabeledQuantile(String labelValue, double q) {
- return registry.getSampleValue("labels_and_quantiles", new String[]{"l", "quantile"}, new String[]{labelValue, Collector.doubleToGoString(q)}).doubleValue();
+
+ private Double getSum(String labelValue) {
+ return registry.getSampleValue("labels_sum", new String[]{"l"}, new String[]{labelValue});
+ }
+
+ private Double getMin(String labelValue) {
+ return registry.getSampleValue("labels_min", new String[]{"l"}, new String[]{labelValue});
+ }
+
+ private Double getMax(String labelValue) {
+ return registry.getSampleValue("labels_max", new String[]{"l"}, new String[]{labelValue});
+ }
+
+ private Double getNoLabelsQuantile(double q) {
+ return registry.getSampleValue("no_labels_and_quantiles", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(q)});
+ }
+
+ private Double getLabelsQuantile(double q) {
+ return registry.getSampleValue("labels_and_quantiles", new String[]{"l", "quantile"}, new String[]{"a", Collector.doubleToGoString(q)});
}
@Test
public void testObserve() {
- noLabels.observe(2);
+ noLabels.observe(2.0);
assertEquals(1.0, getCount(), .001);
assertEquals(2.0, getSum(), .001);
- assertEquals(1.0, noLabels.get().count, .001);
- assertEquals(2.0, noLabels.get().sum, .001);
- noLabels.labels().observe(4);
+ assertEquals(null, getMin());
+ assertEquals(null, getMax());
+
+ noLabels.labels().observe(4.0);
assertEquals(2.0, getCount(), .001);
assertEquals(6.0, getSum(), .001);
- assertEquals(2.0, noLabels.get().count, .001);
- assertEquals(6.0, noLabels.get().sum, .001);
+ assertEquals(null, getMin());
+ assertEquals(null, getMax());
}
@Test
public void testQuantiles() {
int nSamples = 1000000; // simulate one million samples
+ double error = .01; // default `numberOfSignificantValueDigits` is `2`
- for (int i=1; i<=nSamples; i++) {
+ for (int i = 1; i <= nSamples; i++) {
// In this test, we observe the numbers from 1 to nSamples,
// because that makes it easy to verify if the quantiles are correct.
- labelsAndQuantiles.labels("a").observe(i);
noLabelsAndQuantiles.observe(i);
+ labelsAndQuantiles.labels("a").observe(i);
}
- assertEquals(getNoLabelQuantile(0.5), 0.5 * nSamples, 0.05 * nSamples);
- assertEquals(getNoLabelQuantile(0.9), 0.9 * nSamples, 0.01 * nSamples);
- assertEquals(getNoLabelQuantile(0.99), 0.99 * nSamples, 0.001 * nSamples);
- assertEquals(getLabeledQuantile("a", 0.5), 0.5 * nSamples, 0.05 * nSamples);
- assertEquals(getLabeledQuantile("a", 0.9), 0.9 * nSamples, 0.01 * nSamples);
- assertEquals(getLabeledQuantile("a", 0.99), 0.99 * nSamples, 0.001 * nSamples);
+ assertEquals((double) nSamples, registry.getSampleValue("no_labels_and_quantiles_count"), .001);
+ assertEquals((1.0 + nSamples) * nSamples / 2.0, registry.getSampleValue("no_labels_and_quantiles_sum"), .001);
+ assertEquals(1.0, registry.getSampleValue("no_labels_and_quantiles_min"), error * 1.0);
+ assertEquals((double) nSamples, registry.getSampleValue("no_labels_and_quantiles_max"), error * nSamples);
+ assertEquals(0.5 * nSamples, getNoLabelsQuantile(0.5), error * nSamples);
+ assertEquals(0.9 * nSamples, getNoLabelsQuantile(0.9), error * nSamples);
+ assertEquals(0.99 * nSamples, getNoLabelsQuantile(0.99), error * nSamples);
+
+ assertEquals((double) nSamples, registry.getSampleValue("labels_and_quantiles_count", new String[]{"l"}, new String[]{"a"}), .001);
+ assertEquals((1.0 + nSamples) * nSamples / 2.0, registry.getSampleValue("labels_and_quantiles_sum", new String[]{"l"}, new String[]{"a"}), .001);
+ assertEquals(1.0, registry.getSampleValue("labels_and_quantiles_min", new String[]{"l"}, new String[]{"a"}), error * 1.0);
+ assertEquals((double) nSamples, registry.getSampleValue("labels_and_quantiles_max", new String[]{"l"}, new String[]{"a"}), error * nSamples);
+ assertEquals(0.5 * nSamples, getLabelsQuantile(0.5), error * nSamples);
+ assertEquals(0.9 * nSamples, getLabelsQuantile(0.9), error * nSamples);
+ assertEquals(0.99 * nSamples, getLabelsQuantile(0.99), error * nSamples);
+ }
+
+ @Test
+ public void testObserveNegative() {
+ noLabels.observe(-2.0);
+ }
+
+ @Test
+ public void testObserveNegativeQuantiles() {
+ noLabelsAndQuantiles.observe(-2.0);
+ }
+
+ @Test
+ public void testError() {
+ for (int n = 1; n <= 5; ++n) {
+ double error = Math.pow(10, -n);
+
+ Summary summary = Summary.build()
+ .name("test_precision_" + n).help("help")
+ .quantile(0.99)
+ .numberOfSignificantValueDigits(n)
+ .register(registry);
+
+ summary.observe(1.0);
+ double val1 = registry.getSampleValue("test_precision_" + n, new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)});
+ assertEquals(1.0, val1, error * 1.0);
+
+ summary.observe(1000.0);
+ double val2 = registry.getSampleValue("test_precision_" + n, new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)});
+ assertEquals(1000.0, val2, error * 1000.0);
+
+ summary.observe(1000000.0);
+ double val3 = registry.getSampleValue("test_precision_" + n, new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)});
+ assertEquals(1000000.0, val3, error * 1000000.0);
+
+ summary.observe(1000000000.0);
+ double val4 = registry.getSampleValue("test_precision_" + n, new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)});
+ assertEquals(1000000000.0, val4, error * 1000000000.0);
+ }
}
@Test
public void testMaxAge() throws InterruptedException {
Summary summary = Summary.build()
- .quantile(0.99, 0.001)
- .maxAgeSeconds(1) // After 1s, all observations will be discarded.
- .ageBuckets(2) // We got 2 buckets, so we discard one bucket every 500ms.
- .name("short_attention_span").help("help").register(registry);
+ .name("short_attention_span").help("help")
+ .quantile(0.99)
+ .maxAgeSeconds(1) // After 1s, all observations will be discarded.
+ .ageBuckets(2) // We got 2 buckets, so we discard one bucket every 500ms.
+ .register(registry);
+
summary.observe(8.0);
- double val = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)}).doubleValue();
- assertEquals(8.0, val, 0.0); // From bucket 1.
+ double val1 = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)});
+ assertEquals(8.0, val1, .001); // From bucket 1.
+
Thread.sleep(600);
- val = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)}).doubleValue();
- assertEquals(8.0, val, 0.0); // From bucket 2.
+ double val2 = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)});
+ assertEquals(8.0, val2, .001); // From bucket 2.
+
Thread.sleep(600);
- val = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)}).doubleValue();
- assertEquals(Double.NaN, val, 0.0); // Bucket 1 again, now it is empty.
+ double val3 = registry.getSampleValue("short_attention_span", new String[]{"quantile"}, new String[]{Collector.doubleToGoString(0.99)});
+ assertEquals(Double.NaN, val3, .001); // From bucket 1 again, but now it is empty.
}
@Test
public void testTimer() {
SimpleTimer.defaultTimeProvider = new SimpleTimer.TimeProvider() {
- long value = (long)(30 * 1e9);
+ long value = (long) (30 * 1e9);
long nanoTime() {
- value += (long)(10 * 1e9);
+ value += (long) (10 * 1e9);
return value;
}
};
- double elapsed = noLabels.time(new Runnable() {
+ double elapsed1 = noLabels.time(new Runnable() {
@Override
public void run() {
- //no op
+ // no op
}
});
- assertEquals(10, elapsed, .001);
+ assertEquals(10, elapsed1, .001);
int result = noLabels.time(new Callable() {
@Override
@@ -134,55 +219,69 @@ public Integer call() {
assertEquals(123, result);
Summary.Timer timer = noLabels.startTimer();
- elapsed = timer.observeDuration();
+ double elapsed2 = timer.observeDuration();
+ assertEquals(10, elapsed2, .001);
+
assertEquals(3, getCount(), .001);
assertEquals(30, getSum(), .001);
- assertEquals(10, elapsed, .001);
}
@Test
- public void noLabelsDefaultZeroValue() {
+ public void testNoLabels() {
assertEquals(0.0, getCount(), .001);
assertEquals(0.0, getSum(), .001);
- }
+ assertEquals(null, getMin());
+ assertEquals(null, getMax());
- private Double getLabelsCount(String labelValue) {
- return registry.getSampleValue("labels_count", new String[]{"l"}, new String[]{labelValue});
- }
- private Double getLabelsSum(String labelValue) {
- return registry.getSampleValue("labels_sum", new String[]{"l"}, new String[]{labelValue});
+ noLabels.observe(2.0);
+ assertEquals(1.0, getCount(), .001);
+ assertEquals(2.0, getSum(), .001);
+ assertEquals(null, getMin());
+ assertEquals(null, getMax());
}
@Test
public void testLabels() {
- assertEquals(null, getLabelsCount("a"));
- assertEquals(null, getLabelsSum("a"));
- assertEquals(null, getLabelsCount("b"));
- assertEquals(null, getLabelsSum("b"));
- labels.labels("a").observe(2);
- assertEquals(1.0, getLabelsCount("a").doubleValue(), .001);
- assertEquals(2.0, getLabelsSum("a").doubleValue(), .001);
- assertEquals(null, getLabelsCount("b"));
- assertEquals(null, getLabelsSum("b"));
- labels.labels("b").observe(3);
- assertEquals(1.0, getLabelsCount("a").doubleValue(), .001);
- assertEquals(2.0, getLabelsSum("a").doubleValue(), .001);
- assertEquals(1.0, getLabelsCount("b").doubleValue(), .001);
- assertEquals(3.0, getLabelsSum("b").doubleValue(), .001);
+ assertEquals(null, getCount("a"));
+ assertEquals(null, getSum("a"));
+ assertEquals(null, getMin("a"));
+ assertEquals(null, getMax("a"));
+ assertEquals(null, getCount("b"));
+ assertEquals(null, getSum("b"));
+ assertEquals(null, getMin("b"));
+ assertEquals(null, getMax("b"));
+
+ labels.labels("a").observe(2.0);
+ assertEquals(1.0, getCount("a"), .001);
+ assertEquals(2.0, getSum("a"), .001);
+ assertEquals(null, getMin("a"));
+ assertEquals(null, getMax("a"));
+ assertEquals(null, getCount("b"));
+ assertEquals(null, getSum("b"));
+ assertEquals(null, getMin("b"));
+ assertEquals(null, getMax("b"));
+
+
+ labels.labels("b").observe(3.0);
+ assertEquals(1.0, getCount("a"), .001);
+ assertEquals(2.0, getSum("a"), .001);
+ assertEquals(null, getMin("a"));
+ assertEquals(null, getMax("a"));
+ assertEquals(1.0, getCount("b"), .001);
+ assertEquals(3.0, getSum("b"), .001);
+ assertEquals(null, getMin("b"));
+ assertEquals(null, getMax("b"));
+
}
@Test
public void testCollect() {
- labels.labels("a").observe(2);
+ labels.labels("a").observe(2.0);
List mfs = labels.collect();
ArrayList samples = new ArrayList();
- ArrayList labelNames = new ArrayList();
- labelNames.add("l");
- ArrayList labelValues = new ArrayList();
- labelValues.add("a");
- samples.add(new Collector.MetricFamilySamples.Sample("labels_count", labelNames, labelValues, 1.0));
- samples.add(new Collector.MetricFamilySamples.Sample("labels_sum", labelNames, labelValues, 2.0));
+ samples.add(new Collector.MetricFamilySamples.Sample("labels_count", asList("l"), asList("a"), 1.0));
+ samples.add(new Collector.MetricFamilySamples.Sample("labels_sum", asList("l"), asList("a"), 2.0));
Collector.MetricFamilySamples mfsFixture = new Collector.MetricFamilySamples("labels", Collector.Type.SUMMARY, "help", samples);
assertEquals(1, mfs.size());
@@ -198,6 +297,8 @@ public void testCollectWithQuantiles() {
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles", asList("l", "quantile"), asList("a", "0.5"), 2.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles", asList("l", "quantile"), asList("a", "0.9"), 2.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles", asList("l", "quantile"), asList("a", "0.99"), 2.0));
+ samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles_min", asList("l"), asList("a"), 2.0));
+ samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles_max", asList("l"), asList("a"), 2.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles_count", asList("l"), asList("a"), 1.0));
samples.add(new Collector.MetricFamilySamples.Sample("labels_and_quantiles_sum", asList("l"), asList("a"), 2.0));
Collector.MetricFamilySamples mfsFixture = new Collector.MetricFamilySamples("labels_and_quantiles", Collector.Type.SUMMARY, "help", samples);
@@ -215,8 +316,11 @@ public void testChildAndValuePublicApi() throws Exception {
assertEquals(Summary.Child.Value.class, getMethod.getReturnType());
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getModifiers()));
+ assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("min").getModifiers()));
+ assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("max").getModifiers()));
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("count").getModifiers()));
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("sum").getModifiers()));
assertTrue(Modifier.isPublic(Summary.Child.Value.class.getField("quantiles").getModifiers()));
}
+
}
diff --git a/simpleclient_caffeine/pom.xml b/simpleclient_caffeine/pom.xml
index b1c1fe15c..839905cbe 100644
--- a/simpleclient_caffeine/pom.xml
+++ b/simpleclient_caffeine/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,7 +37,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
com.github.ben-manes.caffeine
diff --git a/simpleclient_common/pom.xml b/simpleclient_common/pom.xml
index 24ec812c6..78abc76b8 100644
--- a/simpleclient_common/pom.xml
+++ b/simpleclient_common/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,7 +37,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
diff --git a/simpleclient_common/src/test/java/io/prometheus/client/exporter/common/TextFormatTest.java b/simpleclient_common/src/test/java/io/prometheus/client/exporter/common/TextFormatTest.java
index 67a01b38e..5c1527ba6 100644
--- a/simpleclient_common/src/test/java/io/prometheus/client/exporter/common/TextFormatTest.java
+++ b/simpleclient_common/src/test/java/io/prometheus/client/exporter/common/TextFormatTest.java
@@ -104,6 +104,8 @@ public void testSummaryOutputWithQuantiles() throws IOException {
+ "labelsAndQuantiles{l=\"a\",quantile=\"0.5\",} 2.0\n"
+ "labelsAndQuantiles{l=\"a\",quantile=\"0.9\",} 2.0\n"
+ "labelsAndQuantiles{l=\"a\",quantile=\"0.99\",} 2.0\n"
+ + "labelsAndQuantiles_min{l=\"a\",} 2.0\n"
+ + "labelsAndQuantiles_max{l=\"a\",} 2.0\n"
+ "labelsAndQuantiles_count{l=\"a\",} 1.0\n"
+ "labelsAndQuantiles_sum{l=\"a\",} 2.0\n", writer.toString());
}
diff --git a/simpleclient_dropwizard/pom.xml b/simpleclient_dropwizard/pom.xml
index dad5c826d..0ee0bbf3a 100644
--- a/simpleclient_dropwizard/pom.xml
+++ b/simpleclient_dropwizard/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -35,7 +35,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.dropwizard.metrics
diff --git a/simpleclient_graphite_bridge/pom.xml b/simpleclient_graphite_bridge/pom.xml
index 86054441e..355c45a27 100644
--- a/simpleclient_graphite_bridge/pom.xml
+++ b/simpleclient_graphite_bridge/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -38,7 +38,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
diff --git a/simpleclient_guava/pom.xml b/simpleclient_guava/pom.xml
index 26b52d7f9..297fde57b 100644
--- a/simpleclient_guava/pom.xml
+++ b/simpleclient_guava/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,7 +37,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
com.google.guava
diff --git a/simpleclient_hibernate/pom.xml b/simpleclient_hibernate/pom.xml
index f203a7ec9..226a142bc 100644
--- a/simpleclient_hibernate/pom.xml
+++ b/simpleclient_hibernate/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -38,7 +38,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
diff --git a/simpleclient_hotspot/pom.xml b/simpleclient_hotspot/pom.xml
index 542886714..d1df00fc1 100644
--- a/simpleclient_hotspot/pom.xml
+++ b/simpleclient_hotspot/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,14 +37,14 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_servlet
- 0.9.0
+ 0.9.999-evo1
test
diff --git a/simpleclient_httpserver/pom.xml b/simpleclient_httpserver/pom.xml
index 09c769571..adc56c801 100644
--- a/simpleclient_httpserver/pom.xml
+++ b/simpleclient_httpserver/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,12 +37,12 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_common
- 0.9.0
+ 0.9.999-evo1
diff --git a/simpleclient_jetty/pom.xml b/simpleclient_jetty/pom.xml
index 46e5205f8..adaaa4caa 100644
--- a/simpleclient_jetty/pom.xml
+++ b/simpleclient_jetty/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -35,7 +35,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
org.eclipse.jetty
diff --git a/simpleclient_jetty_jdk8/pom.xml b/simpleclient_jetty_jdk8/pom.xml
index 9a812b0b4..126d52759 100644
--- a/simpleclient_jetty_jdk8/pom.xml
+++ b/simpleclient_jetty_jdk8/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -48,7 +48,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
org.eclipse.jetty
diff --git a/simpleclient_log4j/pom.xml b/simpleclient_log4j/pom.xml
index 39a8409cb..7376c6ca4 100644
--- a/simpleclient_log4j/pom.xml
+++ b/simpleclient_log4j/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,7 +37,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
log4j
diff --git a/simpleclient_log4j2/pom.xml b/simpleclient_log4j2/pom.xml
index 3fb05cf02..559dbdc80 100644
--- a/simpleclient_log4j2/pom.xml
+++ b/simpleclient_log4j2/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,7 +37,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
org.apache.logging.log4j
diff --git a/simpleclient_logback/pom.xml b/simpleclient_logback/pom.xml
index d451cd14b..4272523af 100644
--- a/simpleclient_logback/pom.xml
+++ b/simpleclient_logback/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -37,7 +37,7 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
ch.qos.logback
diff --git a/simpleclient_pushgateway/pom.xml b/simpleclient_pushgateway/pom.xml
index 1d3b98d7f..f67522acb 100644
--- a/simpleclient_pushgateway/pom.xml
+++ b/simpleclient_pushgateway/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -38,12 +38,12 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_common
- 0.9.0
+ 0.9.999-evo1
javax.xml.bind
diff --git a/simpleclient_servlet/pom.xml b/simpleclient_servlet/pom.xml
index d3d5c869e..f8f31bd22 100644
--- a/simpleclient_servlet/pom.xml
+++ b/simpleclient_servlet/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -41,12 +41,12 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_common
- 0.9.0
+ 0.9.999-evo1
javax.servlet
diff --git a/simpleclient_spring_boot/pom.xml b/simpleclient_spring_boot/pom.xml
index f2ae28981..e40c2c22f 100644
--- a/simpleclient_spring_boot/pom.xml
+++ b/simpleclient_spring_boot/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -52,17 +52,17 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_common
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_spring_web
- 0.9.0
+ 0.9.999-evo1
org.springframework.boot
diff --git a/simpleclient_spring_web/pom.xml b/simpleclient_spring_web/pom.xml
index 3d7f43f5a..2fee5daa2 100644
--- a/simpleclient_spring_web/pom.xml
+++ b/simpleclient_spring_web/pom.xml
@@ -5,7 +5,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
simpleclient_spring_web
@@ -51,12 +51,12 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_common
- 0.9.0
+ 0.9.999-evo1
org.springframework
diff --git a/simpleclient_vertx/pom.xml b/simpleclient_vertx/pom.xml
index 4dcae53a2..b40d6c88a 100644
--- a/simpleclient_vertx/pom.xml
+++ b/simpleclient_vertx/pom.xml
@@ -17,7 +17,7 @@
io.prometheus
parent
- 0.9.0
+ 0.9.999-evo1
io.prometheus
@@ -53,12 +53,12 @@
io.prometheus
simpleclient
- 0.9.0
+ 0.9.999-evo1
io.prometheus
simpleclient_common
- 0.9.0
+ 0.9.999-evo1
io.vertx