blob: a31410ddf0692e9e7f394ef772429234629e85d4 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.apache.ambari.metrics.alertservice.prototype.methods.ema;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import static org.apache.ambari.metrics.alertservice.prototype.methods.ema.EmaTechnique.suppressAnomaliesTheshold;
@XmlRootElement
public class EmaModel implements Serializable {
private String metricName;
private String hostname;
private String appId;
private double ema;
private double ems;
private double weight;
private double timessdev;
private int ctr = 0;
private static final Log LOG = LogFactory.getLog(EmaModel.class);
public EmaModel(String name, String hostname, String appId, double weight, double timessdev) {
this.metricName = name;
this.hostname = hostname;
this.appId = appId;
this.weight = weight;
this.timessdev = timessdev;
this.ema = 0.0;
this.ems = 0.0;
}
public String getMetricName() {
return metricName;
}
public String getHostname() {
return hostname;
}
public String getAppId() {
return appId;
}
public double testAndUpdate(double metricValue) {
double anomalyScore = 0.0;
LOG.info("Before Update ->" + metricName + ":" + appId + ":" + hostname + " - " + "ema = " + ema + ", ems = " + ems + ", timessdev = " + timessdev);
update(metricValue);
if (ctr > suppressAnomaliesTheshold) {
anomalyScore = test(metricValue);
if (anomalyScore > 0.0) {
LOG.info("Anomaly ->" + metricName + ":" + appId + ":" + hostname + " - " + "ema = " + ema + ", ems = " + ems +
", timessdev = " + timessdev + ", metricValue = " + metricValue);
} else {
LOG.info("Not an Anomaly ->" + metricName + ":" + appId + ":" + hostname + " - " + "ema = " + ema + ", ems = " + ems +
", timessdev = " + timessdev + ", metricValue = " + metricValue);
}
} else {
ctr++;
if (ctr > suppressAnomaliesTheshold) {
LOG.info("Ema Model for " + metricName + ":" + appId + ":" + hostname + " is ready for testing data.");
}
}
return anomalyScore;
}
public void update(double metricValue) {
ema = weight * ema + (1 - weight) * metricValue;
ems = Math.sqrt(weight * Math.pow(ems, 2.0) + (1 - weight) * Math.pow(metricValue - ema, 2.0));
LOG.debug("In update : ema = " + ema + ", ems = " + ems);
}
public double test(double metricValue) {
LOG.debug("In test : ema = " + ema + ", ems = " + ems);
double diff = Math.abs(ema - metricValue) - (timessdev * ems);
LOG.debug("diff = " + diff);
if (diff > 0) {
return Math.abs((metricValue - ema) / ems); //Z score
} else {
return 0.0;
}
}
public void updateModel(boolean increaseSensitivity, double percent) {
LOG.info("Updating model for " + metricName + " with increaseSensitivity = " + increaseSensitivity + ", percent = " + percent);
double delta = percent / 100;
if (increaseSensitivity) {
delta = delta * -1;
}
this.timessdev = timessdev + delta * timessdev;
//this.weight = Math.min(1.0, weight + delta * weight);
LOG.info("New model parameters " + metricName + " : timessdev = " + timessdev + ", weight = " + weight);
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getTimessdev() {
return timessdev;
}
public void setTimessdev(double timessdev) {
this.timessdev = timessdev;
}
}