net.anotheria.moskito.extensions.monitoring.metrics.GenericMetrics Maven / Gradle / Ivy
package net.anotheria.moskito.extensions.monitoring.metrics;
import net.anotheria.moskito.core.predefined.Constants;
import net.anotheria.moskito.core.stats.IValueHolderFactory;
import net.anotheria.moskito.core.stats.Interval;
import net.anotheria.moskito.core.stats.StatValue;
import net.anotheria.moskito.core.stats.StatValueTypes;
import net.anotheria.moskito.core.stats.TypeAwareStatValue;
import net.anotheria.moskito.core.stats.impl.SkipFirstDiffLongValueHolderFactory;
import net.anotheria.moskito.core.stats.impl.StatValueFactory;
import net.anotheria.moskito.core.stats.impl.TypeAwareStatValueImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Generic implementation of {@link IGenericMetrics} interface.
*
* @author dzhmud
*/
public abstract class GenericMetrics implements IGenericMetrics {
/** Private registry of all created instances, mapped by their Class.*/
private static final ConcurrentMap, List extends GenericMetrics>> registry = new ConcurrentHashMap<>();
/**
* Get all registered metrics of given Class.
* @param type metrics of this class method should return.
* @param class type.
* @return list of metrics of the desired type, or null if there are none.
*/
protected static List getMetricsOfType(Class type) {
List metricsList = (List)registry.get(type);
if (metricsList == null) {
metricsList = new CopyOnWriteArrayList<>();
List previous = (List)registry.putIfAbsent(type, metricsList);
if (previous != null)
metricsList = previous;
}
return metricsList;
}
/** Caption, short explanation and full explanation variables.*/
private final String caption, shortExpl, explanation;
/** ValueType of current metric. */
private final StatValueTypes type;
/** If true, value per second will be calculated. */
private final boolean isRateMetric;
/**
* Shortest constructor of this class. ValueName param goes also to both explanations.
* @param type type of the created StatValue
* @param valueName valueName, used as caption in decorator, as metric name in MonitoringPluginConfig#metrics,
* generally, as string ID of the metric.
*/
protected GenericMetrics(StatValueTypes type, String valueName) {
this(type, false, valueName, valueName);
}
/**
* Constructor that allows adding custom explanation and short explanation.
* @param type type of the created StatValue
* @param valueName string ID of the metric.
* @param strings first string goes to short explanation, second - to full explanation, next are ignored.
*/
protected GenericMetrics(StatValueTypes type, String valueName, String ... strings ) {
this(type, false, valueName, strings);
}
/**
* Last constructor in chain. After assigning all instance variables register this instance in static registry.
* @param type type of the created StatValue
* @param isRateMetric boolean marker for 'rate' metrics, which means they will try to calculate value-per-second.
* @param valueName string ID of the metric.
* @param strings first string goes to short explanation, second - to full explanation, next are ignored.
*/
protected GenericMetrics(StatValueTypes type, boolean isRateMetric, String valueName, String ... strings) {
if (type == null || valueName == null)
throw new IllegalArgumentException("StatValueType and valueName are both required!");
this.type = type;
this.isRateMetric = isRateMetric;
this.caption = valueName;
this.shortExpl = (strings == null || strings.length == 0) ? valueName : strings[0];
this.explanation = (strings == null || strings.length < 2) ? shortExpl : strings[1];
register(this);
}
private void register(T metric) {
Class clazz = (Class)metric.getClass();
if (clazz.isAnonymousClass()) {
clazz = (Class)clazz.getSuperclass();
}
getMetricsOfType(clazz).add(metric);
}
@Override
public StatValue createStatValue() {
if (type != StatValueTypes.DIFFLONG) {
return StatValueFactory.createStatValue(type, caption, Constants.getDefaultIntervals());
} else {
//for DIFFLONG type use upgraded diffLong value holders that ignore first interval.
final IValueHolderFactory factory = SkipFirstDiffLongValueHolderFactory.INSTANCE;
final TypeAwareStatValue statValue = new TypeAwareStatValueImpl(caption, type, factory);
for (Interval interval : Constants.getDefaultIntervals()) {
statValue.addInterval(interval);
}
return statValue;
}
}
/**
* Get logger for current class.
* @return logger.
*/
protected Logger getLogger() {
return LoggerFactory.getLogger(getClass());
}
@Override
public StatValueTypes getType() {
return type;
}
@Override
public String getCaption() {
return caption;
}
@Override
public String getExplanation() {
return explanation;
}
@Override
public String getShortExplanation() {
return shortExpl;
}
@Override
public boolean isRateMetric() {
return isRateMetric;
}
@Override
public boolean isDoubleValue() {
return isRateMetric() || type == StatValueTypes.DOUBLE;
}
@Override
public boolean isStringValue() {
return !isRateMetric() && type == StatValueTypes.STRING;
}
@Override
public boolean isIntegerValue() {
return !isRateMetric() && type == StatValueTypes.INT;
}
@Override
public boolean isLongValue() {
return !isRateMetric() && (type == StatValueTypes.LONG || type == StatValueTypes.DIFFLONG || type == StatValueTypes.COUNTER);
}
@Override
public Object parseValue(String value) {
if (value == null) return null;
Object result = null;
try {
switch (type) {
case COUNTER:
case DIFFLONG:
case LONG: result = Long.parseLong(value); break;
case INT: result = Integer.parseInt(value); break;
case DOUBLE: result = Double.parseDouble(value); break;
case STRING: result = value; break;
default: result = value;
}
} catch (NumberFormatException nfe) {
getLogger().warn("Failed to parse value '"+value+"'! Metric: " + this.toString(), nfe);
}
return result;
}
@Override
public boolean isCorrectValue(Object value) {
if (value == null)
return true;
final boolean result;
switch (type) {
case COUNTER:
case DIFFLONG:
case LONG: result = value instanceof Long; break;
case INT: result = value instanceof Integer; break;
case DOUBLE: result = value instanceof Double; break;
case STRING: result = value instanceof String; break;
default: result = false;
}
return result;
}
@Override
public String toString() {
return "GenericMetrics{" +
"type=" + type +
", isRateMetric=" + isRateMetric +
", caption='" + caption + '\'' +
", shortExpl='" + shortExpl + '\'' +
", explanation='" + explanation + '\'' +
'}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy