Skip to content

Commit

Permalink
Fix registering new metric categories from plugins
Browse files Browse the repository at this point in the history
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
  • Loading branch information
fab-10 committed Oct 29, 2024
1 parent f82bb7d commit 9f04a46
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 174 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Add a method to get all the transaction in the pool, to the `TransactionPoolService`, to easily access the transaction pool content from plugins [#7813](https://github.com/hyperledger/besu/pull/7813)

### Bug fixes
- Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825)

## 24.10.0

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright contributors to Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.plugins;

import org.hyperledger.besu.plugin.BesuContext;
import org.hyperledger.besu.plugin.BesuPlugin;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;

import java.util.Locale;
import java.util.Optional;

import com.google.auto.service.AutoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@AutoService(BesuPlugin.class)
public class TestMetricsPlugin implements BesuPlugin {
private static final Logger LOG = LoggerFactory.getLogger(TestMetricsPlugin.class);
private BesuContext besuContext;

@Override
public void register(final BesuContext context) {
LOG.info("Registering TestMetricsPlugin");
besuContext = context;
context
.getService(MetricCategoryRegistry.class)
.orElseThrow()
.addMetricCategory(TestMetricCategory.TEST_METRIC_CATEGORY);
}

@Override
public void start() {
LOG.info("Starting TestMetricsPlugin");
besuContext
.getService(MetricsSystem.class)
.orElseThrow()
.createGauge(
TestMetricCategory.TEST_METRIC_CATEGORY,
"test_metric",
"Returns 1 on succes",
() -> 1.0);
}

@Override
public void stop() {
LOG.info("Stopping TestMetricsPlugin");
}

public enum TestMetricCategory implements MetricCategory {
TEST_METRIC_CATEGORY;

@Override
public String getName() {
return name().toLowerCase(Locale.ROOT);
}

@Override
public Optional<String> getApplicationPrefix() {
return Optional.of("plugin_test_");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright contributors to Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.tests.acceptance.plugins;

import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.tests.acceptance.plugins.TestMetricsPlugin.TestMetricCategory.TEST_METRIC_CATEGORY;

import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Set;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class MetricsPluginTest extends AcceptanceTestBase {
private BesuNode node;
private MetricsConfiguration metricsConfiguration;

@BeforeEach
public void setUp() throws Exception {
metricsConfiguration =
MetricsConfiguration.builder()
.enabled(true)
.port(0)
.metricCategories(Set.of(TEST_METRIC_CATEGORY))
.build();
node =
besu.create(
new BesuNodeConfigurationBuilder()
.name("node1")
.plugins(List.of("testPlugins"))
.metricsConfiguration(metricsConfiguration)
.build());

cluster.start(node);
}

@Test
public void metricCategoryAdded() throws IOException, InterruptedException {
final var httpClient = HttpClient.newHttpClient();
final var req = HttpRequest.newBuilder(URI.create(node.metricsHttpUrl().get())).build();
final var resp = httpClient.send(req, HttpResponse.BodyHandlers.ofLines());
assertThat(resp.statusCode()).isEqualTo(200);
final var foundMetric =
resp.body()
.filter(
line -> line.startsWith(TEST_METRIC_CATEGORY.getApplicationPrefix().orElseThrow()))
.findFirst()
.orElseThrow();
assertThat(foundMetric).endsWith("1.0");
}
}
18 changes: 7 additions & 11 deletions besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.cli.config.ProfilesCompletionCandidates;
import org.hyperledger.besu.cli.converter.MetricCategoryConverter;
import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty;
import org.hyperledger.besu.cli.error.BesuExecutionExceptionHandler;
import org.hyperledger.besu.cli.error.BesuParameterExceptionHandler;
Expand Down Expand Up @@ -170,7 +169,6 @@
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;
import org.hyperledger.besu.plugin.services.p2p.P2PService;
import org.hyperledger.besu.plugin.services.rlp.RlpConverterService;
Expand Down Expand Up @@ -332,7 +330,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private final Map<String, String> environment;
private final MetricCategoryRegistryImpl metricCategoryRegistry =
new MetricCategoryRegistryImpl();
private final MetricCategoryConverter metricCategoryConverter = new MetricCategoryConverter();

private final PreSynchronizationTaskRunner preSynchronizationTaskRunner =
new PreSynchronizationTaskRunner();
Expand Down Expand Up @@ -1136,10 +1133,6 @@ private void registerConverters() {
commandLine.registerConverter(Hash.class, Hash::fromHexString);
commandLine.registerConverter(Optional.class, Optional::of);
commandLine.registerConverter(Double.class, Double::parseDouble);

metricCategoryConverter.addCategories(BesuMetricCategory.class);
metricCategoryConverter.addCategories(StandardMetricCategory.class);
commandLine.registerConverter(MetricCategory.class, metricCategoryConverter);
}

private void handleStableOptions() {
Expand Down Expand Up @@ -1174,6 +1167,9 @@ private void preparePlugins() {
besuPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine));
besuPluginContext.addService(SecurityModuleService.class, securityModuleService);
besuPluginContext.addService(StorageService.class, storageService);

metricCategoryRegistry.addCategories(BesuMetricCategory.class);
metricCategoryRegistry.addCategories(StandardMetricCategory.class);
besuPluginContext.addService(MetricCategoryRegistry.class, metricCategoryRegistry);
besuPluginContext.addService(PermissioningService.class, permissioningService);
besuPluginContext.addService(PrivacyPluginService.class, privacyPluginService);
Expand All @@ -1191,10 +1187,6 @@ private void preparePlugins() {
rocksDBPlugin.register(besuPluginContext);
new InMemoryStoragePlugin().register(besuPluginContext);

metricCategoryRegistry
.getMetricCategories()
.forEach(metricCategoryConverter::addRegistryCategory);

// register default security module
securityModuleService.register(
DEFAULT_SECURITY_MODULE, Suppliers.memoize(this::defaultSecurityModule));
Expand Down Expand Up @@ -1891,6 +1883,10 @@ public MetricsConfiguration metricsConfiguration() {
"--metrics-push-interval",
"--metrics-push-prometheus-job"));

metricsOptions.setMetricCategoryRegistry(metricCategoryRegistry);

metricsOptions.validate(commandLine);

final MetricsConfiguration.Builder metricsConfigurationBuilder =
metricsOptions.toDomainObject();
metricsConfigurationBuilder
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.cli.options.stable;

import static com.google.common.base.Preconditions.checkState;
import static java.util.stream.Collectors.toUnmodifiableSet;
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP;
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_INTEGER_FORMAT_HELP;
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP;
Expand All @@ -24,6 +26,7 @@

import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.metrics.MetricCategoryRegistryImpl;
import org.hyperledger.besu.metrics.MetricsProtocol;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.plugin.services.metrics.MetricCategory;
Expand All @@ -36,6 +39,7 @@
/** Command line options for configuring metrics. */
// TODO: implement CLIOption<MetricsConfiguration>
public class MetricsOptions implements CLIOptions<MetricsConfiguration.Builder> {
private MetricCategoryRegistryImpl metricCategoryRegistry;

/**
* Returns a MetricsConfiguration.Builder because fields are often overridden from other domains,
Expand Down Expand Up @@ -77,7 +81,11 @@ public static MetricsOptions fromConfiguration(final MetricsConfiguration config
metricsOptions.metricsHost = config.getHost();
metricsOptions.metricsPort = config.getPort();
metricsOptions.metricsProtocol = config.getProtocol();
metricsOptions.metricCategories = config.getMetricCategories();
metricsOptions.metricCategories =
config.getMetricCategories().stream()
.map(MetricCategory::getName)
.collect(toUnmodifiableSet());
;
metricsOptions.metricsPrometheusJob = config.getPrometheusJob();
metricsOptions.isMetricsPushEnabled = config.isPushEnabled();
metricsOptions.metricsPushHost = config.getPushHost();
Expand Down Expand Up @@ -126,7 +134,8 @@ public List<String> getCLIOptions() {
arity = "1..*",
description =
"Comma separated list of categories to track metrics for (default: ${DEFAULT-VALUE})")
private Set<MetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
private Set<String> metricCategories =
DEFAULT_METRIC_CATEGORIES.stream().map(MetricCategory::getName).collect(toUnmodifiableSet());

@CommandLine.Option(
names = {"--metrics-push-enabled"},
Expand Down Expand Up @@ -216,7 +225,12 @@ public Integer getMetricsPort() {
* @return the metric categories
*/
public Set<MetricCategory> getMetricCategories() {
return metricCategories;
checkState(
metricCategoryRegistry != null, "Set metricCategoryRegistry before calling this method");

return metricCategories.stream()
.map(metricCategoryRegistry::getMetricCategory)
.collect(toUnmodifiableSet());
}

/**
Expand Down Expand Up @@ -264,6 +278,33 @@ public String getMetricsPrometheusJob() {
return metricsPrometheusJob;
}

/**
* Perform final validation after all the options, and the metric category registry, have been set
*
* @param commandLine the command line
*/
public void validate(final CommandLine commandLine) {
checkState(
metricCategoryRegistry != null, "Set metricCategoryRegistry before calling this method");
final var unknownCategories =
metricCategories.stream()
.filter(category -> !metricCategoryRegistry.containsMetricCategory(category))
.toList();
if (!unknownCategories.isEmpty()) {
throw new CommandLine.ParameterException(
commandLine, "--metrics-categories contains unknown categories: " + unknownCategories);
}
}

/**
* Set the metric category registry in order to support verification and conversion
*
* @param metricCategoryRegistry the metric category registry
*/
public void setMetricCategoryRegistry(final MetricCategoryRegistryImpl metricCategoryRegistry) {
this.metricCategoryRegistry = metricCategoryRegistry;
}

@CommandLine.ArgGroup(validate = false)
private final MetricsOptions.Unstable unstableOptions = new MetricsOptions.Unstable();

Expand Down
Loading

0 comments on commit 9f04a46

Please sign in to comment.