package com.loadimpact.eval;
import com.loadimpact.resource.testresult.StandardMetricResult;
import com.loadimpact.util.ListUtils;
import java.util.List;
/**
* Represents a single threshold and handles the metric value aggregations and threshold trigger evaluations.
*
* @author jens
*/
public class Threshold {
/**
* Threshold number (1,2,3,...)
*/
private final int id;
/**
* The metric to check.
*/
private final StandardMetricResult.Metrics metric;
/**
* The threshold to compare with.
*/
private final int thresholdValue;
/**
* The result if exceeded
*/
private final LoadTestResult result;
/**
* The comparison operator
*/
private final Operator operator;
/**
* Contains the last N metric values
*/
private final BoundedDroppingQueue<Integer> values;
/**
* Offset of the last bunch of metric values
*/
private int lastOffset;
/**
* Last computed aggregated value
*/
private int lastAggregatedValue;
/**
* True if the last evaluation exceeded the threshold
*/
private boolean lastExceededValue;
public Threshold(int id, StandardMetricResult.Metrics metric, Operator operator, int thresholdValue, LoadTestResult result) {
this.id = id;
this.metric = metric;
this.operator = operator;
this.thresholdValue = thresholdValue;
this.result = result;
this.values = new BoundedDroppingQueue<Integer>();
this.lastOffset = -1;
}
public int getId() { return id; }
public StandardMetricResult.Metrics getMetric() { return metric; }
public LoadTestResult getResult() { return result; }
/**
* Returns the computed aggregated value (median) of the latest N metric values.
*
* @return the median of the N last values
*/
public int getAggregatedValue() { return ListUtils.median(values.toList()); }
/**
* Adds a metric value to the metric value queue.
*
* @param metricValues
* bunch of values
*/
public void accumulate(List<? extends StandardMetricResult> metricValues) {
if (metricValues == null || metricValues.isEmpty()) return;
for (StandardMetricResult v : metricValues) {
if (lastOffset < v.offset) values.put(v.value.intValue());
}
lastOffset = ListUtils.last(metricValues).offset;
}
/**
* Returns true of this threshold has been exceeded.
*
* @return true if exceeded
*/
public boolean isExceeded() {
lastAggregatedValue = getAggregatedValue();
lastExceededValue = false;
switch (operator) {
case lessThan:
lastExceededValue = (lastAggregatedValue < thresholdValue);
break;
case greaterThan: lastExceededValue = (lastAggregatedValue > thresholdValue);
break;
}
return lastExceededValue;
}
@Override
public String toString() {
return "Threshold[id:" + id
+ ", metric:" + metric.name()
+ ", aggregatedValue:" + lastAggregatedValue
+ ", thresholdValue:" + thresholdValue
+ ", operator:" + operator.symbol
+ ", result=" + result
+ ", lastExceededValue:" + lastExceededValue
+ ", lastOffset:" + lastOffset
+ "]";
}
/**
* Returns summary intended for logging.
*
* @return a summary
*/
public String getReason() {
if (lastExceededValue) {
return String.format("Metric '%s' has aggregated-value=%d %s %d as threshold", metric.name(), lastAggregatedValue, operator.symbol, thresholdValue);
} else {
return String.format("Metric %s: aggregated-value=%d", metric.name(), lastAggregatedValue);
}
}
}