provide a fully constructed metric type which can be registered as-is

This commit is contained in:
Jonathan Shook
2023-09-25 23:47:34 -05:00
parent 4a11e652b4
commit e9cf289787
10 changed files with 113 additions and 45 deletions

View File

@@ -63,14 +63,15 @@ public class AtomicInput implements Input, ActivityDefObserver, Gauge<Long>, NBL
this.parent = parent;
this.activityDef = activityDef;
onActivityDefUpdate(activityDef);
ActivityMetrics.gauge(this, "input_cycles_first", new NBFunctionGauge(this, () -> (double)this.cycles_min.get()));
ActivityMetrics.gauge(this, "input_cycles_last", new NBFunctionGauge(this, () -> (double)this.cycles_max.get()));
ActivityMetrics.gauge(this, "input_cycle", new NBFunctionGauge(this, () -> (double)this.cycle_value.get()));
ActivityMetrics.gauge(this, "input_cycles_total", new NBFunctionGauge(this, this::getTotalCycles));
ActivityMetrics.gauge(this, "input_recycles_first", new NBFunctionGauge(this, () -> (double)this.recycles_min.get()));
ActivityMetrics.gauge(this, "input_recycles_last", new NBFunctionGauge(this, () -> (double)this.recycles_max.get()));
ActivityMetrics.gauge(this, "input_recycle", new NBFunctionGauge(this, () -> (double) this.recycle_value.get()));
ActivityMetrics.gauge(this, "input_recycles_total", new NBFunctionGauge(this, this::getTotalRecycles));
ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycles_min.get(),"input_cycles_first"));
ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycles_max.get(), "input_cycles_last"));
ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycle_value.get(), "input_cycle"));
ActivityMetrics.register(new NBFunctionGauge(this, this::getTotalCycles, "input_cycles_total"));
ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.recycles_min.get(), "input_recycles_first"));
ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.recycles_max.get(), "input_recycles_last"));
ActivityMetrics.register(new NBFunctionGauge(this, () -> (double) this.recycle_value.get(),"input_recycle"));
ActivityMetrics.register(new NBFunctionGauge(this, this::getTotalRecycles,"input_recycles_total"));
}
private double getTotalRecycles() {

View File

@@ -98,7 +98,7 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
for (OpTemplate ot : opTemplates) {
ParsedOp incompleteOpDef = new ParsedOp(ot, NBConfiguration.empty(), List.of(), this);
String driverName = incompleteOpDef.takeOptionalStaticValue("driver", String.class)
.or(() -> incompleteOpDef.takeOptionalStaticValue("type",String.class))
.or(() -> incompleteOpDef.takeOptionalStaticValue("type", String.class))
.or(() -> defaultDriverOption)
.orElseThrow(() -> new OpConfigError("Unable to identify driver name for op template:\n" + ot));
@@ -152,12 +152,14 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
throw new OpConfigError("Error mapping workload template to operations: " + e.getMessage(), null, e);
}
this.pendingOpsGauge= ActivityMetrics.gauge(this,"ops_pending",
new NBFunctionGauge(this,() -> this.getProgressMeter().getSummary().pending()));
this.activeOpsGauge = ActivityMetrics.gauge(this,"ops_active",
new NBFunctionGauge(this,() -> this.getProgressMeter().getSummary().current()));
this.completeOpsGauge= ActivityMetrics.gauge(this,"ops_complete",
new NBFunctionGauge(this,() -> this.getProgressMeter().getSummary().complete()));
this.pendingOpsGauge = ActivityMetrics.register(
new NBFunctionGauge(this, () -> this.getProgressMeter().getSummary().pending(), "ops_pending")
);
this.activeOpsGauge = ActivityMetrics.register(
new NBFunctionGauge(this, () -> this.getProgressMeter().getSummary().current(),"ops_active")
);
this.completeOpsGauge = ActivityMetrics.register(
new NBFunctionGauge(this, () -> this.getProgressMeter().getSummary().complete(),"ops_complete"));
}
@Override
@@ -217,7 +219,7 @@ public class StandardActivity<R extends Op, S> extends SimpleActivity implements
public void shutdownActivity() {
for (Map.Entry<String, DriverAdapter> entry : adapters.entrySet()) {
String adapterName = entry.getKey();
DriverAdapter<?,?> adapter = entry.getValue();
DriverAdapter<?, ?> adapter = entry.getValue();
adapter.getSpaceCache().getElements().forEach((spaceName, space) -> {
if (space instanceof AutoCloseable autocloseable) {
try {

View File

@@ -76,10 +76,10 @@ public class ActivityMetrics {
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
private static Metric register(NBLabels labels, MetricProvider metricProvider) {
labels = labelFilter!=null ? labelFilter.apply(labels) : labels;
labels = labelFilter != null ? labelFilter.apply(labels) : labels;
labels = labelValidator != null ? labelValidator.apply(labels) : labels;
final String graphiteName = labels.linearizeValues('.',"[activity]","[space]","[op]","name");
final String graphiteName = labels.linearizeValues('.', "[activity]", "[space]", "[op]", "name");
Metric metric = get().getMetrics().get(graphiteName);
if (null == metric) {
@@ -96,6 +96,45 @@ public class ActivityMetrics {
return metric;
}
/**
* Calls to this version of register must be done with a pre-built metric instrument.
* This means that it is not suitable for lazily creating metric objects directly on
* instances which are one of many. Instead, call this to register metrics at the start
* of an owning element.
*
* This version of register expects that you have fully labeled a metric, including
* addint the 'name' field, also known as the <em>metric family name</em> in some specifications.
*
* It is due to be replaced by a different registry format soon.
*
* @param labeledMetric
* @return the metric instance
*/
public static <M extends NBLabeledMetric> M register(M labeledMetric) {
NBLabels labels = labeledMetric.getLabels();
labels = labelFilter != null ? labelFilter.apply(labels) : labels;
labels = labelValidator != null ? labelValidator.apply(labels) : labels;
final String graphiteName = labels.linearizeValues('.', "[activity]", "[space]", "[op]", "name");
Metric metric = get().getMetrics().get(graphiteName);
metric = get().getMetrics().get(graphiteName);
if (metric!=null) {
logger.warn("Metric already registered for '" + graphiteName + "', probably logic error which could invalidate metric values.");
} else {
get().register(graphiteName, labeledMetric);
}
return labeledMetric;
}
public static void unregister(NBLabeledElement element) {
final String graphiteName = element.getLabels().linearizeValues('.', "[activity]", "[space]", "[op]", "name");
if (!get().getMetrics().containsKey(graphiteName)) {
logger.warn("Removing non-extant metric by name: '"+ graphiteName + "'");
}
get().remove(graphiteName);
}
/**
* <p>Create a timer associated with an activity.</p>
*
@@ -112,7 +151,7 @@ public class ActivityMetrics {
* @return the timer, perhaps a different one if it has already been registered
*/
public static Timer timer(NBLabeledElement parent, String metricFamilyName, int hdrdigits) {
final NBLabels labels = parent.getLabels().and("name",sanitize(metricFamilyName));
final NBLabels labels = parent.getLabels().and("name", sanitize(metricFamilyName));
Timer registeredTimer = (Timer) register(labels, () ->
@@ -164,7 +203,7 @@ public class ActivityMetrics {
* @return the counter, perhaps a different one if it has already been registered
*/
public static Counter counter(NBLabeledElement parent, String metricFamilyName) {
final NBLabels labels = parent.getLabels().and("name",metricFamilyName);
final NBLabels labels = parent.getLabels().and("name", metricFamilyName);
return (Counter) register(labels, () -> new NBMetricCounter(labels));
}
@@ -180,7 +219,7 @@ public class ActivityMetrics {
* @return the meter, perhaps a different one if it has already been registered
*/
public static Meter meter(NBLabeledElement parent, String metricFamilyName) {
final NBLabels labels = parent.getLabels().and("name",sanitize(metricFamilyName));
final NBLabels labels = parent.getLabels().and("name", sanitize(metricFamilyName));
return (Meter) register(labels, () -> new NBMetricMeter(labels));
}
@@ -201,27 +240,30 @@ public class ActivityMetrics {
* and so on. It uses the same data reservoir for all views, but only returns one of them as a handle to the metric.
* This has the effect of leaving some of the metric objects unreferencable from the caller side. This may need
* to be changed in a future update in the even that full inventory management is required on metric objects here.
* @param parent The labeled element the metric pertains to
* @param metricFamilyName The name of the measurement
*
* @param parent
* The labeled element the metric pertains to
* @param metricFamilyName
* The name of the measurement
* @return One of the created metrics, suitable for calling {@link DoubleSummaryGauge#accept(double)} on.
*/
public static DoubleSummaryGauge summaryGauge(NBLabeledElement parent, String metricFamilyName) {
DoubleSummaryStatistics stats = new DoubleSummaryStatistics();
DoubleSummaryGauge anyGauge = null;
for (DoubleSummaryGauge.Stat statName: DoubleSummaryGauge.Stat.values()){
for (DoubleSummaryGauge.Stat statName : DoubleSummaryGauge.Stat.values()) {
final NBLabels labels = parent.getLabels()
.and("name",sanitize(metricFamilyName))
.modifyValue("name", n -> n+"_"+statName.name().toLowerCase());
anyGauge= (DoubleSummaryGauge) register(labels, () -> new DoubleSummaryGauge(labels,statName,stats));
.and("name", sanitize(metricFamilyName))
.modifyValue("name", n -> n + "_" + statName.name().toLowerCase());
anyGauge = (DoubleSummaryGauge) register(labels, () -> new DoubleSummaryGauge(labels, statName, stats));
}
return anyGauge;
}
@SuppressWarnings("unchecked")
public static <T> Gauge<T> gauge(NBLabeledElement parent, String metricFamilyName, Gauge<T> gauge) {
final NBLabels labels = parent.getLabels().and("name",sanitize(metricFamilyName));
return (Gauge<T>) register(labels, () -> new NBMetricGaugeWrapper<>(labels,gauge));
final NBLabels labels = parent.getLabels().and("name", sanitize(metricFamilyName));
return (Gauge<T>) register(labels, () -> new NBMetricGaugeWrapper<>(labels, gauge));
}
private static MetricRegistry lookupRegistry() {
@@ -375,10 +417,11 @@ public class ActivityMetrics {
.forEach(get()::remove);
}
public static String sanitize(String word) {
String sanitized = word;
sanitized = sanitized.replaceAll("\\..+$", "");
sanitized = sanitized.replaceAll("-","_");
sanitized = sanitized.replaceAll("-", "_");
sanitized = sanitized.replaceAll("[^a-zA-Z0-9_]+", "");
if (!word.equals(sanitized)) {

View File

@@ -19,6 +19,7 @@ package io.nosqlbench.api.engine.metrics.instruments;
import io.nosqlbench.api.labels.NBLabeledElement;
import io.nosqlbench.api.labels.NBLabels;
import java.util.Map;
import java.util.function.Supplier;
public class NBFunctionGauge implements NBMetricGauge<Double> {
@@ -27,11 +28,14 @@ public class NBFunctionGauge implements NBMetricGauge<Double> {
private final NBLabeledElement parent;
private final NBLabels labels;
public NBFunctionGauge(NBLabeledElement parent, Supplier<Double> source, Object... labels) {
public NBFunctionGauge(NBLabeledElement parent, Supplier<Double> source, String metricFamilyName, Map<String,String> additionalLabels) {
this.parent = parent;
this.labels = NBLabels.forKV(labels);
this.labels = NBLabels.forMap(additionalLabels).and("name",metricFamilyName);
this.source = source;
}
public NBFunctionGauge(NBLabeledElement parent, Supplier<Double> source, String metricFamilyName) {
this(parent, source, metricFamilyName,Map.of());
}
@Override
public Double getValue() {
return source.get();

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2023 nosqlbench
*
* 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.
*/
package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Metric;
import io.nosqlbench.api.labels.NBLabeledElement;
public interface NBLabeledMetric extends Metric, NBLabeledElement {
}

View File

@@ -17,10 +17,9 @@
package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Counter;
import io.nosqlbench.api.labels.NBLabeledElement;
import io.nosqlbench.api.labels.NBLabels;
public class NBMetricCounter extends Counter implements NBLabeledElement {
public class NBMetricCounter extends Counter implements NBLabeledMetric {
private final NBLabels labels;

View File

@@ -17,8 +17,7 @@
package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Gauge;
import io.nosqlbench.api.labels.NBLabeledElement;
public interface NBMetricGauge<T> extends Gauge<T>, NBLabeledElement {
public interface NBMetricGauge<T> extends Gauge<T>, NBLabeledMetric {
}

View File

@@ -17,15 +17,14 @@
package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Histogram;
import io.nosqlbench.api.labels.NBLabeledElement;
import io.nosqlbench.api.labels.NBLabels;
import io.nosqlbench.api.engine.metrics.*;
import io.nosqlbench.api.labels.NBLabels;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class NBMetricHistogram extends Histogram implements DeltaSnapshotter, HdrDeltaHistogramAttachment, HistogramAttachment, NBLabeledElement {
public class NBMetricHistogram extends Histogram implements DeltaSnapshotter, HdrDeltaHistogramAttachment, HistogramAttachment, NBLabeledMetric {
private final DeltaHdrHistogramReservoir hdrDeltaReservoir;
private final NBLabels labels;

View File

@@ -17,10 +17,9 @@
package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Meter;
import io.nosqlbench.api.labels.NBLabeledElement;
import io.nosqlbench.api.labels.NBLabels;
public class NBMetricMeter extends Meter implements NBLabeledElement {
public class NBMetricMeter extends Meter implements NBLabeledMetric {
private final NBLabels labels;

View File

@@ -17,16 +17,15 @@
package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Timer;
import io.nosqlbench.api.labels.NBLabeledElement;
import io.nosqlbench.api.labels.NBLabels;
import io.nosqlbench.api.engine.metrics.*;
import io.nosqlbench.api.labels.NBLabels;
import org.HdrHistogram.Histogram;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
public class NBMetricTimer extends Timer implements DeltaSnapshotter, HdrDeltaHistogramAttachment, TimerAttachment, NBLabeledElement {
public class NBMetricTimer extends Timer implements DeltaSnapshotter, HdrDeltaHistogramAttachment, TimerAttachment, NBLabeledMetric {
private final DeltaHdrHistogramReservoir deltaHdrHistogramReservoir;
private long cacheExpiry;
private List<Timer> mirrors;