Skip to content

Commit

Permalink
Generalize histogram metrics in a single class and check for category…
Browse files Browse the repository at this point in the history
… enabled

Signed-off-by: Fabio Di Fabio <[email protected]>
  • Loading branch information
fab-10 committed Oct 31, 2024
1 parent 5bbcc85 commit 1564c77
Show file tree
Hide file tree
Showing 15 changed files with 330 additions and 270 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ private BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis(
.metricsConfiguration(
MetricsConfiguration.builder()
.enabled(true)
.metricCategories(Set.of(LineaMetricCategory.PROFITABILITY))
.metricCategories(Set.of(LineaMetricCategory.SEQUENCER_PROFITABILITY))
.build())
.requestedPlugins(
List.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package linea.plugin.acc.test.extradata;

import static java.util.Map.entry;
import static net.consensys.linea.metrics.LineaMetricCategory.PRICING_CONF;
import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
Expand All @@ -23,7 +24,6 @@

import linea.plugin.acc.test.LineaPluginTestBase;
import linea.plugin.acc.test.TestCommandLineOptionsBuilder;
import net.consensys.linea.metrics.LineaMetricCategory;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
Expand Down Expand Up @@ -125,24 +125,17 @@ public void updateProfitabilityParamsViaExtraData() throws IOException, Interrup
assertThat(getTxPoolContent()).isEmpty();

final var fixedCostMetric =
getMetricValue(
LineaMetricCategory.PROFITABILITY, "conf", List.of(entry("field", "fixed_cost_wei")));
getMetricValue(PRICING_CONF, "conf", List.of(entry("field", "fixed_cost_wei")));

assertThat(fixedCostMetric).isEqualTo(MIN_GAS_PRICE.multiply(2).getValue().doubleValue());

final var variableCostMetric =
getMetricValue(
LineaMetricCategory.PROFITABILITY,
"conf",
List.of(entry("field", "variable_cost_wei")));
getMetricValue(PRICING_CONF, "conf", List.of(entry("field", "variable_cost_wei")));

assertThat(variableCostMetric).isEqualTo(MIN_GAS_PRICE.getValue().doubleValue());

final var ethGasPriceMetric =
getMetricValue(
LineaMetricCategory.PROFITABILITY,
"conf",
List.of(entry("field", "eth_gas_price_wei")));
getMetricValue(PRICING_CONF, "conf", List.of(entry("field", "eth_gas_price_wei")));

assertThat(ethGasPriceMetric).isEqualTo(MIN_GAS_PRICE.getValue().doubleValue());
}
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
releaseVersion=0.8.0-rc4.1-local
besuVersion=24.10-develop-829db23
releaseVersion=0.8.0-rc4.1
besuVersion=24.10-local
arithmetizationVersion=0.8.0-rc4
besuArtifactGroup=io.consensys.linea-besu
distributionIdentifier=linea-sequencer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import net.consensys.linea.config.LineaTransactionPoolValidatorConfiguration;
import net.consensys.linea.config.LineaTransactionSelectorCliOptions;
import net.consensys.linea.config.LineaTransactionSelectorConfiguration;
import net.consensys.linea.metrics.LineaMetricCategory;
import net.consensys.linea.plugins.AbstractLineaSharedOptionsPlugin;
import net.consensys.linea.plugins.LineaOptionsPluginConfiguration;
import org.hyperledger.besu.plugin.BesuContext;
Expand All @@ -59,6 +58,7 @@ public abstract class AbstractLineaSharedPrivateOptionsPlugin
extends AbstractLineaSharedOptionsPlugin {
protected static BlockchainService blockchainService;
protected static MetricsSystem metricsSystem;
protected static MetricCategoryRegistry metricCategoryRegistry;

private static final AtomicBoolean sharedRegisterTasksDone = new AtomicBoolean(false);
private static final AtomicBoolean sharedStartTasksDone = new AtomicBoolean(false);
Expand Down Expand Up @@ -143,13 +143,13 @@ protected static void performSharedRegisterTasksOnce(final BesuContext context)
new RuntimeException(
"Failed to obtain BlockchainService from the BesuContext."));

context
.getService(MetricCategoryRegistry.class)
.orElseThrow(
() ->
new RuntimeException(
"Failed to obtain MetricCategoryRegistry from the BesuContext."))
.addMetricCategory(LineaMetricCategory.PROFITABILITY);
metricCategoryRegistry =
context
.getService(MetricCategoryRegistry.class)
.orElseThrow(
() ->
new RuntimeException(
"Failed to obtain MetricCategoryRegistry from the BesuContext."));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@

package net.consensys.linea.extradata;

import static net.consensys.linea.metrics.LineaMetricCategory.PRICING_CONF;

import java.util.concurrent.atomic.AtomicBoolean;

import com.google.auto.service.AutoService;
import lombok.extern.slf4j.Slf4j;
import net.consensys.linea.AbstractLineaRequiredPlugin;
import net.consensys.linea.config.LineaProfitabilityConfiguration;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.plugin.BesuContext;
import org.hyperledger.besu.plugin.BesuPlugin;
import org.hyperledger.besu.plugin.data.AddedBlockContext;
Expand All @@ -46,6 +47,8 @@ public void doRegister(final BesuContext context) {
() ->
new RuntimeException(
"Failed to obtain RpcEndpointService from the BesuContext."));

metricCategoryRegistry.addMetricCategory(PRICING_CONF);
}

