From fe462896d293e878721318389aae18c2ed06030a Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 20 Nov 2024 18:42:36 +0100 Subject: [PATCH] Add support for counter metric with external supplied value (#7894) * Add support for counter metric with external supplied value Signed-off-by: Fabio Di Fabio * Update CHANGELOG Signed-off-by: Fabio Di Fabio --------- Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 3 +- .../org/hyperledger/besu/cli/BesuCommand.java | 2 +- .../eth/manager/MonitoredExecutors.java | 4 +- .../manager/peertask/PeerTaskExecutor.java | 6 +- .../transactions/TransactionPoolMetrics.java | 18 ++--- .../besu/metrics/noop/NoOpMetricsSystem.java | 51 +++++++------- .../besu/metrics/noop/NoOpValueCollector.java | 10 +-- .../opentelemetry/OpenTelemetryGauge.java | 50 ++------------ .../OpenTelemetryLabelledSuppliedMetric.java | 67 +++++++++++++++++++ .../OpenTelemetrySuppliedCounter.java | 43 ++++++++++++ .../opentelemetry/OpenTelemetrySystem.java | 20 +++++- .../prometheus/PrometheusMetricsSystem.java | 31 +++++++-- ... => PrometheusSuppliedValueCollector.java} | 26 +++---- .../besu/metrics/StubMetricsSystem.java | 15 ++++- .../OpenTelemetryMetricsSystemTest.java | 6 +- .../PrometheusMetricsSystemTest.java | 10 +-- plugin-api/build.gradle | 2 +- .../besu/plugin/services/MetricsSystem.java | 57 +++++++++++++++- .../services/metrics/LabelledGauge.java | 30 ++------- .../metrics/LabelledSuppliedMetric.java | 28 ++++++++ 20 files changed, 326 insertions(+), 153 deletions(-) create mode 100644 metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryLabelledSuppliedMetric.java create mode 100644 metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySuppliedCounter.java rename metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/{PrometheusGauge.java => PrometheusSuppliedValueCollector.java} (76%) create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledSuppliedMetric.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2efa312d263..28d0a874427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ # Changelog ## [Unreleased] -- Added isLabelsObserved to LabelledGauge in plugin-api. Default implementation returns false. ### Breaking Changes - Removed Retesteth rpc service and commands [#7833](https://github.com/hyperledger/besu/pull/7783) ### Upcoming Breaking Changes +- `MetricSystem::createLabelledGauge` is deprecated and will be removed in a future release, replace it with `MetricSystem::createLabelledSuppliedGauge` ### Additions and Improvements - Fine tune already seen txs tracker when a tx is removed from the pool [#7755](https://github.com/hyperledger/besu/pull/7755) @@ -16,6 +16,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) - Add a method to check if a metric category is enabled to the plugin API [#7832](https://github.com/hyperledger/besu/pull/7832) - Add account and state overrides to `eth_call` and `eth_estimateGas` [#7801](https://github.com/hyperledger/besu/pull/7801) +- Add a new metric collector for counters which get their value from suppliers [#7894](https://github.com/hyperledger/besu/pull/7894) ### Bug fixes - Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 9126bc8a2a7..f817dfb8a69 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1332,7 +1332,7 @@ private void validatePrivacyPluginOptions() { private void setReleaseMetrics() { besuComponent .getMetricsSystem() - .createLabelledGauge( + .createLabelledSuppliedGauge( StandardMetricCategory.PROCESS, "release", "Release information", "version") .labels(() -> 1, BesuInfo.version()); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MonitoredExecutors.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MonitoredExecutors.java index bf2389c1a85..02514db1e7b 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MonitoredExecutors.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/MonitoredExecutors.java @@ -153,13 +153,13 @@ private static T newMonitoredExecutor( "Current number of threads in the thread pool", executor::getPoolSize); - metricsSystem.createLongGauge( + metricsSystem.createCounter( BesuMetricCategory.EXECUTORS, metricName + "_completed_tasks_total", "Total number of tasks executed", executor::getCompletedTaskCount); - metricsSystem.createLongGauge( + metricsSystem.createCounter( BesuMetricCategory.EXECUTORS, metricName + "_submitted_tasks_total", "Total number of tasks executed", diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java index a2ae0455263..c8eed6e1f1f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java @@ -20,8 +20,8 @@ import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; import java.util.Collection; @@ -43,7 +43,7 @@ public class PeerTaskExecutor { private final LabelledMetric timeoutCounter; private final LabelledMetric invalidResponseCounter; private final LabelledMetric internalExceptionCounter; - private final LabelledGauge inflightRequestGauge; + private final LabelledSuppliedMetric inflightRequestGauge; private final Map inflightRequestCountByClassName; public PeerTaskExecutor( @@ -77,7 +77,7 @@ public PeerTaskExecutor( "Counter of the number of internal exceptions occurred", "taskName"); inflightRequestGauge = - metricsSystem.createLabelledGauge( + metricsSystem.createLabelledSuppliedGauge( BesuMetricCategory.PEERS, "inflight_request_gauge", "Gauge of the number of inflight requests", diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolMetrics.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolMetrics.java index fac9b3174d0..6f116d3b88f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolMetrics.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolMetrics.java @@ -22,8 +22,8 @@ import org.hyperledger.besu.metrics.RunnableCounter; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import java.util.HashMap; import java.util.Map; @@ -47,10 +47,10 @@ public class TransactionPoolMetrics { private final LabelledMetric removedCounter; private final LabelledMetric rejectedCounter; private final LabelledMetric penalizedCounter; - private final LabelledGauge spaceUsed; - private final LabelledGauge transactionCount; - private final LabelledGauge transactionCountByType; - private final LabelledGauge uniqueSenderCount; + private final LabelledSuppliedMetric spaceUsed; + private final LabelledSuppliedMetric transactionCount; + private final LabelledSuppliedMetric transactionCountByType; + private final LabelledSuppliedMetric uniqueSenderCount; private final LabelledMetric expiredMessagesCounter; private final Map expiredMessagesRunnableCounters = new HashMap<>(); private final LabelledMetric alreadySeenTransactionsCounter; @@ -103,21 +103,21 @@ public TransactionPoolMetrics(final MetricsSystem metricsSystem) { "layer"); spaceUsed = - metricsSystem.createLabelledGauge( + metricsSystem.createLabelledSuppliedGauge( BesuMetricCategory.TRANSACTION_POOL, "space_used", "The amount of space used by the transactions in the layer", "layer"); transactionCount = - metricsSystem.createLabelledGauge( + metricsSystem.createLabelledSuppliedGauge( BesuMetricCategory.TRANSACTION_POOL, "number_of_transactions", "The number of transactions currently present in the layer", "layer"); transactionCountByType = - metricsSystem.createLabelledGauge( + metricsSystem.createLabelledSuppliedGauge( BesuMetricCategory.TRANSACTION_POOL, "number_of_transactions_by_type", "The number of transactions, of a specified type, currently present in the layer", @@ -125,7 +125,7 @@ public TransactionPoolMetrics(final MetricsSystem metricsSystem) { "type"); uniqueSenderCount = - metricsSystem.createLabelledGauge( + metricsSystem.createLabelledSuppliedGauge( BesuMetricCategory.TRANSACTION_POOL, "unique_senders", "The number of senders with at least one transaction currently present in the layer", diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpMetricsSystem.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpMetricsSystem.java index d3b6c4aadc5..68b5d52ffa3 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpMetricsSystem.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpMetricsSystem.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.plugin.services.metrics.ExternalSummary; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; @@ -41,7 +42,7 @@ public class NoOpMetricsSystem implements ObservableMetricsSystem { public static final Counter NO_OP_COUNTER = new NoOpCounter(); /** The constant NO_OP_GAUGE. */ - public static final LabelledGauge NO_OP_GAUGE = new NoOpValueCollector(); + public static final LabelledSuppliedMetric NO_OP_GAUGE = new NoOpValueCollector(); private static final OperationTimer.TimingContext NO_OP_TIMING_CONTEXT = () -> 0; @@ -65,16 +66,16 @@ public class NoOpMetricsSystem implements ObservableMetricsSystem { new LabelCountingNoOpMetric<>(1, NO_OP_OPERATION_TIMER); /** The constant NO_OP_LABELLED_1_GAUGE. */ - public static final LabelledGauge NO_OP_LABELLED_1_GAUGE = - new LabelledGaugeNoOpMetric(1, NO_OP_GAUGE); + public static final LabelledSuppliedMetric NO_OP_LABELLED_1_GAUGE = + new LabelledSuppliedNoOpMetric(1, NO_OP_GAUGE); /** The constant NO_OP_LABELLED_2_GAUGE. */ - public static final LabelledGauge NO_OP_LABELLED_2_GAUGE = - new LabelledGaugeNoOpMetric(2, NO_OP_GAUGE); + public static final LabelledSuppliedMetric NO_OP_LABELLED_2_GAUGE = + new LabelledSuppliedNoOpMetric(2, NO_OP_GAUGE); /** The constant NO_OP_LABELLED_3_GAUGE. */ - public static final LabelledGauge NO_OP_LABELLED_3_GAUGE = - new LabelledGaugeNoOpMetric(3, NO_OP_GAUGE); + public static final LabelledSuppliedMetric NO_OP_LABELLED_3_GAUGE = + new LabelledSuppliedNoOpMetric(3, NO_OP_GAUGE); /** Default constructor */ public NoOpMetricsSystem() {} @@ -159,12 +160,21 @@ public void createGuavaCacheCollector( final MetricCategory category, final String name, final Cache cache) {} @Override - public LabelledGauge createLabelledGauge( + public LabelledSuppliedMetric createLabelledSuppliedCounter( final MetricCategory category, final String name, final String help, final String... labelNames) { - return getLabelledGauge(labelNames.length); + return getLabelledSuppliedMetric(labelNames.length); + } + + @Override + public LabelledSuppliedMetric createLabelledSuppliedGauge( + final MetricCategory category, + final String name, + final String help, + final String... labelNames) { + return getLabelledSuppliedMetric(labelNames.length); } /** @@ -173,7 +183,7 @@ public LabelledGauge createLabelledGauge( * @param labelCount the label count * @return the labelled gauge */ - public static LabelledGauge getLabelledGauge(final int labelCount) { + public static LabelledSuppliedMetric getLabelledSuppliedMetric(final int labelCount) { switch (labelCount) { case 1: return NO_OP_LABELLED_1_GAUGE; @@ -182,7 +192,7 @@ public static LabelledGauge getLabelledGauge(final int labelCount) { case 3: return NO_OP_LABELLED_3_GAUGE; default: - return new LabelledGaugeNoOpMetric(labelCount, NO_OP_GAUGE); + return new LabelledSuppliedNoOpMetric(labelCount, NO_OP_GAUGE); } } @@ -237,8 +247,9 @@ public T labels(final String... labels) { } } - /** The Labelled gauge NoOp metric. */ - public static class LabelledGaugeNoOpMetric implements LabelledGauge { + /** The Labelled supplied NoOp metric. */ + @SuppressWarnings("removal") // remove when deprecated LabelledGauge is removed + public static class LabelledSuppliedNoOpMetric implements LabelledSuppliedMetric, LabelledGauge { /** The Label count. */ final int labelCount; @@ -251,13 +262,14 @@ public static class LabelledGaugeNoOpMetric implements LabelledGauge { * @param labelCount the label count * @param fakeMetric the fake metric */ - public LabelledGaugeNoOpMetric(final int labelCount, final LabelledGauge fakeMetric) { + public LabelledSuppliedNoOpMetric( + final int labelCount, final LabelledSuppliedMetric fakeMetric) { this.labelCount = labelCount; this.fakeMetric = fakeMetric; } /** The Fake metric. */ - final LabelledGauge fakeMetric; + final LabelledSuppliedMetric fakeMetric; @Override public void labels(final DoubleSupplier valueSupplier, final String... labelValues) { @@ -270,14 +282,5 @@ public void labels(final DoubleSupplier valueSupplier, final String... labelValu "The count of labels used must match the count of labels expected."); Preconditions.checkNotNull(valueSupplier, "No valueSupplier specified"); } - - @Override - public boolean isLabelsObserved(final String... labelValues) { - Preconditions.checkArgument( - labelValues.length == labelCount, - "The count of labels used must match the count of labels expected."); - final String labelValuesString = String.join(",", labelValues); - return labelValuesCache.contains(labelValuesString); - } } } diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpValueCollector.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpValueCollector.java index 6f36f10d2c7..3db34babe42 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpValueCollector.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/noop/NoOpValueCollector.java @@ -14,14 +14,14 @@ */ package org.hyperledger.besu.metrics.noop; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import java.util.ArrayList; import java.util.List; import java.util.function.DoubleSupplier; /** The NoOp value collector. */ -public class NoOpValueCollector implements LabelledGauge { +public class NoOpValueCollector implements LabelledSuppliedMetric { private final List labelValuesCreated = new ArrayList<>(); /** Default constructor */ @@ -36,10 +36,4 @@ public synchronized void labels(final DoubleSupplier valueSupplier, final String } labelValuesCreated.add(labelValuesString); } - - @Override - public boolean isLabelsObserved(final String... labelValues) { - final String labelValuesString = String.join(",", labelValues); - return labelValuesCreated.contains(labelValuesString); - } } diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryGauge.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryGauge.java index e1d785c68ec..4f250cbd92d 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryGauge.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryGauge.java @@ -16,23 +16,14 @@ import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; -import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.DoubleSupplier; -import com.google.common.base.Preconditions; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; /** The Open telemetry gauge. */ -public class OpenTelemetryGauge implements LabelledGauge { - private final List labelNames; - private final Map observationsMap = new ConcurrentHashMap<>(); - +@SuppressWarnings("removal") // remove when deprecated LabelledGauge is removed +public class OpenTelemetryGauge extends OpenTelemetryLabelledSuppliedMetric + implements LabelledGauge { /** * Instantiates a new Open telemetry gauge. * @@ -46,41 +37,8 @@ public OpenTelemetryGauge( final String help, final Meter meter, final List labelNames) { - this.labelNames = labelNames; + super(labelNames); meter.gaugeBuilder(metricName).setDescription(help).buildWithCallback(this::updater); } - - @Override - public void labels(final DoubleSupplier valueSupplier, final String... labelValues) { - Preconditions.checkArgument( - labelValues.length == labelNames.size(), - "label values and label names need the same number of elements"); - final Attributes labels = getLabels(labelValues); - if (observationsMap.putIfAbsent(labels, valueSupplier) != null) { - throw new IllegalStateException( - "Already registered a gauge with labels " + Arrays.toString(labelValues)); - } - } - - @Override - public boolean isLabelsObserved(final String... labelValues) { - Preconditions.checkArgument( - labelValues.length == labelNames.size(), - "label values and label names need the same number of elements"); - return observationsMap.containsKey(getLabels(labelValues)); - } - - private Attributes getLabels(final String... labelValues) { - final AttributesBuilder labelsBuilder = Attributes.builder(); - for (int i = 0; i < labelNames.size(); i++) { - labelsBuilder.put(labelNames.get(i), labelValues[i]); - } - return labelsBuilder.build(); - } - - private void updater(final ObservableDoubleMeasurement measurement) { - observationsMap.forEach( - (labels, valueSupplier) -> measurement.record(valueSupplier.getAsDouble(), labels)); - } } diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryLabelledSuppliedMetric.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryLabelledSuppliedMetric.java new file mode 100644 index 00000000000..db48ee9b312 --- /dev/null +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryLabelledSuppliedMetric.java @@ -0,0 +1,67 @@ +/* + * 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.metrics.opentelemetry; + +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.DoubleSupplier; + +import com.google.common.base.Preconditions; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; + +abstract class OpenTelemetryLabelledSuppliedMetric implements LabelledSuppliedMetric { + private final List labelNames; + private final Map observationsMap = new ConcurrentHashMap<>(); + + public OpenTelemetryLabelledSuppliedMetric(final List labelNames) { + this.labelNames = labelNames; + } + + @Override + public void labels(final DoubleSupplier valueSupplier, final String... labelValues) { + Preconditions.checkArgument( + labelValues.length == labelNames.size(), + "label values and label names need the same number of elements"); + final Attributes labels = getLabels(labelValues); + if (observationsMap.putIfAbsent(labels, valueSupplier) != null) { + throw new IllegalStateException( + "Already registered a collector with label values " + Arrays.toString(labelValues)); + } + } + + private Attributes getLabels(final String... labelValues) { + final AttributesBuilder labelsBuilder = Attributes.builder(); + for (int i = 0; i < labelNames.size(); i++) { + labelsBuilder.put(labelNames.get(i), labelValues[i]); + } + return labelsBuilder.build(); + } + + /** + * Callback to record the supplied values + * + * @param measurement where to record the values + */ + protected void updater(final ObservableDoubleMeasurement measurement) { + observationsMap.forEach( + (labels, valueSupplier) -> measurement.record(valueSupplier.getAsDouble(), labels)); + } +} diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySuppliedCounter.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySuppliedCounter.java new file mode 100644 index 00000000000..7bfadcdc2d9 --- /dev/null +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySuppliedCounter.java @@ -0,0 +1,43 @@ +/* + * 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.metrics.opentelemetry; + +import java.util.List; + +import io.opentelemetry.api.metrics.Meter; + +/** The Open telemetry supplied counter. */ +public class OpenTelemetrySuppliedCounter extends OpenTelemetryLabelledSuppliedMetric { + /** + * Instantiates a new Open telemetry supplied counter. + * + * @param metricName the metric name + * @param help the help + * @param meter the meter + * @param labelNames the label names + */ + public OpenTelemetrySuppliedCounter( + final String metricName, + final String help, + final Meter meter, + final List labelNames) { + super(labelNames); + meter + .counterBuilder(metricName) + .setDescription(help) + .ofDoubles() + .buildWithCallback(this::updater); + } +} diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySystem.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySystem.java index a17c773813c..cc2174dff53 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySystem.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetrySystem.java @@ -21,8 +21,8 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.ExternalSummary; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; @@ -292,7 +292,21 @@ public void createGuavaCacheCollector( final MetricCategory category, final String name, final Cache cache) {} @Override - public LabelledGauge createLabelledGauge( + public LabelledSuppliedMetric createLabelledSuppliedCounter( + final MetricCategory category, + final String name, + final String help, + final String... labelNames) { + LOG.trace("Creating a labelled supplied counter {}", name); + if (isCategoryEnabled(category)) { + return new OpenTelemetrySuppliedCounter( + name, help, sdkMeterProvider.get(category.getName()), List.of(labelNames)); + } + return NoOpMetricsSystem.getLabelledSuppliedMetric(labelNames.length); + } + + @Override + public LabelledSuppliedMetric createLabelledSuppliedGauge( final MetricCategory category, final String name, final String help, @@ -302,7 +316,7 @@ public LabelledGauge createLabelledGauge( return new OpenTelemetryGauge( name, help, sdkMeterProvider.get(category.getName()), List.of(labelNames)); } - return NoOpMetricsSystem.getLabelledGauge(labelNames.length); + return NoOpMetricsSystem.getLabelledSuppliedMetric(labelNames.length); } @Override diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystem.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystem.java index b001eb0b3be..9263383b8f0 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystem.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystem.java @@ -19,8 +19,8 @@ import org.hyperledger.besu.metrics.StandardMetricCategory; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.metrics.ExternalSummary; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; @@ -240,18 +240,37 @@ public void createGuavaCacheCollector( } @Override - public LabelledGauge createLabelledGauge( + public LabelledSuppliedMetric createLabelledSuppliedCounter( final MetricCategory category, final String name, final String help, final String... labelNames) { + return createLabelledSuppliedMetric(category, Collector.Type.COUNTER, name, help, labelNames); + } + + @Override + public LabelledSuppliedMetric createLabelledSuppliedGauge( + final MetricCategory category, + final String name, + final String help, + final String... labelNames) { + return createLabelledSuppliedMetric(category, Collector.Type.GAUGE, name, help, labelNames); + } + + private LabelledSuppliedMetric createLabelledSuppliedMetric( + final MetricCategory category, + final Collector.Type type, + final String name, + final String help, + final String... labelNames) { final String metricName = convertToPrometheusName(category, name); if (isCategoryEnabled(category)) { - final PrometheusGauge gauge = new PrometheusGauge(metricName, help, List.of(labelNames)); - registerCollector(category, gauge); - return gauge; + final PrometheusSuppliedValueCollector suppliedValueCollector = + new PrometheusSuppliedValueCollector(type, metricName, help, List.of(labelNames)); + registerCollector(category, suppliedValueCollector); + return suppliedValueCollector; } - return NoOpMetricsSystem.getLabelledGauge(labelNames.length); + return NoOpMetricsSystem.getLabelledSuppliedMetric(labelNames.length); } private void registerCollector(final MetricCategory category, final Collector collector) { diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusGauge.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusSuppliedValueCollector.java similarity index 76% rename from metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusGauge.java rename to metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusSuppliedValueCollector.java index b69e3f90626..47394ffed4d 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusGauge.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/prometheus/PrometheusSuppliedValueCollector.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * 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 @@ -15,6 +15,7 @@ package org.hyperledger.besu.metrics.prometheus; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import java.util.ArrayList; import java.util.List; @@ -24,22 +25,27 @@ import io.prometheus.client.Collector; -/** The Prometheus gauge. */ -public class PrometheusGauge extends Collector implements LabelledGauge { +/** The Prometheus supplied value collector. */ +@SuppressWarnings("removal") // remove when deprecated LabelledGauge is removed +public class PrometheusSuppliedValueCollector extends Collector + implements LabelledSuppliedMetric, LabelledGauge { + private final Type type; private final String metricName; private final String help; private final List labelNames; private final Map, DoubleSupplier> observationsMap = new ConcurrentHashMap<>(); /** - * Instantiates a new Prometheus gauge. + * Instantiates a new Prometheus supplied value collector. * + * @param type the type of the collector * @param metricName the metric name * @param help the help * @param labelNames the label names */ - public PrometheusGauge( - final String metricName, final String help, final List labelNames) { + public PrometheusSuppliedValueCollector( + final Type type, final String metricName, final String help, final List labelNames) { + this.type = type; this.metricName = metricName; this.help = help; this.labelNames = labelNames; @@ -55,12 +61,6 @@ public synchronized void labels(final DoubleSupplier valueSupplier, final String } } - @Override - public boolean isLabelsObserved(final String... labelValues) { - validateLabelsCardinality(labelValues); - return observationsMap.containsKey(List.of(labelValues)); - } - @Override public List collect() { final List samples = new ArrayList<>(); @@ -69,7 +69,7 @@ public List collect() { samples.add( new MetricFamilySamples.Sample( metricName, labelNames, labels, valueSupplier.getAsDouble()))); - return List.of(new MetricFamilySamples(metricName, Type.GAUGE, help, samples)); + return List.of(new MetricFamilySamples(metricName, type, help, samples)); } private void validateLabelsCardinality(final String... labelValues) { diff --git a/metrics/core/src/test-support/java/org/hyperledger/besu/metrics/StubMetricsSystem.java b/metrics/core/src/test-support/java/org/hyperledger/besu/metrics/StubMetricsSystem.java index 13f16ef0a0c..c10c62132c1 100644 --- a/metrics/core/src/test-support/java/org/hyperledger/besu/metrics/StubMetricsSystem.java +++ b/metrics/core/src/test-support/java/org/hyperledger/besu/metrics/StubMetricsSystem.java @@ -19,8 +19,8 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.ExternalSummary; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; @@ -50,12 +50,21 @@ public LabelledMetric createLabelledCounter( } @Override - public LabelledGauge createLabelledGauge( + public LabelledSuppliedMetric createLabelledSuppliedCounter( final MetricCategory category, final String name, final String help, final String... labelNames) { - return NoOpMetricsSystem.getLabelledGauge(labelNames.length); + return NoOpMetricsSystem.getLabelledSuppliedMetric(labelNames.length); + } + + @Override + public LabelledSuppliedMetric createLabelledSuppliedGauge( + final MetricCategory category, + final String name, + final String help, + final String... labelNames) { + return NoOpMetricsSystem.getLabelledSuppliedMetric(labelNames.length); } public long getCounterValue(final String name, final String... labels) { diff --git a/metrics/core/src/test/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryMetricsSystemTest.java b/metrics/core/src/test/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryMetricsSystemTest.java index f1bff33e555..8c6dd8261d5 100644 --- a/metrics/core/src/test/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryMetricsSystemTest.java +++ b/metrics/core/src/test/java/org/hyperledger/besu/metrics/opentelemetry/OpenTelemetryMetricsSystemTest.java @@ -31,8 +31,8 @@ import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; import java.util.Collections; @@ -231,8 +231,8 @@ public void shouldCreateObservationFromGauge() { @Test public void shouldCreateLabelledGauge() { - LabelledGauge labelledGauge = - metricsSystem.createLabelledGauge(RPC, "gaugeName", "help", "a", "b"); + LabelledSuppliedMetric labelledGauge = + metricsSystem.createLabelledSuppliedGauge(RPC, "gaugeName", "help", "a", "b"); labelledGauge.labels(() -> 1.0, "a1", "b1"); labelledGauge.labels(() -> 11.0, "a2", "b2"); labelledGauge.labels(() -> 21.0, "a3", "b3"); diff --git a/metrics/core/src/test/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystemTest.java b/metrics/core/src/test/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystemTest.java index 2ddf86d347b..ba875ab79b1 100644 --- a/metrics/core/src/test/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystemTest.java +++ b/metrics/core/src/test/java/org/hyperledger/besu/metrics/prometheus/PrometheusMetricsSystemTest.java @@ -33,8 +33,8 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; import java.util.Collections; @@ -129,8 +129,8 @@ public void shouldCreateSeparateObservationsForEachCounterLabelValue() { @Test public void shouldCreateSeparateObservationsForEachLabelledGaugeValue() { - final LabelledGauge gauge = - metricsSystem.createLabelledGauge(PEERS, "test", "test help", "a", "b", "c"); + final LabelledSuppliedMetric gauge = + metricsSystem.createLabelledSuppliedGauge(PEERS, "test", "test help", "a", "b", "c"); final double value1 = 1.0; final double value2 = 11.0; @@ -145,8 +145,8 @@ public void shouldCreateSeparateObservationsForEachLabelledGaugeValue() { @Test public void shouldNotUseSameLabelsTwiceOnSameGauge() { - final LabelledGauge gauge = - metricsSystem.createLabelledGauge(PEERS, "test", "test help", "a", "b", "c"); + final LabelledSuppliedMetric gauge = + metricsSystem.createLabelledSuppliedGauge(PEERS, "test", "test help", "a", "b", "c"); final double value1 = 1.0; gauge.labels(() -> value1, "a1", "b1", "c1"); diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 2d3d5191df4..8242189db71 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'aYWbsgPoKTGDgq9d4QUBvQEaZYbKNJGMiBufzyKnusA=' + knownHash = 'ktVrmQXU7LMQi1ieb9OQ2vJNqZ0SVQ7Usauh1LMvUXY=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MetricsSystem.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MetricsSystem.java index 744bca4eb3e..f3d3f91d0a5 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MetricsSystem.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MetricsSystem.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.plugin.services.metrics.ExternalSummary; import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; +import org.hyperledger.besu.plugin.services.metrics.LabelledSuppliedMetric; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.OperationTimer; @@ -45,6 +46,23 @@ default Counter createCounter( return createLabelledCounter(category, name, help, new String[0]).labels(); } + /** + * Creates a Counter that gets its value from the specified supplier. To be used when the value of + * the counter is calculated outside the metric system. + * + * @param category The {@link MetricCategory} this counter is assigned to. + * @param name A name for this metric. + * @param help A human readable description of the metric. + * @param valueSupplier The supplier of the value. + */ + default void createCounter( + final MetricCategory category, + final String name, + final String help, + final DoubleSupplier valueSupplier) { + createLabelledSuppliedCounter(category, name, help).labels(valueSupplier); + } + /** * Creates a Counter with assigned labels. * @@ -58,7 +76,42 @@ LabelledMetric createLabelledCounter( MetricCategory category, String name, String help, String... labelNames); /** - * Creates a Gauge with assigned labels. + * Creates a Counter with assigned labels, that gets its values from suppliers. To be used when + * the values of the counter are calculated outside the metric system. + * + * @param category The {@link MetricCategory} this counter is assigned to. + * @param name A name for this metric. + * @param help A human readable description of the metric. + * @param labelNames An array of labels to assign to the Counter. + * @return The created LabelledSupplierMetric instance. + */ + LabelledSuppliedMetric createLabelledSuppliedCounter( + MetricCategory category, String name, String help, String... labelNames); + + /** + * Creates a Gauge with assigned labels, that gets its values from suppliers. To be used when the + * values of the gauge are calculated outside the metric system. + * + * @param category The {@link MetricCategory} this gauge is assigned to. + * @param name A name for this metric. + * @param help A human readable description of the metric. + * @param labelNames An array of labels to assign to the Gauge. + * @return The created LabelledGauge instance. + * @deprecated Use {@link #createLabelledSuppliedGauge(MetricCategory, String, String, String...)} + */ + @Deprecated(forRemoval = true) + @SuppressWarnings("removal") // remove when deprecated LabelledGauge is removed + default LabelledGauge createLabelledGauge( + final MetricCategory category, + final String name, + final String help, + final String... labelNames) { + return (LabelledGauge) createLabelledSuppliedGauge(category, name, help, labelNames); + } + + /** + * Creates a Gauge with assigned labels, that gets its values from suppliers. To be used when the + * values of the gauge are calculated outside the metric system. * * @param category The {@link MetricCategory} this gauge is assigned to. * @param name A name for this metric. @@ -66,7 +119,7 @@ LabelledMetric createLabelledCounter( * @param labelNames An array of labels to assign to the Gauge. * @return The created LabelledGauge instance. */ - LabelledGauge createLabelledGauge( + LabelledSuppliedMetric createLabelledSuppliedGauge( MetricCategory category, String name, String help, String... labelNames); /** diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledGauge.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledGauge.java index 5357c6505ae..f94e5231840 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledGauge.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledGauge.java @@ -14,26 +14,10 @@ */ package org.hyperledger.besu.plugin.services.metrics; -import java.util.function.DoubleSupplier; - -/** The interface Labelled gauge. */ -public interface LabelledGauge { - /** - * Labels. - * - * @param valueSupplier the value supplier - * @param labelValues the label values - */ - void labels(final DoubleSupplier valueSupplier, final String... labelValues); - - /** - * Checks whether the supplied labelValues are already observed by this LabelledGauge - * - * @param labelValues The labelValues to check - * @return true if the supplied labelValues are already observed by this LabelledGauge, false - * otherwise - */ - default boolean isLabelsObserved(final String... labelValues) { - return false; - } -} +/** + * The interface Labelled gauge. + * + * @deprecated Use {@link LabelledSuppliedMetric} + */ +@Deprecated(forRemoval = true) +public interface LabelledGauge extends LabelledSuppliedMetric {} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledSuppliedMetric.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledSuppliedMetric.java new file mode 100644 index 00000000000..755bd6787e3 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/LabelledSuppliedMetric.java @@ -0,0 +1,28 @@ +/* + * 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.plugin.services.metrics; + +import java.util.function.DoubleSupplier; + +/** The interface Labelled gauge. */ +public interface LabelledSuppliedMetric { + /** + * Labels. + * + * @param valueSupplier the value supplier + * @param labelValues the label values + */ + void labels(final DoubleSupplier valueSupplier, final String... labelValues); +}