From b74f88afb21efa7901443104112a16abf3a9f950 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 3 Dec 2018 13:15:15 -0700 Subject: [PATCH] Plumb in three more metrics (#344) * Plumb in three more metrics * add blockchain_height gauge * add blockchain_difficulty_total gauge * add blockchain_announcedBlock_ingest histogram This involved some deep pluming such that the metrics system needs to be created in the PantheonCommand, along with trickle down effects into other consensus engines. This is likely where it should live anyway. --- acceptance-tests/build.gradle | 5 ++-- .../dsl/node/ThreadPantheonNodeRunner.java | 5 ++++ ethereum/core/build.gradle | 1 + .../ethereum/db/DefaultMutableBlockchain.java | 17 +++++++++++- .../core/ExecutionContextTestFixture.java | 4 ++- .../core/InMemoryStorageProvider.java | 4 ++- .../db/DefaultMutableBlockchainTest.java | 4 ++- .../ethereum/db/GenesisBlockMismatchTest.java | 4 ++- .../eth/sync/BlockPropagationManager.java | 22 +++++++++++++--- .../eth/sync/DefaultSynchronizer.java | 7 +++-- .../eth/sync/BlockPropagationManagerTest.java | 9 +++++-- .../p2p/discovery/PeerDiscoveryAgentTest.java | 4 +-- .../pantheon/metrics/MetricCategory.java | 3 ++- .../pantheon/metrics/OperationTimer.java | 3 ++- .../metrics/noop/NoOpMetricsSystem.java | 2 +- .../tech/pegasys/pantheon/RunnerBuilder.java | 8 ++++-- .../pegasys/pantheon/cli/PantheonCommand.java | 6 +++++ .../cli/PantheonControllerBuilder.java | 13 ++++++++-- .../controller/CliquePantheonController.java | 9 ++++--- .../IbftLegacyPantheonController.java | 17 ++++++++---- .../controller/IbftPantheonController.java | 9 ++++--- .../controller/MainnetPantheonController.java | 9 ++++--- .../controller/PantheonController.java | 26 +++++++++++++++---- .../tech/pegasys/pantheon/RunnerTest.java | 14 +++++++--- .../pantheon/cli/CommandTestAbstract.java | 1 + .../pantheon/cli/PantheonCommandTest.java | 1 + .../pantheon/util/BlockImporterTest.java | 7 +++-- 27 files changed, 166 insertions(+), 48 deletions(-) diff --git a/acceptance-tests/build.gradle b/acceptance-tests/build.gradle index c04a753065..4bb3ccfec4 100644 --- a/acceptance-tests/build.gradle +++ b/acceptance-tests/build.gradle @@ -16,14 +16,15 @@ dependencies { testRuntime 'org.apache.logging.log4j:log4j-core' testRuntime 'org.apache.logging.log4j:log4j-slf4j-impl' + testImplementation project(':config') + testImplementation project(':consensus:clique') testImplementation project(':crypto') testImplementation project(':ethereum:eth') testImplementation project(':ethereum:core') testImplementation project(':ethereum:blockcreation') testImplementation project(':ethereum:jsonrpc') + testImplementation project(':metrics') testImplementation project(':pantheon') - testImplementation project(':config') - testImplementation project(':consensus:clique') testImplementation project(':util') testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java index fe892293d2..81d66cbd32 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java @@ -21,6 +21,8 @@ import tech.pegasys.pantheon.cli.PantheonControllerBuilder; import tech.pegasys.pantheon.controller.KeyPairUtil; import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.util.Collections; @@ -48,6 +50,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { nodeExecutor = Executors.newCachedThreadPool(); } + final MetricsSystem noOpMetricsSystem = new NoOpMetricsSystem(); final PantheonControllerBuilder builder = new PantheonControllerBuilder(); final EthNetworkConfig ethNetworkConfig = node.ethNetworkConfig() @@ -63,6 +66,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { .miningParameters(node.getMiningParameters()) .devMode(node.isDevMode()) .nodePrivateKeyFile(KeyPairUtil.getDefaultKeyFile(node.homeDirectory())) + .metricsSystem(noOpMetricsSystem) .build(); } catch (final IOException e) { throw new RuntimeException("Error building PantheonController", e); @@ -81,6 +85,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { .webSocketConfiguration(node.webSocketConfiguration()) .dataDir(node.homeDirectory()) .bannedNodeIds(Collections.emptySet()) + .metricsSystem(noOpMetricsSystem) .build(); nodeExecutor.submit(runner::execute); diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 90c123a6bb..1a3c5f2071 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -30,6 +30,7 @@ dependencies { implementation project(':crypto') implementation project(':ethereum:rlp') implementation project(':ethereum:trie') + implementation project(':metrics') implementation project(':services:kvstore') implementation 'com.fasterxml.jackson.core:jackson-databind' diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java index 03e2fad824..308e95b19f 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java @@ -29,6 +29,8 @@ import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; +import tech.pegasys.pantheon.metrics.MetricCategory; +import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.uint.UInt256; @@ -51,10 +53,23 @@ public class DefaultMutableBlockchain implements MutableBlockchain { private final Subscribers blockAddedObservers = new Subscribers<>(); public DefaultMutableBlockchain( - final Block genesisBlock, final BlockchainStorage blockchainStorage) { + final Block genesisBlock, + final BlockchainStorage blockchainStorage, + final MetricsSystem metricsSystem) { checkNotNull(genesisBlock); this.blockchainStorage = blockchainStorage; this.setGenesis(genesisBlock); + + metricsSystem.createGauge( + MetricCategory.BLOCKCHAIN, + "height", + "Height of the chainhead", + () -> (double) this.getChainHeadBlockNumber()); + metricsSystem.createGauge( + MetricCategory.BLOCKCHAIN, + "difficulty_total", + "Total difficulty of the chainhead", + () -> (double) this.getChainHead().getTotalDifficulty().toLong()); } @Override diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java index 6f33efd5c4..3d9bfa96df 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStorageWorldStateStorage; import tech.pegasys.pantheon.ethereum.worldstate.DefaultMutableWorldState; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; @@ -50,7 +51,8 @@ public class ExecutionContextTestFixture { new DefaultMutableBlockchain( genesis, new KeyValueStoragePrefixedKeyBlockchainStorage( - keyValueStorage, MainnetBlockHashFunction::createHash)); + keyValueStorage, MainnetBlockHashFunction::createHash), + new NoOpMetricsSystem()); this.stateArchive = new WorldStateArchive(new KeyValueStorageWorldStateStorage(keyValueStorage)); this.protocolSchedule = protocolSchedule; diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java index b2e56e38a5..6621f287d6 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java @@ -23,6 +23,7 @@ import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStorageWorldStateStorage; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; public class InMemoryStorageProvider implements StorageProvider { @@ -36,7 +37,8 @@ public class InMemoryStorageProvider implements StorageProvider { final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage(); return new DefaultMutableBlockchain( genesisBlock, - new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHashFunction)); + new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHashFunction), + new NoOpMetricsSystem()); } public static WorldStateArchive createInMemoryWorldStateArchive() { diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java index 9cd6cdac40..d90cd863cc 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchainTest.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator.BlockOptions; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; import tech.pegasys.pantheon.util.uint.UInt256; @@ -713,6 +714,7 @@ public class DefaultMutableBlockchainTest { return new DefaultMutableBlockchain( genesisBlock, new KeyValueStoragePrefixedKeyBlockchainStorage( - kvStore, MainnetBlockHashFunction::createHash)); + kvStore, MainnetBlockHashFunction::createHash), + new NoOpMetricsSystem()); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java index c610596c34..bb03ca0147 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java @@ -25,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.core.LogsBloomFilter; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; import tech.pegasys.pantheon.util.bytes.Bytes32; @@ -73,7 +74,8 @@ public class GenesisBlockMismatchTest { new DefaultMutableBlockchain( genesisBlock00, new KeyValueStoragePrefixedKeyBlockchainStorage( - kvStore, MainnetBlockHashFunction::createHash)); + kvStore, MainnetBlockHashFunction::createHash), + new NoOpMetricsSystem()); final BlockHeader genesisHeader01 = BlockHeaderBuilder.create() diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java index b3fa3022ce..4af2ca3f62 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java @@ -34,6 +34,9 @@ import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason; import tech.pegasys.pantheon.ethereum.rlp.RLPException; +import tech.pegasys.pantheon.metrics.MetricCategory; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.OperationTimer; import tech.pegasys.pantheon.util.uint.UInt256; import java.util.ArrayList; @@ -64,6 +67,7 @@ public class BlockPropagationManager { private final Set requestedBlocks = new ConcurrentSet<>(); private final PendingBlocks pendingBlocks; + private final OperationTimer announcedBlockIngestTimer; BlockPropagationManager( final SynchronizerConfiguration config, @@ -71,7 +75,8 @@ public class BlockPropagationManager { final ProtocolContext protocolContext, final EthContext ethContext, final SyncState syncState, - final PendingBlocks pendingBlocks) { + final PendingBlocks pendingBlocks, + final MetricsSystem metricsSystem) { this.config = config; this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; @@ -79,6 +84,12 @@ public class BlockPropagationManager { this.syncState = syncState; this.pendingBlocks = pendingBlocks; + + this.announcedBlockIngestTimer = + metricsSystem.createTimer( + MetricCategory.BLOCKCHAIN, + "pantheon_blockchain_announcedBlock_ingest", + "Time to ingest a single announced block"); } public void start() { @@ -241,21 +252,24 @@ public class BlockPropagationManager { final PersistBlockTask importTask = PersistBlockTask.create( protocolSchedule, protocolContext, block, HeaderValidationMode.FULL); + final OperationTimer.TimingContext blockTimer = announcedBlockIngestTimer.startTimer(); return ethContext .getScheduler() .scheduleWorkerTask(importTask::run) .whenComplete( (r, t) -> { if (t != null) { + // TODO do we time failures? But we cannot drop a label in at this point. LOG.warn( "Failed to import announced block {} ({}).", block.getHeader().getNumber(), block.getHash()); } else { + final double timeInMs = blockTimer.stopTimer() * 1000; LOG.info( - "Successfully imported announced block {} ({}).", - block.getHeader().getNumber(), - block.getHash()); + String.format( + "Successfully imported announced block %d (%s) in %01.3fms.", + block.getHeader().getNumber(), block.getHash(), timeInMs)); } }); } diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java index 3a1f40f755..20fcb3fafd 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java @@ -19,6 +19,7 @@ import tech.pegasys.pantheon.ethereum.eth.manager.EthContext; import tech.pegasys.pantheon.ethereum.eth.sync.state.PendingBlocks; import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; @@ -40,7 +41,8 @@ public class DefaultSynchronizer implements Synchronizer { final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, - final SyncState syncState) { + final SyncState syncState, + final MetricsSystem metricsSystem) { this.syncState = syncState; this.blockPropagationManager = new BlockPropagationManager<>( @@ -49,7 +51,8 @@ public class DefaultSynchronizer implements Synchronizer { protocolContext, ethContext, syncState, - new PendingBlocks()); + new PendingBlocks(), + metricsSystem); this.downloader = new Downloader<>(syncConfig, protocolSchedule, protocolContext, ethContext, syncState); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java index 9d51def6ba..da051d3c96 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java @@ -35,6 +35,8 @@ import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator.BlockOptions; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.util.uint.UInt256; import java.util.Collections; @@ -56,6 +58,7 @@ public class BlockPropagationManagerTest { private SynchronizerConfiguration syncConfig; private final PendingBlocks pendingBlocks = new PendingBlocks(); private SyncState syncState; + private final MetricsSystem metricsSystem = new NoOpMetricsSystem(); @BeforeClass public static void setupSuite() { @@ -87,7 +90,8 @@ public class BlockPropagationManagerTest { protocolContext, ethProtocolManager.ethContext(), syncState, - pendingBlocks); + pendingBlocks, + metricsSystem); } @Test @@ -462,7 +466,8 @@ public class BlockPropagationManagerTest { protocolContext, ethProtocolManager.ethContext(), syncState, - pendingBlocks); + pendingBlocks, + metricsSystem); final BlockDataGenerator gen = new BlockDataGenerator(); // Import some blocks diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java index 12d78a4ca9..5ce28f38fb 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java @@ -295,7 +295,7 @@ public class PeerDiscoveryAgentTest extends AbstractPeerDiscoveryTest { @Test public void shouldBeActiveWhenConfigIsTrue() { final DiscoveryConfiguration config = new DiscoveryConfiguration(); - config.setActive(true); + config.setActive(true).setBindPort(0); final PeerDiscoveryAgent agent = startDiscoveryAgent(config, new PeerBlacklist()); @@ -305,7 +305,7 @@ public class PeerDiscoveryAgentTest extends AbstractPeerDiscoveryTest { @Test public void shouldNotBeActiveWhenConfigIsFalse() { final DiscoveryConfiguration config = new DiscoveryConfiguration(); - config.setActive(false); + config.setActive(false).setBindPort(0); final PeerDiscoveryAgent agent = startDiscoveryAgent(config, new PeerBlacklist()); diff --git a/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java b/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java index 8798501b25..d1b12e40f3 100644 --- a/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java +++ b/metrics/src/main/java/tech/pegasys/pantheon/metrics/MetricCategory.java @@ -16,7 +16,8 @@ public enum MetricCategory { PEERS("peers"), RPC("rpc"), JVM("jvm", false), - PROCESS("process", false); + PROCESS("process", false), + BLOCKCHAIN("blockchain"); private final String name; private final boolean pantheonSpecific; diff --git a/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java b/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java index e16bc15dca..e5d13d237e 100644 --- a/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java +++ b/metrics/src/main/java/tech/pegasys/pantheon/metrics/OperationTimer.java @@ -19,7 +19,8 @@ public interface OperationTimer { TimingContext startTimer(); interface TimingContext extends Closeable { - void stopTimer(); + /** @return Elapsed time in seconds. */ + double stopTimer(); @Override default void close() { diff --git a/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java b/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java index 090c98058c..9b0f43d9a7 100644 --- a/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java +++ b/metrics/src/main/java/tech/pegasys/pantheon/metrics/noop/NoOpMetricsSystem.java @@ -26,7 +26,7 @@ import java.util.stream.Stream; public class NoOpMetricsSystem implements MetricsSystem { private static final Counter NO_OP_COUNTER = new NoOpCounter(); - private static final TimingContext NO_OP_TIMING_CONTEXT = () -> {}; + private static final TimingContext NO_OP_TIMING_CONTEXT = () -> 0; private static final OperationTimer NO_OP_TIMER = () -> NO_OP_TIMING_CONTEXT; @Override diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java index a3f8cccbf7..977eba9c68 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java @@ -53,7 +53,6 @@ import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.metrics.MetricsSystem; -import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.nio.file.Path; @@ -80,6 +79,7 @@ public class RunnerBuilder { private WebSocketConfiguration webSocketConfiguration; private Path dataDir; private Collection bannedNodeIds; + private MetricsSystem metricsSystem; private PermissioningConfiguration permissioningConfiguration; public RunnerBuilder vertx(final Vertx vertx) { @@ -143,11 +143,15 @@ public class RunnerBuilder { return this; } + public RunnerBuilder metricsSystem(final MetricsSystem metricsSystem) { + this.metricsSystem = metricsSystem; + return this; + } + public Runner build() { Preconditions.checkNotNull(pantheonController); - final MetricsSystem metricsSystem = PrometheusMetricsSystem.init(); final DiscoveryConfiguration discoveryConfiguration; if (discovery) { final Collection bootstrap; diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java index cda7fdbc64..8347b5961c 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -36,6 +36,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration; import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; import tech.pegasys.pantheon.util.BlockImporter; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -120,6 +122,8 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { private final Builder synchronizerConfigurationBuilder; private final RunnerBuilder runnerBuilder; + private final MetricsSystem metricsSystem = PrometheusMetricsSystem.init(); + // Public IP stored to prevent having to research it each time we need it. private InetAddress autoDiscoveredDefaultIP = null; @@ -446,6 +450,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { new MiningParameters(coinbase, minTransactionGasPrice, extraData, isMiningEnabled)) .devMode(isDevMode) .nodePrivateKeyFile(getNodePrivateKeyFile()) + .metricsSystem(metricsSystem) .build(); } catch (final InvalidConfigurationException e) { throw new ExecutionException(new CommandLine(this), e.getMessage()); @@ -520,6 +525,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable { .webSocketConfiguration(webSocketConfiguration) .dataDir(dataDir()) .bannedNodeIds(bannedNodeIds) + .metricsSystem(metricsSystem) .permissioningConfiguration(permissioningConfiguration) .build(); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java index b429842445..01505223da 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java @@ -24,6 +24,7 @@ import tech.pegasys.pantheon.ethereum.development.DevelopmentProtocolSchedule; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.storage.keyvalue.RocksDbStorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.File; import java.io.IOException; @@ -38,6 +39,7 @@ public class PantheonControllerBuilder { private MiningParameters miningParameters; private boolean devMode; private File nodePrivateKeyFile; + private MetricsSystem metricsSystem; public PantheonControllerBuilder synchronizerConfiguration( final SynchronizerConfiguration synchronizerConfiguration) { @@ -75,6 +77,11 @@ public class PantheonControllerBuilder { return this; } + public PantheonControllerBuilder metricsSystem(final MetricsSystem metricsSystem) { + this.metricsSystem = metricsSystem; + return this; + } + public PantheonController build() throws IOException { // instantiate a controller with mainnet config if no genesis file is defined // otherwise use the indicated genesis file @@ -90,7 +97,8 @@ public class PantheonControllerBuilder { DevelopmentProtocolSchedule.create(genesisConfig.getConfigOptions()), synchronizerConfiguration, miningParameters, - nodeKeys); + nodeKeys, + metricsSystem); } else { final String genesisConfig = ethNetworkConfig.getGenesisConfig(); final GenesisConfigFile genesisConfigFile = GenesisConfigFile.fromConfig(genesisConfig); @@ -101,7 +109,8 @@ public class PantheonControllerBuilder { syncWithOttoman, ethNetworkConfig.getNetworkId(), miningParameters, - nodeKeys); + nodeKeys, + metricsSystem); } } } diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java index c2bd2558c3..28c44cbf9e 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java @@ -54,6 +54,7 @@ import tech.pegasys.pantheon.ethereum.p2p.api.ProtocolManager; import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.IOException; import java.time.Clock; @@ -104,7 +105,8 @@ public class CliquePantheonController implements PantheonController init( @@ -101,14 +105,15 @@ public class IbftLegacyPantheonController implements PantheonController protocolSchedule = IbftProtocolSchedule.create(genesisConfig.getConfigOptions()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final BlockchainStorage blockchainStorage = storageProvider.createBlockchainStorage(protocolSchedule); final MutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage); + new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); final WorldStateStorage worldStateStorage = storageProvider.createWorldStateStorage(); final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); @@ -159,7 +164,8 @@ public class IbftLegacyPantheonController implements PantheonController { @@ -183,7 +189,8 @@ public class IbftLegacyPantheonController implements PantheonController { final SynchronizerConfiguration taintedSyncConfig, final MiningParameters miningParams, final int networkId, - final KeyPair nodeKeys) { + final KeyPair nodeKeys, + final MetricsSystem metricsSystem) { final ProtocolSchedule protocolSchedule = IbftProtocolSchedule.create(genesisConfig.getConfigOptions()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final BlockchainStorage blockchainStorage = storageProvider.createBlockchainStorage(protocolSchedule); final MutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage); + new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); final WorldStateStorage worldStateStorage = storageProvider.createWorldStateStorage(); final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); @@ -160,7 +162,8 @@ public class IbftPantheonController implements PantheonController { protocolSchedule, protocolContext, ethProtocolManager.ethContext(), - syncState); + syncState, + metricsSystem); final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java index fcc4353608..90e135620d 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java @@ -41,6 +41,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.p2p.api.ProtocolManager; import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.IOException; import java.time.Clock; @@ -90,13 +91,14 @@ public class MainnetPantheonController implements PantheonController { final ProtocolSchedule protocolSchedule, final SynchronizerConfiguration taintedSyncConfig, final MiningParameters miningParams, - final KeyPair nodeKeys) { + final KeyPair nodeKeys, + final MetricsSystem metricsSystem) { final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); final BlockchainStorage blockchainStorage = storageProvider.createBlockchainStorage(protocolSchedule); final MutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage); + new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); final WorldStateArchive worldStateArchive = new WorldStateArchive(storageProvider.createWorldStateStorage()); @@ -125,7 +127,8 @@ public class MainnetPantheonController implements PantheonController { protocolSchedule, protocolContext, ethProtocolManager.ethContext(), - syncState); + syncState, + metricsSystem); final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java index af57b872ed..c4d229e205 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java @@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; import java.io.Closeable; import java.util.Collection; @@ -45,7 +46,8 @@ public interface PantheonController extends Closeable { final boolean ottomanTestnetOperation, final int networkId, final MiningParameters miningParameters, - final KeyPair nodeKeys) { + final KeyPair nodeKeys, + final MetricsSystem metricsSystem) { final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions(); @@ -56,10 +58,17 @@ public interface PantheonController extends Closeable { MainnetProtocolSchedule.fromConfig(configOptions), syncConfig, miningParameters, - nodeKeys); + nodeKeys, + metricsSystem); } else if (configOptions.isRevisedIbft()) { return IbftPantheonController.init( - storageProvider, genesisConfigFile, syncConfig, miningParameters, networkId, nodeKeys); + storageProvider, + genesisConfigFile, + syncConfig, + miningParameters, + networkId, + nodeKeys, + metricsSystem); } else if (configOptions.isIbft()) { return IbftLegacyPantheonController.init( storageProvider, @@ -67,10 +76,17 @@ public interface PantheonController extends Closeable { syncConfig, ottomanTestnetOperation, networkId, - nodeKeys); + nodeKeys, + metricsSystem); } else if (configOptions.isClique()) { return CliquePantheonController.init( - storageProvider, genesisConfigFile, syncConfig, miningParameters, networkId, nodeKeys); + storageProvider, + genesisConfigFile, + syncConfig, + miningParameters, + networkId, + nodeKeys, + metricsSystem); } else { throw new IllegalArgumentException("Unknown consensus mechanism defined"); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java index 166f0e24f6..add7efdb05 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java @@ -37,6 +37,8 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.ethereum.storage.StorageProvider; import tech.pegasys.pantheon.ethereum.storage.keyvalue.RocksDbStorageProvider; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.util.uint.UInt256; import java.io.IOException; @@ -93,6 +95,7 @@ public final class RunnerTest { // .fastSyncPivotDistance(blockCount / 2).build(); .fastSyncPivotDistance(0) .build(); + final MetricsSystem noOpMetricsSystem = new NoOpMetricsSystem(); // Setup state with block data try (final PantheonController controller = @@ -102,7 +105,8 @@ public final class RunnerTest { MainnetProtocolSchedule.create(), fastSyncConfig, new MiningParametersTestBuilder().enabled(false).build(), - aheadDbNodeKeys)) { + aheadDbNodeKeys, + noOpMetricsSystem)) { setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext()); } @@ -114,7 +118,8 @@ public final class RunnerTest { MainnetProtocolSchedule.create(), fastSyncConfig, new MiningParametersTestBuilder().enabled(false).build(), - aheadDbNodeKeys); + aheadDbNodeKeys, + noOpMetricsSystem); final String listenHost = InetAddress.getLoopbackAddress().getHostAddress(); final ExecutorService executorService = Executors.newFixedThreadPool(2); final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration(); @@ -127,6 +132,7 @@ public final class RunnerTest { .discoveryHost(listenHost) .discoveryPort(0) .maxPeers(3) + .metricsSystem(noOpMetricsSystem) .bannedNodeIds(Collections.emptySet()); final Runner runnerAhead = @@ -152,7 +158,8 @@ public final class RunnerTest { MainnetProtocolSchedule.create(), fastSyncConfig, new MiningParametersTestBuilder().enabled(false).build(), - KeyPair.generate()); + KeyPair.generate(), + noOpMetricsSystem); final Runner runnerBehind = runnerBuilder .pantheonController(controllerBehind) @@ -166,6 +173,7 @@ public final class RunnerTest { .jsonRpcConfiguration(behindJsonRpcConfiguration) .webSocketConfiguration(behindWebSocketConfiguration) .dataDir(temp.newFolder().toPath()) + .metricsSystem(noOpMetricsSystem) .build(); executorService.submit(runnerBehind::execute); diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java index b8a668eafd..d477ce1029 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java @@ -85,6 +85,7 @@ public abstract class CommandTestAbstract { when(mockControllerBuilder.miningParameters(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.devMode(anyBoolean())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.nodePrivateKeyFile(any())).thenReturn(mockControllerBuilder); + when(mockControllerBuilder.metricsSystem(any())).thenReturn(mockControllerBuilder); when(mockSyncConfBuilder.build()).thenReturn(mockSyncConf); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java index 4993ec775f..8f96e0da85 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java @@ -102,6 +102,7 @@ public class PantheonCommandTest extends CommandTestAbstract { when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.dataDir(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.bannedNodeIds(any())).thenReturn(mockRunnerBuilder); + when(mockRunnerBuilder.metricsSystem(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.build()).thenReturn(mockRunner); } diff --git a/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java b/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java index 32344c044c..d06b86bb88 100644 --- a/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java +++ b/pantheon/src/test/java/tech/pegasys/pantheon/util/BlockImporterTest.java @@ -21,6 +21,7 @@ import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; +import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.testutil.BlockTestUtil; import tech.pegasys.pantheon.util.uint.UInt256; @@ -53,7 +54,8 @@ public final class BlockImporterTest { false, 1, new MiningParametersTestBuilder().enabled(false).build(), - KeyPair.generate()); + KeyPair.generate(), + new NoOpMetricsSystem()); final BlockImporter.ImportResult result = blockImporter.importBlockchain(source, targetController); assertThat(result.count).isEqualTo(1000); @@ -83,7 +85,8 @@ public final class BlockImporterTest { false, 10, new MiningParametersTestBuilder().enabled(false).build(), - KeyPair.generate()); + KeyPair.generate(), + new NoOpMetricsSystem()); final BlockImporter.ImportResult result = blockImporter.importBlockchain(source, controller); assertThat(result.count).isEqualTo(959);