/**
Expand Down Expand Up @@ -94,16 +97,15 @@ public synchronized void onInitialSyncRestart() {
});
}

initMetrics(profitabilityConfiguration());
if (metricCategoryRegistry.isMetricCategoryEnabled(PRICING_CONF)) {
initMetrics(profitabilityConfiguration());
}
}

private void initMetrics(final LineaProfitabilityConfiguration lineaProfitabilityConfiguration) {
final var confLabelledGauge =
metricsSystem.createLabelledGauge(
BesuMetricCategory.ETHEREUM,
"conf",
"Profitability configuration values at runtime",
"field");
PRICING_CONF, "values", "Profitability configuration values at runtime", "field");
confLabelledGauge.labels(lineaProfitabilityConfiguration::fixedCostWei, "fixed_cost_wei");
confLabelledGauge.labels(lineaProfitabilityConfiguration::variableCostWei, "variable_cost_wei");
confLabelledGauge.labels(lineaProfitabilityConfiguration::ethGasPriceWei, "eth_gas_price_wei");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright Consensys Software Inc.
*
* 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 net.consensys.linea.metrics;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Histogram;
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;

@Slf4j
public class HistogramMetrics {

public interface LabelValue {
String value();
}

private static final double[] DEFAULT_HISTOGRAM_BUCKETS = {0.9, 1.0, 1.2, 2, 5, 10, 100, 1000};
private static final String LABEL_VALUES_SEPARATOR = "\u2060";
private final LabelledMetric<Histogram> histogram;
private final Map<String, Double> mins;
private final Map<String, Double> maxs;

@SafeVarargs
public HistogramMetrics(
final MetricsSystem metricsSystem,
final LineaMetricCategory category,
final String name,
final String help,
final Class<? extends LabelValue>... labels) {

final var labelNames = getLabelNames(labels);

final LabelledGauge minRatio =
metricsSystem.createLabelledGauge(category, name + "_min", "Lowest " + help, labelNames);

final LabelledGauge maxRatio =
metricsSystem.createLabelledGauge(category, name + "_max", "Highest " + help, labelNames);

final var combinations = getLabelValuesCombinations(labels);
mins = HashMap.newHashMap(combinations.size());
maxs = HashMap.newHashMap(combinations.size());
for (final var combination : combinations) {
final var key = String.join(LABEL_VALUES_SEPARATOR, combination);
mins.put(key, Double.POSITIVE_INFINITY);
minRatio.labels(() -> mins.get(key), combination);
maxs.put(key, 0.0);
maxRatio.labels(() -> maxs.get(key), combination);
}

this.histogram =
metricsSystem.createLabelledHistogram(
category,
name,
StringUtils.capitalize(help) + " buckets",
DEFAULT_HISTOGRAM_BUCKETS,
labelNames);
}

@SafeVarargs
private String[] getLabelNames(final Class<? extends LabelValue>... labels) {
return Arrays.stream(labels)
.map(Class::getSimpleName)
.map(sn -> sn.toLowerCase(Locale.ROOT))
.toArray(String[]::new);
}

@SafeVarargs
private List<String[]> getLabelValuesCombinations(final Class<? extends LabelValue>... labels) {
if (labels.length == 0) {
return Collections.singletonList(new String[0]);
}
if (labels.length == 1) {
return Arrays.stream(labels[0].getEnumConstants())
.map(lv -> new String[] {lv.value()})
.toList();
}
final var head = labels[0];
final var tail = Arrays.copyOfRange(labels, 1, labels.length);
final var tailCombinations = getLabelValuesCombinations(tail);
final int newSize = tailCombinations.size() * head.getEnumConstants().length;
final List<String[]> combinations = new ArrayList<>(newSize);
for (final var headValue : head.getEnumConstants()) {
for (final var tailValues : tailCombinations) {
final var combination = new String[tailValues.length + 1];
combination[0] = headValue.value();
System.arraycopy(tailValues, 0, combination, 1, tailValues.length);
combinations.add(combination);
}
}
return combinations;
}

public void track(final double value, final String... labelValues) {

final var key = String.join(LABEL_VALUES_SEPARATOR, labelValues);

// Update lowest seen
mins.compute(key, (unused, currMin) -> Math.min(currMin, value));

// Update highest seen
maxs.compute(key, (unused, currMax) -> Math.max(currMax, value));

// Record the observation
histogram.labels(labelValues).observe(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,25 @@
*/
package net.consensys.linea.metrics;

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

import org.hyperledger.besu.plugin.services.metrics.MetricCategory;

public enum LineaMetricCategory implements MetricCategory {
/** Profitability metric category */
PROFITABILITY("profitability");
/** Sequencer profitability metric category */
SEQUENCER_PROFITABILITY,
/** Tx pool profitability metric category */
TX_POOL_PROFITABILITY,
/** Runtime pricing configuration */
PRICING_CONF;

private static final Optional<String> APPLICATION_PREFIX = Optional.of("linea_");

private final String name;

LineaMetricCategory(final String name) {
this.name = name;
LineaMetricCategory() {
this.name = name().toLowerCase(Locale.ROOT);
}

@Override
Expand Down
Loading

0 comments on commit 1564c77

Please sign in to comment.