Support arbitrary MetricCategories (#1550)

* Make MetricCategory an interface so it isn't locked into the pantheon specific categories.
 * Split categories into StandardMetricCategory and PanteonMetricCategory to separate the common and Pantheon specific categories.
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Adrian Sutton 6 years ago committed by GitHub
parent f2a2ffc008
commit 9b509d1163
  1. 2
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
  2. 3
      metrics/core/build.gradle
  3. 22
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java
  4. 21
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/MetricsSystem.java
  5. 6
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/Observation.java
  6. 33
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/PantheonMetricCategory.java
  7. 36
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/StandardMetricCategory.java
  8. 10
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java
  9. 12
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/prometheus/MetricsConfiguration.java
  10. 15
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/prometheus/MetricsHttpService.java
  11. 4
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/prometheus/MetricsPushGatewayService.java
  12. 85
      metrics/core/src/main/java/tech/pegasys/pantheon/metrics/prometheus/PrometheusMetricsSystem.java
  13. 13
      metrics/core/src/test-support/java/tech/pegasys/pantheon/metrics/StubMetricsSystem.java
  14. 10
      metrics/core/src/test/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystemTest.java
  15. 6
      metrics/core/src/test/java/tech/pegasys/pantheon/metrics/prometheus/MetricsHttpServiceTest.java
  16. 12
      metrics/core/src/test/java/tech/pegasys/pantheon/metrics/prometheus/PrometheusMetricsSystemTest.java
  17. 3
      metrics/rocksdb/src/main/java/tech/pegasys/pantheon/metrics/rocksdb/RocksDBStats.java
  18. 10
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
  19. 40
      pantheon/src/main/java/tech/pegasys/pantheon/cli/converter/MetricCategoryConverter.java
  20. 6
      pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java

@ -257,7 +257,7 @@ public class JsonRpcHttpServiceRpcApisTest {
}
private MetricsConfiguration createMetricsConfiguration() {
return MetricsConfiguration.builder().enabled(true).build();
return MetricsConfiguration.builder().enabled(true).port(0).build();
}
private JsonRpcHttpService createJsonRpcHttpService(

@ -26,8 +26,6 @@ jar {
}
dependencies {
implementation project(':util')
implementation 'com.google.guava:guava'
implementation 'io.prometheus:simpleclient'
implementation 'io.prometheus:simpleclient_common'
@ -40,6 +38,7 @@ dependencies {
runtime 'org.apache.logging.log4j:log4j-core'
// test dependencies.
testImplementation project(':util')
testImplementation 'junit:junit'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core'

@ -0,0 +1,22 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.metrics;
import java.util.Optional;
public interface MetricCategory {
String getName();
Optional<String> getAppliationPrefix();
}

@ -20,26 +20,25 @@ import java.util.stream.Stream;
public interface MetricsSystem {
default Counter createCounter(
final PantheonMetricCategory category, final String name, final String help) {
final MetricCategory category, final String name, final String help) {
return createLabelledCounter(category, name, help, new String[0]).labels();
}
LabelledMetric<Counter> createLabelledCounter(
PantheonMetricCategory category, String name, String help, String... labelNames);
MetricCategory category, String name, String help, String... labelNames);
default OperationTimer createTimer(
final PantheonMetricCategory category, final String name, final String help) {
final MetricCategory category, final String name, final String help) {
return createLabelledTimer(category, name, help, new String[0]).labels();
}
LabelledMetric<OperationTimer> createLabelledTimer(
PantheonMetricCategory category, String name, String help, String... labelNames);
MetricCategory category, String name, String help, String... labelNames);
void createGauge(
PantheonMetricCategory category, String name, String help, DoubleSupplier valueSupplier);
void createGauge(MetricCategory category, String name, String help, DoubleSupplier valueSupplier);
default void createIntegerGauge(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final IntSupplier valueSupplier) {
@ -47,16 +46,14 @@ public interface MetricsSystem {
}
default void createLongGauge(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final LongSupplier valueSupplier) {
createGauge(category, name, help, () -> (double) valueSupplier.getAsLong());
}
Stream<Observation> streamObservations(PantheonMetricCategory category);
Stream<Observation> streamObservations(MetricCategory category);
default Stream<Observation> streamObservations() {
return Stream.of(PantheonMetricCategory.values()).flatMap(this::streamObservations);
}
Stream<Observation> streamObservations();
}

@ -18,13 +18,13 @@ import java.util.Objects;
import com.google.common.base.MoreObjects;
public class Observation {
private final PantheonMetricCategory category;
private final MetricCategory category;
private final String metricName;
private final List<String> labels;
private final Object value;
public Observation(
final PantheonMetricCategory category,
final MetricCategory category,
final String metricName,
final Object value,
final List<String> labels) {
@ -34,7 +34,7 @@ public class Observation {
this.labels = labels;
}
public PantheonMetricCategory getCategory() {
public MetricCategory getCategory() {
return category;
}

@ -1,5 +1,5 @@
/*
* Copyright 2018 ConsenSys AG.
* Copyright 2019 ConsenSys AG.
*
* 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
@ -13,16 +13,16 @@
package tech.pegasys.pantheon.metrics;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
public enum PantheonMetricCategory {
BIG_QUEUE("big_queue"),
import com.google.common.collect.ImmutableSet;
public enum PantheonMetricCategory implements MetricCategory {
BLOCKCHAIN("blockchain"),
EXECUTORS("executors"),
JVM("jvm", false),
NETWORK("network"),
PEERS("peers"),
PROCESS("process", false),
PERMISSIONING("permissioning"),
KVSTORE_ROCKSDB("rocksdb"),
KVSTORE_ROCKSDB_STATS("rocksdb", false),
@ -30,9 +30,20 @@ public enum PantheonMetricCategory {
SYNCHRONIZER("synchronizer"),
TRANSACTION_POOL("transaction_pool");
// Why not BIG_QUEUE and ROCKSDB? They hurt performance under load.
public static final Set<PantheonMetricCategory> DEFAULT_METRIC_CATEGORIES =
EnumSet.complementOf(EnumSet.of(BIG_QUEUE, KVSTORE_ROCKSDB, KVSTORE_ROCKSDB_STATS));
private static final Optional<String> PANTHEON_PREFIX = Optional.of("pantheon_");
public static final Set<MetricCategory> DEFAULT_METRIC_CATEGORIES;
static {
// Why not ROCKSDB and KVSTORE_ROCKSDB_STATS? They hurt performance under load.
final EnumSet<PantheonMetricCategory> pantheonCategories =
EnumSet.complementOf(EnumSet.of(KVSTORE_ROCKSDB, KVSTORE_ROCKSDB_STATS));
DEFAULT_METRIC_CATEGORIES =
ImmutableSet.<MetricCategory>builder()
.addAll(pantheonCategories)
.addAll(EnumSet.allOf(StandardMetricCategory.class))
.build();
}
private final String name;
private final boolean pantheonSpecific;
@ -46,11 +57,13 @@ public enum PantheonMetricCategory {
this.pantheonSpecific = pantheonSpecific;
}
@Override
public String getName() {
return name;
}
public boolean isPantheonSpecific() {
return pantheonSpecific;
@Override
public Optional<String> getAppliationPrefix() {
return pantheonSpecific ? PANTHEON_PREFIX : Optional.empty();
}
}

@ -0,0 +1,36 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.metrics;
import java.util.Optional;
public enum StandardMetricCategory implements MetricCategory {
JVM("jvm"),
PROCESS("process");
private final String name;
StandardMetricCategory(final String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public Optional<String> getAppliationPrefix() {
return Optional.empty();
}
}

@ -14,11 +14,11 @@ package tech.pegasys.pantheon.metrics.noop;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.LabelledMetric;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.Observation;
import tech.pegasys.pantheon.metrics.OperationTimer;
import tech.pegasys.pantheon.metrics.OperationTimer.TimingContext;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import java.util.function.DoubleSupplier;
import java.util.stream.Stream;
@ -42,7 +42,7 @@ public class NoOpMetricsSystem implements MetricsSystem {
@Override
public LabelledMetric<Counter> createLabelledCounter(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final String... labelNames) {
@ -64,7 +64,7 @@ public class NoOpMetricsSystem implements MetricsSystem {
@Override
public LabelledMetric<OperationTimer> createLabelledTimer(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final String... labelNames) {
@ -82,13 +82,13 @@ public class NoOpMetricsSystem implements MetricsSystem {
@Override
public void createGauge(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final DoubleSupplier valueSupplier) {}
@Override
public Stream<Observation> streamObservations(final PantheonMetricCategory category) {
public Stream<Observation> streamObservations(final MetricCategory category) {
return Stream.empty();
}

@ -14,7 +14,7 @@ package tech.pegasys.pantheon.metrics.prometheus;
import static tech.pegasys.pantheon.metrics.PantheonMetricCategory.DEFAULT_METRIC_CATEGORIES;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import tech.pegasys.pantheon.metrics.MetricCategory;
import java.util.Arrays;
import java.util.Collection;
@ -35,7 +35,7 @@ public class MetricsConfiguration {
private final boolean enabled;
private final int port;
private final String host;
private final Set<PantheonMetricCategory> metricCategories;
private final Set<MetricCategory> metricCategories;
private final boolean pushEnabled;
private final int pushPort;
private final String pushHost;
@ -51,7 +51,7 @@ public class MetricsConfiguration {
final boolean enabled,
final int port,
final String host,
final Set<PantheonMetricCategory> metricCategories,
final Set<MetricCategory> metricCategories,
final boolean pushEnabled,
final int pushPort,
final String pushHost,
@ -82,7 +82,7 @@ public class MetricsConfiguration {
return host;
}
public Set<PantheonMetricCategory> getMetricCategories() {
public Set<MetricCategory> getMetricCategories() {
return metricCategories;
}
@ -166,7 +166,7 @@ public class MetricsConfiguration {
private boolean enabled = false;
private int port = DEFAULT_METRICS_PORT;
private String host = DEFAULT_METRICS_HOST;
private Set<PantheonMetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
private Set<MetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
private boolean pushEnabled = false;
private int pushPort = DEFAULT_METRICS_PUSH_PORT;
private String pushHost = DEFAULT_METRICS_PUSH_HOST;
@ -191,7 +191,7 @@ public class MetricsConfiguration {
return this;
}
public Builder metricCategories(final Set<PantheonMetricCategory> metricCategories) {
public Builder metricCategories(final Set<MetricCategory> metricCategories) {
this.metricCategories = metricCategories;
return this;
}

@ -14,10 +14,8 @@ package tech.pegasys.pantheon.metrics.prometheus;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Streams.stream;
import static tech.pegasys.pantheon.util.NetworkUtility.urlForSocketAddress;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.NetworkUtility;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -30,7 +28,6 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import io.netty.handler.codec.http.HttpResponseStatus;
@ -68,9 +65,7 @@ class MetricsHttpService implements MetricsService {
}
private void validateConfig(final MetricsConfiguration config) {
checkArgument(
config.getPort() == 0 || NetworkUtility.isValidPort(config.getPort()),
"Invalid port configuration.");
checkArgument(config.getPort() >= 0 && config.getPort() < 65535, "Invalid port configuration.");
checkArgument(config.getHost() != null, "Required host is not configured.");
checkArgument(
!(config.isEnabled() && config.isPushEnabled()),
@ -232,14 +227,6 @@ class MetricsHttpService implements MetricsService {
return Optional.of(httpServer.actualPort());
}
@VisibleForTesting
public String url() {
if (httpServer == null) {
return "";
}
return urlForSocketAddress("http", socketAddress());
}
// Facilitate remote health-checks in AWS, inter alia.
private void handleEmptyRequest(final RoutingContext routingContext) {
routingContext.response().setStatusCode(201).end();

@ -15,7 +15,6 @@ package tech.pegasys.pantheon.metrics.prometheus;
import static com.google.common.base.Preconditions.checkArgument;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.NetworkUtility;
import java.io.IOException;
import java.util.Optional;
@ -45,8 +44,7 @@ class MetricsPushGatewayService implements MetricsService {
private void validateConfig(final MetricsConfiguration config) {
checkArgument(
config.getPushPort() == 0 || NetworkUtility.isValidPort(config.getPushPort()),
"Invalid port configuration.");
config.getPushPort() >= 0 && config.getPushPort() < 65536, "Invalid port configuration.");
checkArgument(config.getPushHost() != null, "Required host is not configured.");
checkArgument(
!(config.isEnabled() && config.isPushEnabled()),

@ -16,22 +16,24 @@ import static java.util.Arrays.asList;
import static java.util.Collections.singleton;
import tech.pegasys.pantheon.metrics.LabelledMetric;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.Observation;
import tech.pegasys.pantheon.metrics.OperationTimer;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import tech.pegasys.pantheon.metrics.StandardMetricCategory;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.DoubleSupplier;
import java.util.stream.Stream;
import com.google.common.collect.ImmutableSet;
import io.prometheus.client.Collector;
import io.prometheus.client.Collector.MetricFamilySamples;
import io.prometheus.client.Collector.MetricFamilySamples.Sample;
@ -48,34 +50,33 @@ import io.prometheus.client.hotspot.ThreadExports;
public class PrometheusMetricsSystem implements MetricsSystem {
private static final String PANTHEON_PREFIX = "pantheon_";
private final Map<PantheonMetricCategory, Collection<Collector>> collectors =
new ConcurrentHashMap<>();
private final Map<MetricCategory, Collection<Collector>> collectors = new ConcurrentHashMap<>();
private final CollectorRegistry registry = new CollectorRegistry(true);
private final Map<String, LabelledMetric<tech.pegasys.pantheon.metrics.Counter>> cachedCounters =
new ConcurrentHashMap<>();
private final Map<String, LabelledMetric<tech.pegasys.pantheon.metrics.OperationTimer>>
cachedTimers = new ConcurrentHashMap<>();
private final EnumSet<PantheonMetricCategory> enabledCategories =
EnumSet.allOf(PantheonMetricCategory.class);
private final Set<MetricCategory> enabledCategories;
PrometheusMetricsSystem() {}
PrometheusMetricsSystem(final Set<MetricCategory> enabledCategories) {
this.enabledCategories = ImmutableSet.copyOf(enabledCategories);
}
public static MetricsSystem init(final MetricsConfiguration metricsConfiguration) {
if (!metricsConfiguration.isEnabled() && !metricsConfiguration.isPushEnabled()) {
return new NoOpMetricsSystem();
}
final PrometheusMetricsSystem metricsSystem = new PrometheusMetricsSystem();
metricsSystem.enabledCategories.retainAll(metricsConfiguration.getMetricCategories());
if (metricsSystem.enabledCategories.contains(PantheonMetricCategory.PROCESS)) {
final PrometheusMetricsSystem metricsSystem =
new PrometheusMetricsSystem(metricsConfiguration.getMetricCategories());
if (metricsSystem.isCategoryEnabled(StandardMetricCategory.PROCESS)) {
metricsSystem.collectors.put(
PantheonMetricCategory.PROCESS,
StandardMetricCategory.PROCESS,
singleton(new StandardExports().register(metricsSystem.registry)));
}
if (metricsSystem.enabledCategories.contains(PantheonMetricCategory.JVM)) {
if (metricsSystem.isCategoryEnabled(StandardMetricCategory.JVM)) {
metricsSystem.collectors.put(
PantheonMetricCategory.JVM,
StandardMetricCategory.JVM,
asList(
new MemoryPoolsExports().register(metricsSystem.registry),
new BufferPoolsExports().register(metricsSystem.registry),
@ -88,7 +89,7 @@ public class PrometheusMetricsSystem implements MetricsSystem {
@Override
public LabelledMetric<tech.pegasys.pantheon.metrics.Counter> createLabelledCounter(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final String... labelNames) {
@ -96,7 +97,7 @@ public class PrometheusMetricsSystem implements MetricsSystem {
return cachedCounters.computeIfAbsent(
metricName,
(k) -> {
if (enabledCategories.contains(category)) {
if (isCategoryEnabled(category)) {
final Counter counter = Counter.build(metricName, help).labelNames(labelNames).create();
addCollectorUnchecked(category, counter);
return new PrometheusCounter(counter);
@ -108,7 +109,7 @@ public class PrometheusMetricsSystem implements MetricsSystem {
@Override
public LabelledMetric<OperationTimer> createLabelledTimer(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final String... labelNames) {
@ -116,7 +117,7 @@ public class PrometheusMetricsSystem implements MetricsSystem {
return cachedTimers.computeIfAbsent(
metricName,
(k) -> {
if (enabledCategories.contains(category)) {
if (isCategoryEnabled(category)) {
final Summary summary =
Summary.build(metricName, help)
.quantile(0.2, 0.02)
@ -137,25 +138,28 @@ public class PrometheusMetricsSystem implements MetricsSystem {
@Override
public void createGauge(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final DoubleSupplier valueSupplier) {
final String metricName = convertToPrometheusName(category, name);
if (enabledCategories.contains(category)) {
if (isCategoryEnabled(category)) {
final Collector collector = new CurrentValueCollector(metricName, help, valueSupplier);
addCollectorUnchecked(category, collector);
}
}
public void addCollector(final PantheonMetricCategory category, final Collector metric) {
if (enabledCategories.contains(category)) {
private boolean isCategoryEnabled(final MetricCategory category) {
return enabledCategories.contains(category);
}
public void addCollector(final MetricCategory category, final Collector metric) {
if (isCategoryEnabled(category)) {
addCollectorUnchecked(category, metric);
}
}
private void addCollectorUnchecked(
final PantheonMetricCategory category, final Collector metric) {
private void addCollectorUnchecked(final MetricCategory category, final Collector metric) {
metric.register(registry);
collectors
.computeIfAbsent(category, key -> Collections.newSetFromMap(new ConcurrentHashMap<>()))
@ -163,22 +167,25 @@ public class PrometheusMetricsSystem implements MetricsSystem {
}
@Override
public Stream<Observation> streamObservations(final PantheonMetricCategory category) {
public Stream<Observation> streamObservations(final MetricCategory category) {
return collectors.getOrDefault(category, Collections.emptySet()).stream()
.flatMap(collector -> collector.collect().stream())
.flatMap(familySamples -> convertSamplesToObservations(category, familySamples));
}
@Override
public Stream<Observation> streamObservations() {
return collectors.keySet().stream().flatMap(this::streamObservations);
}
private Stream<Observation> convertSamplesToObservations(
final PantheonMetricCategory category, final MetricFamilySamples familySamples) {
final MetricCategory category, final MetricFamilySamples familySamples) {
return familySamples.samples.stream()
.map(sample -> createObservationFromSample(category, sample, familySamples));
}
private Observation createObservationFromSample(
final PantheonMetricCategory category,
final Sample sample,
final MetricFamilySamples familySamples) {
final MetricCategory category, final Sample sample, final MetricFamilySamples familySamples) {
if (familySamples.type == Type.HISTOGRAM) {
return convertHistogramSampleNamesToLabels(category, sample, familySamples);
}
@ -193,9 +200,7 @@ public class PrometheusMetricsSystem implements MetricsSystem {
}
private Observation convertHistogramSampleNamesToLabels(
final PantheonMetricCategory category,
final Sample sample,
final MetricFamilySamples familySamples) {
final MetricCategory category, final Sample sample, final MetricFamilySamples familySamples) {
final List<String> labelValues = new ArrayList<>(sample.labelValues);
if (sample.name.endsWith("_bucket")) {
labelValues.add(labelValues.size() - 1, "bucket");
@ -210,9 +215,7 @@ public class PrometheusMetricsSystem implements MetricsSystem {
}
private Observation convertSummarySampleNamesToLabels(
final PantheonMetricCategory category,
final Sample sample,
final MetricFamilySamples familySamples) {
final MetricCategory category, final Sample sample, final MetricFamilySamples familySamples) {
final List<String> labelValues = new ArrayList<>(sample.labelValues);
if (sample.name.endsWith("_sum")) {
labelValues.add("sum");
@ -228,21 +231,17 @@ public class PrometheusMetricsSystem implements MetricsSystem {
labelValues);
}
public static String convertToPrometheusName(
final PantheonMetricCategory category, final String name) {
public String convertToPrometheusName(final MetricCategory category, final String name) {
return prometheusPrefix(category) + name;
}
private String convertFromPrometheusName(
final PantheonMetricCategory category, final String metricName) {
private String convertFromPrometheusName(final MetricCategory category, final String metricName) {
final String prefix = prometheusPrefix(category);
return metricName.startsWith(prefix) ? metricName.substring(prefix.length()) : metricName;
}
private static String prometheusPrefix(final PantheonMetricCategory category) {
return category.isPantheonSpecific()
? PANTHEON_PREFIX + category.getName() + "_"
: category.getName() + "_";
private String prometheusPrefix(final MetricCategory category) {
return category.getAppliationPrefix().orElse("") + category.getName() + "_";
}
CollectorRegistry getRegistry() {

@ -29,7 +29,7 @@ public class StubMetricsSystem implements MetricsSystem {
@Override
public LabelledMetric<Counter> createLabelledCounter(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final String... labelNames) {
@ -50,7 +50,7 @@ public class StubMetricsSystem implements MetricsSystem {
@Override
public LabelledMetric<OperationTimer> createLabelledTimer(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final String... labelNames) {
@ -59,7 +59,7 @@ public class StubMetricsSystem implements MetricsSystem {
@Override
public void createGauge(
final PantheonMetricCategory category,
final MetricCategory category,
final String name,
final String help,
final DoubleSupplier valueSupplier) {
@ -75,7 +75,12 @@ public class StubMetricsSystem implements MetricsSystem {
}
@Override
public Stream<Observation> streamObservations(final PantheonMetricCategory category) {
public Stream<Observation> streamObservations(final MetricCategory category) {
throw new UnsupportedOperationException("Observations aren't actually recorded");
}
@Override
public Stream<Observation> streamObservations() {
throw new UnsupportedOperationException("Observations aren't actually recorded");
}

@ -19,7 +19,7 @@ import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.LabelledMetric;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.OperationTimer;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import tech.pegasys.pantheon.metrics.StandardMetricCategory;
import org.junit.Test;
@ -31,7 +31,7 @@ public class NoOpMetricsSystemTest {
public void labelCountsMatchOnCounter() {
final LabelledMetric<Counter> labeledCounter =
metricsSystem.createLabelledCounter(
PantheonMetricCategory.PROCESS, "name", "help", "label1");
StandardMetricCategory.PROCESS, "name", "help", "label1");
assertThat(labeledCounter.labels("one")).isSameAs(NoOpMetricsSystem.NO_OP_COUNTER);
}
@ -39,7 +39,7 @@ public class NoOpMetricsSystemTest {
public void failsWheLabelCountsDoNotMatchOnCounter() {
final LabelledMetric<Counter> labeledCounter =
metricsSystem.createLabelledCounter(
PantheonMetricCategory.PROCESS, "name", "help", "label1", "label2");
StandardMetricCategory.PROCESS, "name", "help", "label1", "label2");
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> labeledCounter.labels("one"))
@ -52,7 +52,7 @@ public class NoOpMetricsSystemTest {
@Test
public void labelCountsMatchOnTimer() {
final LabelledMetric<OperationTimer> labeledTimer =
metricsSystem.createLabelledTimer(PantheonMetricCategory.PROCESS, "name", "help", "label1");
metricsSystem.createLabelledTimer(StandardMetricCategory.PROCESS, "name", "help", "label1");
assertThat(labeledTimer.labels("one")).isSameAs(NoOpMetricsSystem.NO_OP_OPERATION_TIMER);
}
@ -60,7 +60,7 @@ public class NoOpMetricsSystemTest {
public void failsWheLabelCountsDoNotMatchOnTimer() {
final LabelledMetric<OperationTimer> labeledTimer =
metricsSystem.createLabelledTimer(
PantheonMetricCategory.PROCESS, "name", "help", "label1", "label2");
StandardMetricCategory.PROCESS, "name", "help", "label1", "label2");
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> labeledTimer.labels("one"))

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.metrics.prometheus;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static tech.pegasys.pantheon.util.NetworkUtility.urlForSocketAddress;
import java.net.InetSocketAddress;
import java.util.Properties;
@ -45,7 +46,7 @@ public class MetricsHttpServiceTest {
// Build an OkHttp client.
client = new OkHttpClient();
baseUrl = service.url();
baseUrl = urlForSocketAddress("http", service.socketAddress());
}
private static MetricsHttpService createMetricsHttpService(final MetricsConfiguration config) {
@ -108,7 +109,7 @@ public class MetricsHttpServiceTest {
final InetSocketAddress socketAddress = service.socketAddress();
assertThat("0.0.0.0").isEqualTo(socketAddress.getAddress().getHostAddress());
assertThat(0).isEqualTo(socketAddress.getPort());
assertThat("").isEqualTo(service.url());
assertThat(new InetSocketAddress("0.0.0.0", 0)).isEqualTo(service.socketAddress());
}
@Test
@ -121,7 +122,6 @@ public class MetricsHttpServiceTest {
final InetSocketAddress socketAddress = service.socketAddress();
assertThat("0.0.0.0").isEqualTo(socketAddress.getAddress().getHostAddress());
assertThat(socketAddress.getPort() > 0).isTrue();
assertThat(!service.url().contains("0.0.0.0")).isTrue();
} finally {
service.stop().join();
}

@ -17,10 +17,11 @@ import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static tech.pegasys.pantheon.metrics.PantheonMetricCategory.JVM;
import static tech.pegasys.pantheon.metrics.PantheonMetricCategory.DEFAULT_METRIC_CATEGORIES;
import static tech.pegasys.pantheon.metrics.PantheonMetricCategory.NETWORK;
import static tech.pegasys.pantheon.metrics.PantheonMetricCategory.PEERS;
import static tech.pegasys.pantheon.metrics.PantheonMetricCategory.RPC;
import static tech.pegasys.pantheon.metrics.StandardMetricCategory.JVM;
import tech.pegasys.pantheon.metrics.Counter;
import tech.pegasys.pantheon.metrics.LabelledMetric;
@ -32,18 +33,19 @@ import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import java.util.Comparator;
import java.util.EnumSet;
import com.google.common.collect.ImmutableSet;
import org.junit.Test;
public class PrometheusMetricsSystemTest {
private static final Comparator<Observation> IGNORE_VALUES =
Comparator.comparing(Observation::getCategory)
Comparator.<Observation, String>comparing(observation -> observation.getCategory().getName())
.thenComparing(Observation::getMetricName)
.thenComparing((o1, o2) -> o1.getLabels().equals(o2.getLabels()) ? 0 : 1);
private final MetricsSystem metricsSystem = new PrometheusMetricsSystem();
private final MetricsSystem metricsSystem =
new PrometheusMetricsSystem(DEFAULT_METRIC_CATEGORIES);
@Test
public void shouldCreateObservationFromCounter() {
@ -175,7 +177,7 @@ public class PrometheusMetricsSystemTest {
public void shouldOnlyObserveEnabledMetrics() {
final MetricsConfiguration metricsConfiguration =
MetricsConfiguration.builder()
.metricCategories(EnumSet.of(PantheonMetricCategory.RPC))
.metricCategories(ImmutableSet.of(PantheonMetricCategory.RPC))
.enabled(true)
.build();
final MetricsSystem localMetricSystem = PrometheusMetricsSystem.init(metricsConfiguration);

@ -187,8 +187,7 @@ public class RocksDBStats {
final Statistics stats, final HistogramType histogram) {
return new Collector() {
final String metricName =
PrometheusMetricsSystem.convertToPrometheusName(
KVSTORE_ROCKSDB_STATS, histogram.name().toLowerCase());
KVSTORE_ROCKSDB_STATS.getName() + "_" + histogram.name().toLowerCase();
@Override
public List<MetricFamilySamples> collect() {

@ -31,6 +31,7 @@ import static tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration.DEFA
import tech.pegasys.pantheon.Runner;
import tech.pegasys.pantheon.RunnerBuilder;
import tech.pegasys.pantheon.cli.PublicKeySubCommand.KeyLoader;
import tech.pegasys.pantheon.cli.converter.MetricCategoryConverter;
import tech.pegasys.pantheon.cli.converter.RpcApisConverter;
import tech.pegasys.pantheon.cli.custom.CorsAllowedOriginsProperty;
import tech.pegasys.pantheon.cli.custom.JsonRPCWhitelistHostsProperty;
@ -61,8 +62,10 @@ import tech.pegasys.pantheon.ethereum.permissioning.LocalPermissioningConfigurat
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfigurationBuilder;
import tech.pegasys.pantheon.ethereum.permissioning.SmartContractPermissioningConfiguration;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import tech.pegasys.pantheon.metrics.StandardMetricCategory;
import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration;
import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem;
import tech.pegasys.pantheon.metrics.vertx.VertxMetricsAdapterFactory;
@ -412,7 +415,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
arity = "1..*",
description =
"Comma separated list of categories to track metrics for (default: ${DEFAULT-VALUE})")
private final Set<PantheonMetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
private final Set<MetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
@Option(
names = {"--metrics-push-enabled"},
@ -650,6 +653,11 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
commandLine.registerConverter(Wei.class, (arg) -> Wei.of(Long.parseUnsignedLong(arg)));
commandLine.registerConverter(PositiveNumber.class, PositiveNumber::fromString);
final MetricCategoryConverter metricCategoryConverter = new MetricCategoryConverter();
metricCategoryConverter.addCategories(PantheonMetricCategory.class);
metricCategoryConverter.addCategories(StandardMetricCategory.class);
commandLine.registerConverter(MetricCategory.class, metricCategoryConverter);
// Add performance options
UnstableOptionsSubCommand.createUnstableOptions(
commandLine,

@ -0,0 +1,40 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.cli.converter;
import tech.pegasys.pantheon.metrics.MetricCategory;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import picocli.CommandLine;
public class MetricCategoryConverter implements CommandLine.ITypeConverter<MetricCategory> {
private final Map<String, MetricCategory> metricCategories = new HashMap<>();
@Override
public MetricCategory convert(final String value) {
final MetricCategory category = metricCategories.get(value);
if (category == null) {
throw new IllegalArgumentException("Unknown category: " + value);
}
return category;
}
public <T extends Enum<T> & MetricCategory> void addCategories(final Class<T> categoryEnum) {
EnumSet.allOf(categoryEnum)
.forEach(category -> metricCategories.put(category.name(), category));
}
}

@ -49,7 +49,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.EnodeURL;
import tech.pegasys.pantheon.ethereum.permissioning.LocalPermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.SmartContractPermissioningConfiguration;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import tech.pegasys.pantheon.metrics.StandardMetricCategory;
import tech.pegasys.pantheon.metrics.prometheus.MetricsConfiguration;
import tech.pegasys.pantheon.util.bytes.BytesValue;
@ -2054,13 +2054,13 @@ public class PantheonCommandTest extends CommandTestAbstract {
@Test
public void metricsCategoryPropertyMustBeUsed() {
parseCommand("--metrics-enabled", "--metrics-category", PantheonMetricCategory.JVM.toString());
parseCommand("--metrics-enabled", "--metrics-category", StandardMetricCategory.JVM.toString());
verify(mockRunnerBuilder).metricsConfiguration(metricsConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(metricsConfigArgumentCaptor.getValue().getMetricCategories())
.containsExactly(PantheonMetricCategory.JVM);
.containsExactly(StandardMetricCategory.JVM);
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();

Loading…
Cancel
Save