Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Begin capturing metrics to better understand Pantheon's behaviour (#326)
Metrics being captured initially:

Total number of peers ever connected to
Total number of peers disconnected, by disconnect reason and whether the disconnect was initiated locally or remotely.
Current number of peers
Timing for processing JSON-RPC requests, broken down by method name.
Generic JVM and process metrics (memory used, heap size, thread count, time spent in GC, file descriptors opened, CPU time etc).
  • Loading branch information
ajsutton committed Nov 29, 2018
1 parent 25bc82f commit 081c2f9
Show file tree
Hide file tree
Showing 36 changed files with 1,152 additions and 44 deletions.
1 change: 1 addition & 0 deletions ethereum/eth/build.gradle
Expand Up @@ -29,6 +29,7 @@ dependencies {
implementation project(':ethereum:core')
implementation project(':ethereum:p2p')
implementation project(':ethereum:rlp')
implementation project(':metrics')
implementation project(':services:kvstore')

implementation 'io.vertx:vertx-core'
Expand Down
Expand Up @@ -44,6 +44,7 @@
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.io.Closeable;
Expand Down Expand Up @@ -112,7 +113,8 @@ public TestNode(
networkingConfiguration,
capabilities,
ethProtocolManager,
new PeerBlacklist()))
new PeerBlacklist(),
new NoOpMetricsSystem()))
.build();
network = networkRunner.getNetwork();
this.port = network.getSelf().getPort();
Expand Down
1 change: 1 addition & 0 deletions ethereum/jsonrpc/build.gradle
Expand Up @@ -32,6 +32,7 @@ dependencies {
implementation project(':ethereum:eth')
implementation project(':ethereum:p2p')
implementation project(':ethereum:rlp')
implementation project(':metrics')

implementation 'com.google.guava:guava'
implementation 'io.vertx:vertx-core'
Expand Down
Expand Up @@ -35,6 +35,8 @@
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;

import java.util.HashSet;
import java.util.Map;
Expand Down Expand Up @@ -75,6 +77,7 @@ public Map<String, JsonRpcMethod> methods() {
new FilterManager(
blockchainQueries, transactionPool, new FilterIdGenerator(), new FilterRepository());
final EthHashMiningCoordinator miningCoordinator = mock(EthHashMiningCoordinator.class);
final MetricsSystem metricsSystem = new NoOpMetricsSystem();

return new JsonRpcMethodsFactory()
.methods(
Expand All @@ -86,6 +89,7 @@ public Map<String, JsonRpcMethod> methods() {
filterManager,
transactionPool,
miningCoordinator,
metricsSystem,
new HashSet<>(),
RpcApis.DEFAULT_JSON_RPC_APIS);
}
Expand Down
Expand Up @@ -25,6 +25,11 @@
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcNoResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponseType;
import tech.pegasys.pantheon.metrics.LabelledMetric;
import tech.pegasys.pantheon.metrics.MetricCategory;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.OperationTimer;
import tech.pegasys.pantheon.metrics.OperationTimer.TimingContext;
import tech.pegasys.pantheon.util.NetworkUtility;

import java.net.BindException;
Expand Down Expand Up @@ -69,15 +74,23 @@ public class JsonRpcHttpService {
private final JsonRpcConfiguration config;
private final Map<String, JsonRpcMethod> jsonRpcMethods;
private final Path dataDir;
private final LabelledMetric<OperationTimer> requestTimer;

private HttpServer httpServer;

public JsonRpcHttpService(
final Vertx vertx,
final Path dataDir,
final JsonRpcConfiguration config,
final MetricsSystem metricsSystem,
final Map<String, JsonRpcMethod> methods) {
this.dataDir = dataDir;
requestTimer =
metricsSystem.createLabelledTimer(
MetricCategory.RPC,
"request_time",
"Time taken to process a JSON-RPC request",
"methodName");
validateConfig(config);
this.config = config;
this.vertx = vertx;
Expand Down Expand Up @@ -327,7 +340,7 @@ private JsonRpcResponse process(final JsonObject requestJson) {
}

// Generate response
try {
try (final TimingContext context = requestTimer.labels(request.getMethod()).startTimer()) {
return method.response(request);
} catch (final InvalidJsonRpcParameters e) {
LOG.debug(e);
Expand Down
Expand Up @@ -19,6 +19,7 @@
import tech.pegasys.pantheon.ethereum.db.WorldStateArchive;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.filter.FilterManager;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.AdminPeers;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugMetrics;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugStorageRangeAt;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.DebugTraceTransaction;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.EthAccounts;
Expand Down Expand Up @@ -75,6 +76,7 @@
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.metrics.MetricsSystem;

import java.util.Collection;
import java.util.HashMap;
Expand All @@ -95,6 +97,7 @@ public Map<String, JsonRpcMethod> methods(
final TransactionPool transactionPool,
final ProtocolSchedule<?> protocolSchedule,
final MiningCoordinator miningCoordinator,
final MetricsSystem metricsSystem,
final Set<Capability> supportedCapabilities,
final Collection<RpcApi> rpcApis,
final FilterManager filterManager) {
Expand All @@ -109,6 +112,7 @@ public Map<String, JsonRpcMethod> methods(
filterManager,
transactionPool,
miningCoordinator,
metricsSystem,
supportedCapabilities,
rpcApis);
}
Expand All @@ -122,6 +126,7 @@ public Map<String, JsonRpcMethod> methods(
final FilterManager filterManager,
final TransactionPool transactionPool,
final MiningCoordinator miningCoordinator,
final MetricsSystem metricsSystem,
final Set<Capability> supportedCapabilities,
final Collection<RpcApi> rpcApis) {
final Map<String, JsonRpcMethod> enabledMethods = new HashMap<>();
Expand Down Expand Up @@ -189,7 +194,8 @@ public Map<String, JsonRpcMethod> methods(
enabledMethods,
new DebugTraceTransaction(
blockchainQueries, new TransactionTracer(blockReplay), parameter),
new DebugStorageRangeAt(parameter, blockchainQueries, blockReplay));
new DebugStorageRangeAt(parameter, blockchainQueries, blockReplay),
new DebugMetrics(metricsSystem));
}
if (rpcApis.contains(RpcApis.NET)) {
addMethods(
Expand Down
@@ -0,0 +1,72 @@
/*
* Copyright 2018 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.ethereum.jsonrpc.internal.methods;

import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.Observation;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DebugMetrics implements JsonRpcMethod {

private final MetricsSystem metricsSystem;

public DebugMetrics(final MetricsSystem metricsSystem) {
this.metricsSystem = metricsSystem;
}

@Override
public String getName() {
return "debug_metrics";
}

@Override
public JsonRpcResponse response(final JsonRpcRequest request) {
final Map<String, Object> observations = new HashMap<>();
metricsSystem.getMetrics().forEach(observation -> addObservation(observations, observation));
return new JsonRpcSuccessResponse(request.getId(), observations);
}

private void addObservation(
final Map<String, Object> observations, final Observation observation) {
final Map<String, Object> categoryObservations =
getNextMapLevel(observations, observation.getCategory().getName());
if (observation.getLabels().isEmpty()) {
categoryObservations.put(observation.getMetricName(), observation.getValue());
} else {
addLabelledObservation(categoryObservations, observation);
}
}

private void addLabelledObservation(
final Map<String, Object> categoryObservations, final Observation observation) {
final List<String> labels = observation.getLabels();
Map<String, Object> values = getNextMapLevel(categoryObservations, observation.getMetricName());
for (int i = 0; i < labels.size() - 1; i++) {
values = getNextMapLevel(values, labels.get(i));
}
values.put(labels.get(labels.size() - 1), observation.getValue());
}

@SuppressWarnings("unchecked")
private Map<String, Object> getNextMapLevel(
final Map<String, Object> current, final String name) {
return (Map<String, Object>)
current.computeIfAbsent(name, key -> new HashMap<String, Object>());
}
}
Expand Up @@ -47,6 +47,7 @@
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.util.RawBlockIterator;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;

import java.net.URL;
import java.nio.file.Paths;
Expand Down Expand Up @@ -175,11 +176,14 @@ public void setupTest() throws Exception {
filterManager,
transactionPoolMock,
miningCoordinatorMock,
new NoOpMetricsSystem(),
supportedCapabilities,
JSON_RPC_APIS);
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setPort(0);
service = new JsonRpcHttpService(vertx, folder.newFolder().toPath(), config, methods);
service =
new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), config, new NoOpMetricsSystem(), methods);
service.start().join();

client = new OkHttpClient();
Expand Down
Expand Up @@ -14,6 +14,8 @@

import static org.assertj.core.api.Assertions.assertThat;

import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;

import java.util.HashMap;

import com.google.common.collect.Lists;
Expand Down Expand Up @@ -168,7 +170,8 @@ private JsonRpcHttpService createJsonRpcHttpServiceWithAllowedDomains(
}

final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(vertx, folder.newFolder().toPath(), config, new HashMap<>());
new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), config, new NoOpMetricsSystem(), new HashMap<>());
jsonRpcHttpService.start().join();

return jsonRpcHttpService;
Expand Down
Expand Up @@ -28,6 +28,7 @@
import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;

import java.util.HashSet;
import java.util.Map;
Expand Down Expand Up @@ -176,10 +177,12 @@ private JsonRpcHttpService createJsonRpcHttpServiceWithRpcApis(final JsonRpcConf
mock(FilterManager.class),
mock(TransactionPool.class),
mock(EthHashMiningCoordinator.class),
new NoOpMetricsSystem(),
supportedCapabilities,
config.getRpcApis()));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(vertx, folder.newFolder().toPath(), config, rpcMethods);
new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), config, new NoOpMetricsSystem(), rpcMethods);
jsonRpcHttpService.start().join();

baseUrl = jsonRpcHttpService.url();
Expand Down
Expand Up @@ -42,6 +42,7 @@
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.BytesValues;
import tech.pegasys.pantheon.util.uint.UInt256;
Expand Down Expand Up @@ -119,6 +120,7 @@ public static void initServerAndClient() throws Exception {
mock(FilterManager.class),
mock(TransactionPool.class),
mock(EthHashMiningCoordinator.class),
new NoOpMetricsSystem(),
supportedCapabilities,
JSON_RPC_APIS));
service = createJsonRpcHttpService();
Expand All @@ -131,12 +133,17 @@ public static void initServerAndClient() throws Exception {

protected static JsonRpcHttpService createJsonRpcHttpService(final JsonRpcConfiguration config)
throws Exception {
return new JsonRpcHttpService(vertx, folder.newFolder().toPath(), config, rpcMethods);
return new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), config, new NoOpMetricsSystem(), rpcMethods);
}

protected static JsonRpcHttpService createJsonRpcHttpService() throws Exception {
return new JsonRpcHttpService(
vertx, folder.newFolder().toPath(), createJsonRpcConfig(), rpcMethods);
vertx,
folder.newFolder().toPath(),
createJsonRpcConfig(),
new NoOpMetricsSystem(),
rpcMethods);
}

protected static JsonRpcConfiguration createJsonRpcConfig() {
Expand Down

0 comments on commit 081c2f9

Please sign in to comment.