Skip to content

Commit

Permalink
integration of "top" into metrics-core + unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimir-bukhtoyarov committed Nov 7, 2016
1 parent 507f787 commit 485b787
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 0 deletions.
99 changes: 99 additions & 0 deletions src/main/java/com/github/metricscore/hdr/top/TopMetricSet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
*
* Copyright 2016 Vladimir Bukhtoyarov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.metricscore.hdr.top;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricSet;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class TopMetricSet implements MetricSet {

private final BigDecimal zero;
private final Map<String, Metric> gauges;

public TopMetricSet(String name, Top top, TimeUnit latencyUnit, int digitsAfterDecimalPoint) {
if (name == null) {
throw new IllegalArgumentException("name should not be null");
}
if (name.isEmpty()) {
throw new IllegalArgumentException("name should not be empty");
}
if (top == null) {
throw new IllegalArgumentException("top should not be null");
}
if (latencyUnit == null) {
throw new IllegalArgumentException("latencyUnit should not be null");
}
if (digitsAfterDecimalPoint < 0) {
throw new IllegalArgumentException("digitsAfterDecimalPoint should not be negative");
}

gauges = new HashMap<>();
gauges.put(name + ".latencyUnit", (Gauge<String>) latencyUnit::toString);

zero = BigDecimal.ZERO.setScale(digitsAfterDecimalPoint, RoundingMode.CEILING);

int size = top.getSize();
for (int i = 0; i < size; i++) {
String latencyName = name + "." + i + "." + "latency";
Gauge<BigDecimal> latencyGauge = createLatencyGauge(i, top, latencyUnit, digitsAfterDecimalPoint);
gauges.put(latencyName, latencyGauge);

String descriptionName = name + "." + i + "." + "description";
Gauge<String> descriptionGauge = createDescriptionGauge(i, top);
gauges.put(descriptionName, descriptionGauge);
}
}

@Override
public Map<String, Metric> getMetrics() {
return gauges;
}

private Gauge<BigDecimal> createLatencyGauge(int i, Top top, TimeUnit latencyUnit, int digitsAfterDecimalPoint) {
return () -> {
List<Position> positions = top.getPositionsInDescendingOrder();
if (positions.size() <= i) {
return zero;
}
double latencyNanos = positions.get(i).getLatencyInNanoseconds();
long scale = latencyUnit.toNanos(1);
double result = latencyNanos/scale;

return new BigDecimal(result).setScale(digitsAfterDecimalPoint, RoundingMode.CEILING);
};
}

private Gauge<String> createDescriptionGauge(int i, Top top) {
return () -> {
List<Position> positions = top.getPositionsInDescendingOrder();
if (positions.size() <= i) {
return "";
}
return positions.get(i).getQueryDescription();
};
}

}
125 changes: 125 additions & 0 deletions src/test/java/com/github/metricscore/hdr/top/TopMetricSetTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
*
* Copyright 2016 Vladimir Bukhtoyarov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.github.metricscore.hdr.top;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import org.junit.Test;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.github.metricscore.hdr.top.TestData.first;
import static com.github.metricscore.hdr.top.TestData.second;
import static com.github.metricscore.hdr.top.TestData.third;
import static com.github.metricscore.hdr.top.impl.TopTestUtil.update;
import static org.junit.Assert.*;

public class TopMetricSetTest {

private Top top = Top.builder(3).withSnapshotCachingDuration(Duration.ZERO).build();

@Test(expected = IllegalArgumentException.class)
public void shouldDisallowNullName() {
new TopMetricSet(null, top, TimeUnit.MILLISECONDS, 3);
}

@Test(expected = IllegalArgumentException.class)
public void shouldDisallowEmptyName() {
new TopMetricSet("", top, TimeUnit.MILLISECONDS, 3);
}

@Test(expected = IllegalArgumentException.class)
public void shouldDisallowNullTop() {
new TopMetricSet("my-top", null, TimeUnit.MILLISECONDS, 3);
}

@Test(expected = IllegalArgumentException.class)
public void shouldDisallowNullLatencyUnit() {
new TopMetricSet("my-top", top, null, 3);
}

@Test(expected = IllegalArgumentException.class)
public void shouldDisallowNegativeDigitsAfterDecimalPoint() {
new TopMetricSet("my-top", top, TimeUnit.MILLISECONDS, -1);
}

@Test
public void shouldAddLatencyUnitGauge() {
for (TimeUnit timeUnit: TimeUnit.values()) {
TopMetricSet metricSet = new TopMetricSet("my-top", top, timeUnit, 3);
Map<String, Metric> metrics = metricSet.getMetrics();
Gauge<String> timeUnitGauge = (Gauge<String>) metrics.get("my-top.latencyUnit");
assertNotNull(timeUnitGauge);
assertEquals(timeUnit.toString(), timeUnitGauge.getValue());
}
}

@Test
public void testDescriptionGauges() {
TopMetricSet metricSet = new TopMetricSet("my-top", top, TimeUnit.MILLISECONDS, 3);
checkDescriptions(metricSet, "my-top", "", "", "");

update(top, first);
checkDescriptions(metricSet, "my-top", first.getQueryDescription(), "", "");

update(top, second);
checkDescriptions(metricSet, "my-top", second.getQueryDescription(), first.getQueryDescription(), "");

update(top, third);
checkDescriptions(metricSet, "my-top", third.getQueryDescription(), second.getQueryDescription(), first.getQueryDescription());
}

@Test
public void testValueGauges() {
TopMetricSet metricSet = new TopMetricSet("my-top", top, TimeUnit.MILLISECONDS, 3);
checkValues(metricSet, "my-top", 3, 0.0d, 0.0d, 0.0d);

top.update(0, 13_345_456, TimeUnit.NANOSECONDS, () -> "SELECT * FROM USERS");
checkValues(metricSet, "my-top", 3, 13.345d, 0.0d, 0.0d);


top.update(0, 11_666_957, TimeUnit.NANOSECONDS, () -> "SELECT * FROM USERS");
checkValues(metricSet, "my-top", 3, 13.345d, 11.666d, 0.0d);

top.update(0, 2_004_123, TimeUnit.NANOSECONDS, () -> "SELECT * FROM DUAL");
checkValues(metricSet, "my-top", 3, 13.345d, 11.666d, 2.004d);
}

private void checkDescriptions(TopMetricSet metricSet, String name, String... requiredDescriptions) {
for (int i = 0; i < requiredDescriptions.length; i++) {
String requiredDescription = requiredDescriptions[i];
Gauge<String> gauge = (Gauge<String>) metricSet.getMetrics().get(name + "." + i + ".description");
String description = gauge.getValue();
assertEquals(requiredDescription, description);
}
}

private void checkValues(TopMetricSet metricSet, String name, int digitsAfterDecimalPoint, double... requiredLatencies) {
for (int i = 0; i < requiredLatencies.length; i++) {
BigDecimal requiredLatency = new BigDecimal(requiredLatencies[i]).setScale(digitsAfterDecimalPoint, RoundingMode.CEILING);
Gauge<BigDecimal> gauge = (Gauge<BigDecimal>) metricSet.getMetrics().get(name + "." + i + ".latency");
BigDecimal latency = gauge.getValue();
assertEquals(requiredLatency, latency);
}
}

}

0 comments on commit 485b787

Please sign in to comment.