mirror of https://github.com/hyperledger/besu
Add a labelled gauge to metrics (#2646)
The labelled gauge functionality will allow monitoring of gauge type data without creating many gauges, which can be particularly handy in tracking related data. Signed-off-by: Paul Harris <paul.harris@consensys.net> Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2661/head
parent
4a22b41c2f
commit
92955d2894
@ -0,0 +1,35 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.metrics.noop; |
||||
|
||||
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.function.DoubleSupplier; |
||||
|
||||
public class NoOpValueCollector implements LabelledGauge { |
||||
private final List<String> labelValuesCreated = new ArrayList<>(); |
||||
|
||||
@Override |
||||
public synchronized void labels(final DoubleSupplier valueSupplier, final String... labelValues) { |
||||
final String labelValuesString = String.join(",", labelValues); |
||||
if (labelValuesCreated.contains(labelValuesString)) { |
||||
throw new IllegalArgumentException( |
||||
String.format("A gauge has already been created for label values %s", labelValuesString)); |
||||
} |
||||
labelValuesCreated.add(labelValuesString); |
||||
} |
||||
} |
@ -0,0 +1,73 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.metrics.opentelemetry; |
||||
|
||||
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.metrics.AsynchronousInstrument; |
||||
import io.opentelemetry.api.metrics.Meter; |
||||
import io.opentelemetry.api.metrics.common.Labels; |
||||
import io.opentelemetry.api.metrics.common.LabelsBuilder; |
||||
|
||||
public class OpenTelemetryGauge implements LabelledGauge { |
||||
private final List<String> labelNames; |
||||
private final Map<Labels, DoubleSupplier> observationsMap = new ConcurrentHashMap<>(); |
||||
|
||||
public OpenTelemetryGauge( |
||||
final String metricName, |
||||
final String help, |
||||
final Meter meter, |
||||
final List<String> labelNames) { |
||||
this.labelNames = labelNames; |
||||
|
||||
meter |
||||
.doubleValueObserverBuilder(metricName) |
||||
.setDescription(help) |
||||
.setUpdater(this::updater) |
||||
.build(); |
||||
} |
||||
|
||||
@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 Labels labels = getLabels(labelValues); |
||||
if (observationsMap.putIfAbsent(labels, valueSupplier) != null) { |
||||
throw new IllegalStateException( |
||||
"Already registered a gauge with labels " + Arrays.toString(labelValues)); |
||||
} |
||||
} |
||||
|
||||
private Labels getLabels(final String... labelValues) { |
||||
final LabelsBuilder labelsBuilder = Labels.builder(); |
||||
for (int i = 0; i < labelNames.size(); i++) { |
||||
labelsBuilder.put(labelNames.get(i), labelValues[i]); |
||||
} |
||||
return labelsBuilder.build(); |
||||
} |
||||
|
||||
private void updater(final AsynchronousInstrument.DoubleResult doubleResult) { |
||||
observationsMap.forEach( |
||||
(labels, valueSupplier) -> doubleResult.observe(valueSupplier.getAsDouble(), labels)); |
||||
} |
||||
} |
@ -0,0 +1,63 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.metrics.prometheus; |
||||
|
||||
import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.function.DoubleSupplier; |
||||
|
||||
import io.prometheus.client.Collector; |
||||
|
||||
public class PrometheusGauge extends Collector implements LabelledGauge { |
||||
private final String metricName; |
||||
private final String help; |
||||
private final List<String> labelNames; |
||||
private final Map<List<String>, DoubleSupplier> observationsMap = new ConcurrentHashMap<>(); |
||||
|
||||
public PrometheusGauge( |
||||
final String metricName, final String help, final List<String> labelNames) { |
||||
this.metricName = metricName; |
||||
this.help = help; |
||||
this.labelNames = labelNames; |
||||
} |
||||
|
||||
@Override |
||||
public synchronized void labels(final DoubleSupplier valueSupplier, final String... labelValues) { |
||||
if (labelValues.length != labelNames.size()) { |
||||
throw new IllegalArgumentException( |
||||
"Label values and label names must be the same cardinality"); |
||||
} |
||||
if (observationsMap.putIfAbsent(List.of(labelValues), valueSupplier) != null) { |
||||
final String labelValuesString = String.join(",", labelValues); |
||||
throw new IllegalArgumentException( |
||||
String.format("A gauge has already been created for label values %s", labelValuesString)); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public List<MetricFamilySamples> collect() { |
||||
final List<MetricFamilySamples.Sample> samples = new ArrayList<>(); |
||||
observationsMap.forEach( |
||||
(labels, valueSupplier) -> |
||||
samples.add( |
||||
new MetricFamilySamples.Sample( |
||||
metricName, labelNames, labels, valueSupplier.getAsDouble()))); |
||||
return List.of(new MetricFamilySamples(metricName, Type.GAUGE, help, samples)); |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.plugin.services.metrics; |
||||
|
||||
import java.util.function.DoubleSupplier; |
||||
|
||||
public interface LabelledGauge { |
||||
void labels(final DoubleSupplier valueSupplier, final String... labelValues); |
||||
} |
Loading…
Reference in new issue