package org.stagemonitor.alerting.check;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.stagemonitor.core.metrics.metrics2.InfluxDbReporter;
import org.stagemonitor.core.metrics.metrics2.MetricName;
import java.util.Map;
/**
* Represents a threshold to check
*/
public class Threshold {
private final MetricValueType valueType;
private final Operator operator;
private final double thresholdValue;
@JsonCreator
public Threshold(@JsonProperty("valueType") String metric, @JsonProperty("operator") Operator operator, @JsonProperty("thresholdValue") double thresholdValue) {
if (operator == null) {
throw new IllegalArgumentException("Operator may not be null");
}
this.valueType = MetricValueType.valueOf(metric.toUpperCase());
this.operator = operator;
this.thresholdValue = thresholdValue;
}
/**
* Checks if the threshold is exceeded.
*
* @param actualValue the value to check
* @return <code>true</code>, if the actual value exceeds the threshold, <code>false</code> otherwise
*/
public boolean isExceeded(double actualValue) {
return !operator.check(actualValue, thresholdValue);
}
public Operator getOperator() {
return operator;
}
public double getThresholdValue() {
return thresholdValue;
}
public MetricValueType getValueType() {
return valueType;
}
public String toString() {
return valueType.getName() + " " + operator.operatorString + " " + thresholdValue;
}
public String getCheckExpressionAsString(MetricName target) {
return InfluxDbReporter.getInfluxDbLineProtocolString(target) + ' ' + valueType.getName() + " " + operator.operatorString + " " + thresholdValue;
}
public CheckResult check(CheckResult.Status severity, MetricName target, Map<String, Number> currentValuesByMetric) {
double actualValue = currentValuesByMetric.get(valueType.getName()).doubleValue();
if (isExceeded(actualValue)) {
return new CheckResult(getCheckExpressionAsString(target) + " is false", actualValue, severity);
}
return new CheckResult(null, actualValue, CheckResult.Status.OK);
}
/**
* Represents a boolean operator that can be used to check whether the expression
* <code>actualValue OPERATOR thresholdValue</code> is true or false
*/
public enum Operator {
LESS("<") {
@Override
public boolean check(double actualValue, double expectedValue) {
return actualValue < expectedValue;
}
},
LESS_EQUAL("<=") {
@Override
public boolean check(double actualValue, double expectedValue) {
return actualValue <= expectedValue;
}
},
GREATER(">") {
@Override
public boolean check(double actualValue, double expectedValue) {
return actualValue > expectedValue;
}
},
GREATER_EQUAL(">=") {
@Override
public boolean check(double actualValue, double expectedValue) {
return actualValue >= expectedValue;
}
};
private final String operatorString;
Operator(String operatorString) {
this.operatorString = operatorString;
}
/**
* Checks, whether <code>actualValue OPERATOR thresholdValue</code> is true or false
*
* @param actualValue
* @param expectedValue
* @return
*/
public abstract boolean check(double actualValue, double expectedValue);
/**
* Gets a operator by its {@link #operatorString}.
*
* @param operatorString the operator string
* @return the operator (e.g. {@link #GREATER_EQUAL} for the operatorString <code>>=</code>)
*/
public static Operator getByString(String operatorString) {
for (Operator operator : Operator.values()) {
if (operator.operatorString.equals(operatorString)) {
return operator;
}
}
throw new IllegalArgumentException("Operator '" + operatorString + "' does not exist.");
}
}
}