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.parent = parent;
this.activityDef = activityDef; this.activityDef = activityDef;
onActivityDefUpdate(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.register(new NBFunctionGauge(this, () -> (double)this.cycles_min.get(),"input_cycles_first"));
ActivityMetrics.gauge(this, "input_cycle", new NBFunctionGauge(this, () -> (double)this.cycle_value.get())); ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycles_max.get(), "input_cycles_last"));
ActivityMetrics.gauge(this, "input_cycles_total", new NBFunctionGauge(this, this::getTotalCycles)); ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.cycle_value.get(), "input_cycle"));
ActivityMetrics.gauge(this, "input_recycles_first", new NBFunctionGauge(this, () -> (double)this.recycles_min.get())); ActivityMetrics.register(new NBFunctionGauge(this, this::getTotalCycles, "input_cycles_total"));
ActivityMetrics.gauge(this, "input_recycles_last", new NBFunctionGauge(this, () -> (double)this.recycles_max.get())); ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.recycles_min.get(), "input_recycles_first"));
ActivityMetrics.gauge(this, "input_recycle", new NBFunctionGauge(this, () -> (double) this.recycle_value.get())); ActivityMetrics.register(new NBFunctionGauge(this, () -> (double)this.recycles_max.get(), "input_recycles_last"));
ActivityMetrics.gauge(this, "input_recycles_total", new NBFunctionGauge(this, this::getTotalRecycles)); 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() { private double getTotalRecycles() {

View File

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

View File

@@ -76,10 +76,10 @@ public class ActivityMetrics {
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
private static Metric register(NBLabels labels, MetricProvider metricProvider) { 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; 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); Metric metric = get().getMetrics().get(graphiteName);
if (null == metric) { if (null == metric) {
@@ -96,6 +96,45 @@ public class ActivityMetrics {
return metric; 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> * <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 * @return the timer, perhaps a different one if it has already been registered
*/ */
public static Timer timer(NBLabeledElement parent, String metricFamilyName, int hdrdigits) { 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, () -> 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 * @return the counter, perhaps a different one if it has already been registered
*/ */
public static Counter counter(NBLabeledElement parent, String metricFamilyName) { 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)); 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 * @return the meter, perhaps a different one if it has already been registered
*/ */
public static Meter meter(NBLabeledElement parent, String metricFamilyName) { 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)); 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. * 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 * 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. * 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. * @return One of the created metrics, suitable for calling {@link DoubleSummaryGauge#accept(double)} on.
*/ */
public static DoubleSummaryGauge summaryGauge(NBLabeledElement parent, String metricFamilyName) { public static DoubleSummaryGauge summaryGauge(NBLabeledElement parent, String metricFamilyName) {
DoubleSummaryStatistics stats = new DoubleSummaryStatistics(); DoubleSummaryStatistics stats = new DoubleSummaryStatistics();
DoubleSummaryGauge anyGauge = null; DoubleSummaryGauge anyGauge = null;
for (DoubleSummaryGauge.Stat statName: DoubleSummaryGauge.Stat.values()){ for (DoubleSummaryGauge.Stat statName : DoubleSummaryGauge.Stat.values()) {
final NBLabels labels = parent.getLabels() final NBLabels labels = parent.getLabels()
.and("name",sanitize(metricFamilyName)) .and("name", sanitize(metricFamilyName))
.modifyValue("name", n -> n+"_"+statName.name().toLowerCase()); .modifyValue("name", n -> n + "_" + statName.name().toLowerCase());
anyGauge= (DoubleSummaryGauge) register(labels, () -> new DoubleSummaryGauge(labels,statName,stats)); anyGauge = (DoubleSummaryGauge) register(labels, () -> new DoubleSummaryGauge(labels, statName, stats));
} }
return anyGauge; return anyGauge;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> Gauge<T> gauge(NBLabeledElement parent, String metricFamilyName, Gauge<T> gauge) { public static <T> Gauge<T> gauge(NBLabeledElement parent, String metricFamilyName, Gauge<T> gauge) {
final NBLabels labels = parent.getLabels().and("name",sanitize(metricFamilyName)); final NBLabels labels = parent.getLabels().and("name", sanitize(metricFamilyName));
return (Gauge<T>) register(labels, () -> new NBMetricGaugeWrapper<>(labels, gauge));
return (Gauge<T>) register(labels, () -> new NBMetricGaugeWrapper<>(labels,gauge));
} }
private static MetricRegistry lookupRegistry() { private static MetricRegistry lookupRegistry() {
@@ -375,10 +417,11 @@ public class ActivityMetrics {
.forEach(get()::remove); .forEach(get()::remove);
} }
public static String sanitize(String word) { public static String sanitize(String word) {
String sanitized = word; String sanitized = word;
sanitized = sanitized.replaceAll("\\..+$", ""); sanitized = sanitized.replaceAll("\\..+$", "");
sanitized = sanitized.replaceAll("-","_"); sanitized = sanitized.replaceAll("-", "_");
sanitized = sanitized.replaceAll("[^a-zA-Z0-9_]+", ""); sanitized = sanitized.replaceAll("[^a-zA-Z0-9_]+", "");
if (!word.equals(sanitized)) { 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.NBLabeledElement;
import io.nosqlbench.api.labels.NBLabels; import io.nosqlbench.api.labels.NBLabels;
import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
public class NBFunctionGauge implements NBMetricGauge<Double> { public class NBFunctionGauge implements NBMetricGauge<Double> {
@@ -27,11 +28,14 @@ public class NBFunctionGauge implements NBMetricGauge<Double> {
private final NBLabeledElement parent; private final NBLabeledElement parent;
private final NBLabels labels; 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.parent = parent;
this.labels = NBLabels.forKV(labels); this.labels = NBLabels.forMap(additionalLabels).and("name",metricFamilyName);
this.source = source; this.source = source;
} }
public NBFunctionGauge(NBLabeledElement parent, Supplier<Double> source, String metricFamilyName) {
this(parent, source, metricFamilyName,Map.of());
}
@Override @Override
public Double getValue() { public Double getValue() {
return source.get(); 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; package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Counter; import com.codahale.metrics.Counter;
import io.nosqlbench.api.labels.NBLabeledElement;
import io.nosqlbench.api.labels.NBLabels; import io.nosqlbench.api.labels.NBLabels;
public class NBMetricCounter extends Counter implements NBLabeledElement { public class NBMetricCounter extends Counter implements NBLabeledMetric {
private final NBLabels labels; private final NBLabels labels;

View File

@@ -17,8 +17,7 @@
package io.nosqlbench.api.engine.metrics.instruments; package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Gauge; 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; package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Histogram; 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.engine.metrics.*;
import io.nosqlbench.api.labels.NBLabels;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; 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 DeltaHdrHistogramReservoir hdrDeltaReservoir;
private final NBLabels labels; private final NBLabels labels;

View File

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

View File

@@ -17,16 +17,15 @@
package io.nosqlbench.api.engine.metrics.instruments; package io.nosqlbench.api.engine.metrics.instruments;
import com.codahale.metrics.Timer; 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.engine.metrics.*;
import io.nosqlbench.api.labels.NBLabels;
import org.HdrHistogram.Histogram; import org.HdrHistogram.Histogram;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit; 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 final DeltaHdrHistogramReservoir deltaHdrHistogramReservoir;
private long cacheExpiry; private long cacheExpiry;
private List<Timer> mirrors; private List<Timer> mirrors;