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() { private MetricsConfiguration createMetricsConfiguration() {
return MetricsConfiguration.builder().enabled(true).build(); return MetricsConfiguration.builder().enabled(true).port(0).build();
} }
private JsonRpcHttpService createJsonRpcHttpService( private JsonRpcHttpService createJsonRpcHttpService(

@ -26,8 +26,6 @@ jar {
} }
dependencies { dependencies {
implementation project(':util')
implementation 'com.google.guava:guava' implementation 'com.google.guava:guava'
implementation 'io.prometheus:simpleclient' implementation 'io.prometheus:simpleclient'
implementation 'io.prometheus:simpleclient_common' implementation 'io.prometheus:simpleclient_common'
@ -40,6 +38,7 @@ dependencies {
runtime 'org.apache.logging.log4j:log4j-core' runtime 'org.apache.logging.log4j:log4j-core'
// test dependencies. // test dependencies.
testImplementation project(':util')
testImplementation 'junit:junit' testImplementation 'junit:junit'
testImplementation 'org.assertj:assertj-core' testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-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 { public interface MetricsSystem {
default Counter createCounter( 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(); return createLabelledCounter(category, name, help, new String[0]).labels();
} }
LabelledMetric<Counter> createLabelledCounter( LabelledMetric<Counter> createLabelledCounter(
PantheonMetricCategory category, String name, String help, String... labelNames); MetricCategory category, String name, String help, String... labelNames);
default OperationTimer createTimer( 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(); return createLabelledTimer(category, name, help, new String[0]).labels();
} }
LabelledMetric<OperationTimer> createLabelledTimer( LabelledMetric<OperationTimer> createLabelledTimer(
PantheonMetricCategory category, String name, String help, String... labelNames); MetricCategory category, String name, String help, String... labelNames);
void createGauge( void createGauge(MetricCategory category, String name, String help, DoubleSupplier valueSupplier);
PantheonMetricCategory category, String name, String help, DoubleSupplier valueSupplier);
default void createIntegerGauge( default void createIntegerGauge(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final IntSupplier valueSupplier) { final IntSupplier valueSupplier) {
@ -47,16 +46,14 @@ public interface MetricsSystem {
} }
default void createLongGauge( default void createLongGauge(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final LongSupplier valueSupplier) { final LongSupplier valueSupplier) {
createGauge(category, name, help, () -> (double) valueSupplier.getAsLong()); createGauge(category, name, help, () -> (double) valueSupplier.getAsLong());
} }
Stream<Observation> streamObservations(PantheonMetricCategory category); Stream<Observation> streamObservations(MetricCategory category);
default Stream<Observation> streamObservations() { Stream<Observation> streamObservations();
return Stream.of(PantheonMetricCategory.values()).flatMap(this::streamObservations);
}
} }

@ -18,13 +18,13 @@ import java.util.Objects;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
public class Observation { public class Observation {
private final PantheonMetricCategory category; private final MetricCategory category;
private final String metricName; private final String metricName;
private final List<String> labels; private final List<String> labels;
private final Object value; private final Object value;
public Observation( public Observation(
final PantheonMetricCategory category, final MetricCategory category,
final String metricName, final String metricName,
final Object value, final Object value,
final List<String> labels) { final List<String> labels) {
@ -34,7 +34,7 @@ public class Observation {
this.labels = labels; this.labels = labels;
} }
public PantheonMetricCategory getCategory() { public MetricCategory getCategory() {
return category; 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 * 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 * the License. You may obtain a copy of the License at
@ -13,16 +13,16 @@
package tech.pegasys.pantheon.metrics; package tech.pegasys.pantheon.metrics;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import java.util.Set; import java.util.Set;
public enum PantheonMetricCategory { import com.google.common.collect.ImmutableSet;
BIG_QUEUE("big_queue"),
public enum PantheonMetricCategory implements MetricCategory {
BLOCKCHAIN("blockchain"), BLOCKCHAIN("blockchain"),
EXECUTORS("executors"), EXECUTORS("executors"),
JVM("jvm", false),
NETWORK("network"), NETWORK("network"),
PEERS("peers"), PEERS("peers"),
PROCESS("process", false),
PERMISSIONING("permissioning"), PERMISSIONING("permissioning"),
KVSTORE_ROCKSDB("rocksdb"), KVSTORE_ROCKSDB("rocksdb"),
KVSTORE_ROCKSDB_STATS("rocksdb", false), KVSTORE_ROCKSDB_STATS("rocksdb", false),
@ -30,9 +30,20 @@ public enum PantheonMetricCategory {
SYNCHRONIZER("synchronizer"), SYNCHRONIZER("synchronizer"),
TRANSACTION_POOL("transaction_pool"); TRANSACTION_POOL("transaction_pool");
// Why not BIG_QUEUE and ROCKSDB? They hurt performance under load. private static final Optional<String> PANTHEON_PREFIX = Optional.of("pantheon_");
public static final Set<PantheonMetricCategory> DEFAULT_METRIC_CATEGORIES = public static final Set<MetricCategory> DEFAULT_METRIC_CATEGORIES;
EnumSet.complementOf(EnumSet.of(BIG_QUEUE, KVSTORE_ROCKSDB, KVSTORE_ROCKSDB_STATS));
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 String name;
private final boolean pantheonSpecific; private final boolean pantheonSpecific;
@ -46,11 +57,13 @@ public enum PantheonMetricCategory {
this.pantheonSpecific = pantheonSpecific; this.pantheonSpecific = pantheonSpecific;
} }
@Override
public String getName() { public String getName() {
return name; return name;
} }
public boolean isPantheonSpecific() { @Override
return pantheonSpecific; 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.Counter;
import tech.pegasys.pantheon.metrics.LabelledMetric; import tech.pegasys.pantheon.metrics.LabelledMetric;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.Observation; import tech.pegasys.pantheon.metrics.Observation;
import tech.pegasys.pantheon.metrics.OperationTimer; import tech.pegasys.pantheon.metrics.OperationTimer;
import tech.pegasys.pantheon.metrics.OperationTimer.TimingContext; import tech.pegasys.pantheon.metrics.OperationTimer.TimingContext;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -42,7 +42,7 @@ public class NoOpMetricsSystem implements MetricsSystem {
@Override @Override
public LabelledMetric<Counter> createLabelledCounter( public LabelledMetric<Counter> createLabelledCounter(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final String... labelNames) { final String... labelNames) {
@ -64,7 +64,7 @@ public class NoOpMetricsSystem implements MetricsSystem {
@Override @Override
public LabelledMetric<OperationTimer> createLabelledTimer( public LabelledMetric<OperationTimer> createLabelledTimer(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final String... labelNames) { final String... labelNames) {
@ -82,13 +82,13 @@ public class NoOpMetricsSystem implements MetricsSystem {
@Override @Override
public void createGauge( public void createGauge(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final DoubleSupplier valueSupplier) {} final DoubleSupplier valueSupplier) {}
@Override @Override
public Stream<Observation> streamObservations(final PantheonMetricCategory category) { public Stream<Observation> streamObservations(final MetricCategory category) {
return Stream.empty(); return Stream.empty();
} }

@ -14,7 +14,7 @@ package tech.pegasys.pantheon.metrics.prometheus;
import static tech.pegasys.pantheon.metrics.PantheonMetricCategory.DEFAULT_METRIC_CATEGORIES; 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.Arrays;
import java.util.Collection; import java.util.Collection;
@ -35,7 +35,7 @@ public class MetricsConfiguration {
private final boolean enabled; private final boolean enabled;
private final int port; private final int port;
private final String host; private final String host;
private final Set<PantheonMetricCategory> metricCategories; private final Set<MetricCategory> metricCategories;
private final boolean pushEnabled; private final boolean pushEnabled;
private final int pushPort; private final int pushPort;
private final String pushHost; private final String pushHost;
@ -51,7 +51,7 @@ public class MetricsConfiguration {
final boolean enabled, final boolean enabled,
final int port, final int port,
final String host, final String host,
final Set<PantheonMetricCategory> metricCategories, final Set<MetricCategory> metricCategories,
final boolean pushEnabled, final boolean pushEnabled,
final int pushPort, final int pushPort,
final String pushHost, final String pushHost,
@ -82,7 +82,7 @@ public class MetricsConfiguration {
return host; return host;
} }
public Set<PantheonMetricCategory> getMetricCategories() { public Set<MetricCategory> getMetricCategories() {
return metricCategories; return metricCategories;
} }
@ -166,7 +166,7 @@ public class MetricsConfiguration {
private boolean enabled = false; private boolean enabled = false;
private int port = DEFAULT_METRICS_PORT; private int port = DEFAULT_METRICS_PORT;
private String host = DEFAULT_METRICS_HOST; 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 boolean pushEnabled = false;
private int pushPort = DEFAULT_METRICS_PUSH_PORT; private int pushPort = DEFAULT_METRICS_PUSH_PORT;
private String pushHost = DEFAULT_METRICS_PUSH_HOST; private String pushHost = DEFAULT_METRICS_PUSH_HOST;
@ -191,7 +191,7 @@ public class MetricsConfiguration {
return this; return this;
} }
public Builder metricCategories(final Set<PantheonMetricCategory> metricCategories) { public Builder metricCategories(final Set<MetricCategory> metricCategories) {
this.metricCategories = metricCategories; this.metricCategories = metricCategories;
return this; 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.base.Preconditions.checkArgument;
import static com.google.common.collect.Streams.stream; 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.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.NetworkUtility;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@ -30,7 +28,6 @@ import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
@ -68,9 +65,7 @@ class MetricsHttpService implements MetricsService {
} }
private void validateConfig(final MetricsConfiguration config) { private void validateConfig(final MetricsConfiguration config) {
checkArgument( checkArgument(config.getPort() >= 0 && config.getPort() < 65535, "Invalid port configuration.");
config.getPort() == 0 || NetworkUtility.isValidPort(config.getPort()),
"Invalid port configuration.");
checkArgument(config.getHost() != null, "Required host is not configured."); checkArgument(config.getHost() != null, "Required host is not configured.");
checkArgument( checkArgument(
!(config.isEnabled() && config.isPushEnabled()), !(config.isEnabled() && config.isPushEnabled()),
@ -232,14 +227,6 @@ class MetricsHttpService implements MetricsService {
return Optional.of(httpServer.actualPort()); 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. // Facilitate remote health-checks in AWS, inter alia.
private void handleEmptyRequest(final RoutingContext routingContext) { private void handleEmptyRequest(final RoutingContext routingContext) {
routingContext.response().setStatusCode(201).end(); routingContext.response().setStatusCode(201).end();

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

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

@ -29,7 +29,7 @@ public class StubMetricsSystem implements MetricsSystem {
@Override @Override
public LabelledMetric<Counter> createLabelledCounter( public LabelledMetric<Counter> createLabelledCounter(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final String... labelNames) { final String... labelNames) {
@ -50,7 +50,7 @@ public class StubMetricsSystem implements MetricsSystem {
@Override @Override
public LabelledMetric<OperationTimer> createLabelledTimer( public LabelledMetric<OperationTimer> createLabelledTimer(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final String... labelNames) { final String... labelNames) {
@ -59,7 +59,7 @@ public class StubMetricsSystem implements MetricsSystem {
@Override @Override
public void createGauge( public void createGauge(
final PantheonMetricCategory category, final MetricCategory category,
final String name, final String name,
final String help, final String help,
final DoubleSupplier valueSupplier) { final DoubleSupplier valueSupplier) {
@ -75,7 +75,12 @@ public class StubMetricsSystem implements MetricsSystem {
} }
@Override @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"); 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.LabelledMetric;
import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.OperationTimer; import tech.pegasys.pantheon.metrics.OperationTimer;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory; import tech.pegasys.pantheon.metrics.StandardMetricCategory;
import org.junit.Test; import org.junit.Test;
@ -31,7 +31,7 @@ public class NoOpMetricsSystemTest {
public void labelCountsMatchOnCounter() { public void labelCountsMatchOnCounter() {
final LabelledMetric<Counter> labeledCounter = final LabelledMetric<Counter> labeledCounter =
metricsSystem.createLabelledCounter( metricsSystem.createLabelledCounter(
PantheonMetricCategory.PROCESS, "name", "help", "label1"); StandardMetricCategory.PROCESS, "name", "help", "label1");
assertThat(labeledCounter.labels("one")).isSameAs(NoOpMetricsSystem.NO_OP_COUNTER); assertThat(labeledCounter.labels("one")).isSameAs(NoOpMetricsSystem.NO_OP_COUNTER);
} }
@ -39,7 +39,7 @@ public class NoOpMetricsSystemTest {
public void failsWheLabelCountsDoNotMatchOnCounter() { public void failsWheLabelCountsDoNotMatchOnCounter() {
final LabelledMetric<Counter> labeledCounter = final LabelledMetric<Counter> labeledCounter =
metricsSystem.createLabelledCounter( metricsSystem.createLabelledCounter(
PantheonMetricCategory.PROCESS, "name", "help", "label1", "label2"); StandardMetricCategory.PROCESS, "name", "help", "label1", "label2");
assertThatExceptionOfType(IllegalArgumentException.class) assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> labeledCounter.labels("one")) .isThrownBy(() -> labeledCounter.labels("one"))
@ -52,7 +52,7 @@ public class NoOpMetricsSystemTest {
@Test @Test
public void labelCountsMatchOnTimer() { public void labelCountsMatchOnTimer() {
final LabelledMetric<OperationTimer> labeledTimer = 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); assertThat(labeledTimer.labels("one")).isSameAs(NoOpMetricsSystem.NO_OP_OPERATION_TIMER);
} }
@ -60,7 +60,7 @@ public class NoOpMetricsSystemTest {
public void failsWheLabelCountsDoNotMatchOnTimer() { public void failsWheLabelCountsDoNotMatchOnTimer() {
final LabelledMetric<OperationTimer> labeledTimer = final LabelledMetric<OperationTimer> labeledTimer =
metricsSystem.createLabelledTimer( metricsSystem.createLabelledTimer(
PantheonMetricCategory.PROCESS, "name", "help", "label1", "label2"); StandardMetricCategory.PROCESS, "name", "help", "label1", "label2");
assertThatExceptionOfType(IllegalArgumentException.class) assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> labeledTimer.labels("one")) .isThrownBy(() -> labeledTimer.labels("one"))

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

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

@ -187,8 +187,7 @@ public class RocksDBStats {
final Statistics stats, final HistogramType histogram) { final Statistics stats, final HistogramType histogram) {
return new Collector() { return new Collector() {
final String metricName = final String metricName =
PrometheusMetricsSystem.convertToPrometheusName( KVSTORE_ROCKSDB_STATS.getName() + "_" + histogram.name().toLowerCase();
KVSTORE_ROCKSDB_STATS, histogram.name().toLowerCase());
@Override @Override
public List<MetricFamilySamples> collect() { 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.Runner;
import tech.pegasys.pantheon.RunnerBuilder; import tech.pegasys.pantheon.RunnerBuilder;
import tech.pegasys.pantheon.cli.PublicKeySubCommand.KeyLoader; 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.converter.RpcApisConverter;
import tech.pegasys.pantheon.cli.custom.CorsAllowedOriginsProperty; import tech.pegasys.pantheon.cli.custom.CorsAllowedOriginsProperty;
import tech.pegasys.pantheon.cli.custom.JsonRPCWhitelistHostsProperty; 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.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfigurationBuilder; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfigurationBuilder;
import tech.pegasys.pantheon.ethereum.permissioning.SmartContractPermissioningConfiguration; import tech.pegasys.pantheon.ethereum.permissioning.SmartContractPermissioningConfiguration;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.PantheonMetricCategory; 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.MetricsConfiguration;
import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem;
import tech.pegasys.pantheon.metrics.vertx.VertxMetricsAdapterFactory; import tech.pegasys.pantheon.metrics.vertx.VertxMetricsAdapterFactory;
@ -412,7 +415,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
arity = "1..*", arity = "1..*",
description = description =
"Comma separated list of categories to track metrics for (default: ${DEFAULT-VALUE})") "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( @Option(
names = {"--metrics-push-enabled"}, 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(Wei.class, (arg) -> Wei.of(Long.parseUnsignedLong(arg)));
commandLine.registerConverter(PositiveNumber.class, PositiveNumber::fromString); 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 // Add performance options
UnstableOptionsSubCommand.createUnstableOptions( UnstableOptionsSubCommand.createUnstableOptions(
commandLine, 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.LocalPermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.SmartContractPermissioningConfiguration; 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.metrics.prometheus.MetricsConfiguration;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
@ -2054,13 +2054,13 @@ public class PantheonCommandTest extends CommandTestAbstract {
@Test @Test
public void metricsCategoryPropertyMustBeUsed() { 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).metricsConfiguration(metricsConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build(); verify(mockRunnerBuilder).build();
assertThat(metricsConfigArgumentCaptor.getValue().getMetricCategories()) assertThat(metricsConfigArgumentCaptor.getValue().getMetricCategories())
.containsExactly(PantheonMetricCategory.JVM); .containsExactly(StandardMetricCategory.JVM);
assertThat(commandOutput.toString()).isEmpty(); assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty(); assertThat(commandErrorOutput.toString()).isEmpty();

Loading…
Cancel
Save