提交 30de9a29 编写于 作者: Y youyong205

Merge pull request #304 from leonindy/master

add monitor rule page & job
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<?xml version="1.0" encoding="utf-8"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="config" type="ConfigType"/>
<xs:complexType name="ConfigType">
<xs:sequence>
......
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<?xml version="1.0" encoding="utf-8"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="status" type="StatusType"/>
<xs:complexType name="StatusType">
<xs:sequence>
......
......@@ -164,6 +164,7 @@
${basedir}/src/main/resources/META-INF/dal/model/metric-aggregation-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/netgraph-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/alert-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/monitor-rules-manifest.xml,
</manifest>
</configuration>
</execution>
......
package com.dianping.cat.report.page.alteration;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;
......@@ -47,9 +49,15 @@ public class Handler implements PageHandler<Context> {
alt.setUser(user);
alt.setAltGroup(group);
alt.setContent(content);
alt.setUrl(url);
alt.setHostname(hostname);
alt.setDate(date);
try {
alt.setUrl(URLDecoder.decode(url, "UTF-8"));
} catch (UnsupportedEncodingException e) {
Cat.logError(e);
alt.setUrl("");
}
return alt;
}
......@@ -113,6 +121,7 @@ public class Handler implements PageHandler<Context> {
}
}
public boolean isArguComplete(Payload payload) {
if (StringUtils.isEmpty(payload.getType())) {
return false;
......@@ -150,7 +159,7 @@ public class Handler implements PageHandler<Context> {
} else if (status == 1) {
model.setInsertResult("{\"status\":500}");
} else if (status == 2) {
model.setInsertResult("{\"status\":200, \"errorMessage\":\"lack args\"}");
model.setInsertResult("{\"status\":500, \"errorMessage\":\"lack args\"}");
}
}
......
......@@ -22,6 +22,15 @@ public class Payload extends AbstractReportPayload<Action> {
@FieldMeta("fullScreen")
private boolean fullScreen = false;
@FieldMeta("showPuppet")
private boolean m_isShowPuppet = true;
@FieldMeta("showWorkflow")
private boolean m_isShowWorkflow = true;
@FieldMeta("showLazyman")
private boolean m_isShowLazyman = true;
@FieldMeta("group")
private String m_group;
......@@ -37,7 +46,7 @@ public class Payload extends AbstractReportPayload<Action> {
@FieldMeta("domain")
private String m_domain;
@FieldMeta("ip")
private String m_ip;
......@@ -58,7 +67,7 @@ public class Payload extends AbstractReportPayload<Action> {
@FieldMeta("endTime")
private String m_endTime;
@FieldMeta("hostname")
private String m_hostname;
......@@ -124,14 +133,15 @@ public class Payload extends AbstractReportPayload<Action> {
return m_hostname;
}
}
public String getIp() {
return m_ip;
}
public ReportPage getPage() {
return m_page;
}
public Date getStartTime() {
if (m_startTime == null || m_startTime.length() == 0) {
......@@ -173,6 +183,18 @@ public class Payload extends AbstractReportPayload<Action> {
return m_refresh;
}
public boolean isShowLazyman() {
return m_isShowLazyman;
}
public boolean isShowPuppet() {
return m_isShowPuppet;
}
public boolean isShowWorkflow() {
return m_isShowWorkflow;
}
public void setAction(String action) {
m_action = Action.getByName(action, Action.VIEW);
}
......@@ -226,6 +248,18 @@ public class Payload extends AbstractReportPayload<Action> {
m_refresh = refresh;
}
public void setShowLazyman(boolean isShowLazyman) {
m_isShowLazyman = isShowLazyman;
}
public void setShowPuppet(boolean isShowPuppet) {
m_isShowPuppet = isShowPuppet;
}
public void setShowWorkflow(boolean isShowWorkflow) {
m_isShowWorkflow = isShowWorkflow;
}
public void setStartTime(String startTime) {
m_startTime = startTime;
}
......
......@@ -10,29 +10,45 @@ import org.unidal.tuple.Pair;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.consumer.company.model.entity.ProductLine;
import com.dianping.cat.home.monitorrules.entity.Condition;
import com.dianping.cat.home.monitorrules.entity.Config;
import com.dianping.cat.home.monitorrules.entity.Subcondition;
import com.dianping.cat.core.dal.Project;
import com.site.helper.Splitters;
public class AlertConfig {
public List<String> buildMailReceivers(Project project) {
private DecimalFormat m_df = new DecimalFormat("0.0");
private static final Long ONE_MINUTE_MILLSEC = 60000L;
private static final int JUDGE_DEFAULT_MINUTE = 3;
public List<String> buildExceptionSMSReceivers(ProductLine productLine) {
List<String> phones = new ArrayList<String>();
phones.add("15201789489");// 佳林
return phones;
}
public List<String> buildMailReceivers(ProductLine productLine) {
List<String> emails = new ArrayList<String>();
String emailList = project.getEmail();
String emailList = productLine.getEmail();
emails.add("yong.you@dianping.com");
emails.add("jialin.sun@dianping.com");
emails.add("argus@dianping.com");
emails.add("monitor@dianping.com");
emails.addAll(Splitters.by(",").noEmptyItem().split(emailList));
return emails;
}
public List<String> buildMailReceivers(ProductLine productLine) {
public List<String> buildMailReceivers(Project project) {
List<String> emails = new ArrayList<String>();
String emailList = productLine.getEmail();
String emailList = project.getEmail();
emails.add("yong.you@dianping.com");
emails.add("jialin.sun@dianping.com");
emails.add("argus@dianping.com");
emails.add("monitor@dianping.com");
emails.addAll(Splitters.by(",").noEmptyItem().split(emailList));
return emails;
}
......@@ -49,22 +65,18 @@ public class AlertConfig {
List<String> phones = new ArrayList<String>();
String phonesList = productLine.getPhone();
phones.add("13916536843");//值班
phones.add("18616671676");//尤勇
phones.add("13858086694");//黄河
phones.add("13916536843");// 值班
phones.add("18616671676");// 尤勇
phones.add("13858086694");// 黄河
phones.addAll(Splitters.by(",").noEmptyItem().split(phonesList));
return phones;
}
public List<String> buildExceptionSMSReceivers(ProductLine productLine) {
List<String> phones = new ArrayList<String>();
phones.add("15201789489");//佳林
return phones;
}
public Pair<Boolean, String> checkData(MetricItemConfig config, double[] value, double[] baseline, MetricType type) {
int length = value.length;
int listLength = value.length;
int length = JUDGE_DEFAULT_MINUTE > listLength ? listLength : JUDGE_DEFAULT_MINUTE;
double[] valueTrim = getLastMinutes(value, length);
double[] baseLineTrim = getLastMinutes(baseline, length);
StringBuilder baselines = new StringBuilder();
StringBuilder values = new StringBuilder();
double decreasePercent = config.getDecreasePercentage();
......@@ -81,8 +93,78 @@ public class AlertConfig {
}
for (int i = 0; i < length; i++) {
baselines.append(df.format(baseline[i])).append(" ");
values.append(df.format(value[i])).append(" ");
baselines.append(df.format(baseLineTrim[i])).append(" ");
values.append(df.format(valueTrim[i])).append(" ");
valueSum = valueSum + valueTrim[i];
baselineSum = baselineSum + baseLineTrim[i];
if (baseLineTrim[i] <= 0) {
baseLineTrim[i] = 100;
return new Pair<Boolean, String>(false, "");
}
if (type == MetricType.COUNT || type == MetricType.SUM) {
if (valueTrim[i] / baseLineTrim[i] > (1 - decreasePercent / 100)
|| (baseLineTrim[i] - valueTrim[i]) < decreaseValue) {
return new Pair<Boolean, String>(false, "");
}
}
}
double percent = (1 - valueSum / baselineSum) * 100;
StringBuilder sb = new StringBuilder();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sb.append("[基线值:").append(baselines.toString()).append("] ");
sb.append("[实际值:").append(values.toString()).append("] ");
sb.append("[下降:").append(df.format(percent)).append("%").append("]");
sb.append("[告警时间:").append(sdf.format(new Date()) + "]");
return new Pair<Boolean, String>(true, sb.toString());
}
public Pair<Boolean, String> checkData(MetricItemConfig config, double[] value, double[] baseline, MetricType type,
List<Config> configs) {
int valLength = value.length;
for (Config con : configs) {
int dataLength = getMaxMinute(con);
if (dataLength > valLength) {
continue;
}
double[] validVal = getLastMinutes(value, dataLength);
double[] validBase = getLastMinutes(baseline, dataLength);
Pair<Boolean, String> tmpResult = checkDataByConfig(config, validVal, validBase, type, con);
if (tmpResult.getKey() == true) {
return tmpResult;
}
}
return new Pair<Boolean, String>(false, "");
}
private int getMaxMinute(Config con) {
int maxMinute = 0;
for (Condition condition : con.getConditions()) {
int tmpMinute = condition.getMinute();
if (tmpMinute > maxMinute) {
maxMinute = tmpMinute;
}
}
return maxMinute;
}
private Pair<Boolean, String> checkDataByConfig(MetricItemConfig config, double[] value, double[] baseline,
MetricType type, Config con) {
int length = value.length;
StringBuilder baselines = new StringBuilder();
StringBuilder values = new StringBuilder();
double valueSum = 0;
double baselineSum = 0;
for (int i = 0; i < length; i++) {
baselines.append(m_df.format(baseline[i])).append(" ");
values.append(m_df.format(value[i])).append(" ");
valueSum = valueSum + value[i];
baselineSum = baselineSum + baseline[i];
......@@ -91,7 +173,7 @@ public class AlertConfig {
return new Pair<Boolean, String>(false, "");
}
if (type == MetricType.COUNT || type == MetricType.SUM) {
if (value[i] / baseline[i] > (1 - decreasePercent / 100) || (baseline[i] - value[i]) < decreaseValue) {
if (!judgeByRule(con, value[i], baseline[i], i, length)) {
return new Pair<Boolean, String>(false, "");
}
}
......@@ -102,8 +184,88 @@ public class AlertConfig {
sb.append("[基线值:").append(baselines.toString()).append("] ");
sb.append("[实际值:").append(values.toString()).append("] ");
sb.append("[下降:").append(df.format(percent)).append("%").append("]");
sb.append("[下降:").append(m_df.format(percent)).append("%").append("]");
sb.append("[告警时间:").append(sdf.format(new Date()) + "]");
return new Pair<Boolean, String>(true, sb.toString());
}
private double[] getLastMinutes(double[] doubleList, int remainCount) {
double[] result = new double[remainCount];
int startIndex = doubleList.length - remainCount;
for (int i = 0; i < remainCount; i++) {
result[i] = doubleList[startIndex + i];
}
return result;
}
private Long getMillsByString(String time) throws Exception {
String[] times = time.split(":");
int hour = Integer.parseInt(times[0]);
int minute = Integer.parseInt(times[1]);
long result = hour * 60 * 60 * 1000 + minute * 60 * 1000;
return result;
}
private boolean judgeByRule(Config ruleConfig, double value, double baseline, int index, int length) {
boolean isRuleTriggered = false;
long ruleStartTime;
long ruleEndTime;
long nowTime = (System.currentTimeMillis() + 8 * 60 * 60 * 1000) % (24 * 60 * 60 * 1000);
try {
ruleStartTime = getMillsByString(ruleConfig.getStarttime());
ruleEndTime = getMillsByString(ruleConfig.getEndtime()) + ONE_MINUTE_MILLSEC;
} catch (Exception ex) {
ruleStartTime = 0L;
ruleEndTime = 86400000L;
}
if (nowTime < ruleStartTime || nowTime > ruleEndTime) {
return false;
}
for (Condition condition : ruleConfig.getConditions()) {
if (isRuleTriggered) {
break;
}
int minute = condition.getMinute();
if (minute == 0) {
minute = JUDGE_DEFAULT_MINUTE;
}
if (index < length - minute) {
continue;
}
boolean isSubRuleTriggered = true;
for (Subcondition subCondition : condition.getSubconditions()) {
if (!isSubRuleTriggered) {
break;
}
String ruleType = subCondition.getType();
int ruleValue = Integer.parseInt(subCondition.getText());
RuleType rule = RuleType.getByTypeId(ruleType);
if (rule == null) {
continue;
} else {
isSubRuleTriggered = rule.executeRule(value, baseline, ruleValue);
}
}
if (isSubRuleTriggered) {
isRuleTriggered = true;
}
}
return isRuleTriggered;
}
}
......@@ -23,11 +23,15 @@ import com.dianping.cat.consumer.metric.ProductLineConfigManager;
import com.dianping.cat.consumer.metric.model.entity.MetricReport;
import com.dianping.cat.consumer.metric.model.entity.Segment;
import com.dianping.cat.helper.TimeUtil;
import com.dianping.cat.home.monitorrules.entity.Condition;
import com.dianping.cat.home.monitorrules.entity.Config;
import com.dianping.cat.home.monitorrules.entity.Subcondition;
import com.dianping.cat.message.Event;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.report.baseline.BaselineService;
import com.dianping.cat.service.ModelPeriod;
import com.dianping.cat.service.ModelRequest;
import com.dianping.cat.system.config.MetricRuleConfigManager;
import com.dianping.cat.system.tool.MailSMS;
public class MetricAlert implements Task, LogEnabled {
......@@ -38,6 +42,9 @@ public class MetricAlert implements Task, LogEnabled {
@Inject
private ProductLineConfigManager m_productLineConfigManager;
@Inject
private MetricRuleConfigManager m_metricRuleConfigManager;
@Inject
private BaselineService m_baselineService;
......@@ -65,34 +72,125 @@ public class MetricAlert implements Task, LogEnabled {
private Logger m_logger;
private void addDescMetricIfNotExist(MetricItemConfig config, List<Config> configs) {
double descPer = config.getDecreasePercentage();
double descVal = config.getDecreaseValue();
boolean isDescPerExist = false;
boolean isDescValExist = false;
String dayBeginTime = "00:00";
String dayEndTime = "24:00";
if (descPer == 0) {
descPer = 50;
}
if (descVal == 0) {
descVal = 100;
}
for (Config con : configs) {
String startTime = con.getStarttime();
String endTime = con.getEndtime();
if (startTime == null || !startTime.equals(dayBeginTime) || endTime == null || !endTime.equals(dayEndTime)) {
continue;
}
for (Condition c : con.getConditions()) {
List<Subcondition> subCons = c.getSubconditions();
if (subCons.size() != 2) {
continue;
}
for (Subcondition sub : subCons) {
RuleType type = RuleType.getByTypeId(sub.getType());
switch (type) {
case DecreasePercentage:
isDescPerExist = true;
break;
case DecreaseValue:
isDescValExist = true;
break;
default:
break;
}
}
if (isDescPerExist && isDescValExist) {
break;
} else {
isDescPerExist = false;
isDescValExist = false;
}
}
}
if (isDescPerExist && isDescValExist) {
return;
} else {
addNewCondition(configs, "DescPer", descPer, "DescVal", descVal, dayBeginTime, dayEndTime);
}
}
private void addNewCondition(List<Config> configs, String type, double val, String type2, double val2,
String dayBeginTime, String dayEndTime) {
configs.add(new Config()
.setStarttime(dayBeginTime)
.setEndtime(dayEndTime)
.addCondition(
new Condition().setTitle("default rule")
.addSubcondition(new Subcondition().setType(type).setText(String.valueOf(val)))
.addSubcondition(new Subcondition().setType(type2).setText(String.valueOf(val2)))));
}
private Pair<Boolean, String> checkDataByJudge(MetricItemConfig config, double[] value, double[] baseline,
MetricType type, List<Config> configs) {
Pair<Boolean, String> originResult = m_alertConfig.checkData(config, value, baseline, type);
addDescMetricIfNotExist(config, configs);
Pair<Boolean, String> ruleJudgeResult = m_alertConfig.checkData(config, value, baseline, type, configs);
if (originResult.getKey() != ruleJudgeResult.getKey()) {
Cat.logError("rule execute error!", new Exception());
}
return originResult;
}
private Pair<Boolean, String> computeAlertInfo(int minute, String product, MetricItemConfig config, MetricType type) {
double[] value = null;
double[] baseline = null;
String metricKey = m_metricConfigManager.buildMetricKey(config.getDomain(), config.getType(),
config.getMetricKey());
String domain = config.getDomain();
String key = config.getMetricKey();
String metricKey = m_metricConfigManager.buildMetricKey(domain, config.getType(), key);
List<Config> configs = m_metricRuleConfigManager.getConfigs(product, domain, key, metricKey);
int maxMinute = getMaxMinute(configs);
if (minute >= DATA_CHECK_MINUTE - 1) {
if (minute >= maxMinute - 1) {
MetricReport report = fetchMetricReport(product, ModelPeriod.CURRENT);
if (report != null) {
int start = minute + 1 - DATA_CHECK_MINUTE;
int start = minute + 1 - maxMinute;
int end = minute;
value = queryRealData(start, end, metricKey, report, type);
baseline = queryBaseLine(start, end, metricKey, new Date(ModelPeriod.CURRENT.getStartTime()), type);
return m_alertConfig.checkData(config, value, baseline, type);
return checkDataByJudge(config, value, baseline, type, configs);
}
} else if (minute < 0) {
MetricReport lastReport = fetchMetricReport(product, ModelPeriod.LAST);
if (lastReport != null) {
int start = 60 + minute + 1 - (DATA_CHECK_MINUTE);
int start = 60 + minute + 1 - (maxMinute);
int end = 60 + minute;
value = queryRealData(start, end, metricKey, lastReport, type);
baseline = queryBaseLine(start, end, metricKey, new Date(ModelPeriod.LAST.getStartTime()), type);
return m_alertConfig.checkData(config, value, baseline, type);
return checkDataByJudge(config, value, baseline, type, configs);
}
} else {
MetricReport currentReport = fetchMetricReport(product, ModelPeriod.CURRENT);
......@@ -104,7 +202,7 @@ public class MetricAlert implements Task, LogEnabled {
double[] currentBaseline = queryBaseLine(currentStart, currentEnd, metricKey,
new Date(ModelPeriod.CURRENT.getStartTime()), type);
int lastStart = 60 + 1 - (DATA_CHECK_MINUTE - minute);
int lastStart = 60 + 1 - (maxMinute - minute);
int lastEnd = 59;
double[] lastValue = queryRealData(lastStart, lastEnd, metricKey, lastReport, type);
double[] lastBaseline = queryBaseLine(lastStart, lastEnd, metricKey,
......@@ -112,7 +210,7 @@ public class MetricAlert implements Task, LogEnabled {
value = mergerArray(lastValue, currentValue);
baseline = mergerArray(lastBaseline, currentBaseline);
return m_alertConfig.checkData(config, value, baseline, type);
return checkDataByJudge(config, value, baseline, type, configs);
}
}
return null;
......@@ -159,6 +257,20 @@ public class MetricAlert implements Task, LogEnabled {
}
}
private int getMaxMinute(List<Config> configs) {
int maxMinute = DATA_CHECK_MINUTE;
for (Config config : configs) {
for (Condition con : config.getConditions()) {
int tmpMinute = con.getMinute();
if (tmpMinute > maxMinute) {
maxMinute = tmpMinute;
}
}
}
return maxMinute;
}
@Override
public String getName() {
return "metric-alert";
......@@ -180,6 +292,31 @@ public class MetricAlert implements Task, LogEnabled {
return result;
}
private void processMetricItemConfig(MetricItemConfig config, int minute, String product, ProductLine productLine) {
if ((!config.getAlarm() && !config.isShowAvgDashboard() && !config.isShowSumDashboard() && !config
.isShowCountDashboard())) {
return;
}
Pair<Boolean, String> alert = null;
if (config.isShowAvg()) {
alert = computeAlertInfo(minute, product, config, MetricType.AVG);
}
if (config.isShowCount()) {
alert = computeAlertInfo(minute, product, config, MetricType.COUNT);
}
if (config.isShowSum()) {
alert = computeAlertInfo(minute, product, config, MetricType.SUM);
}
if (alert != null && alert.getKey()) {
config.setId(m_metricConfigManager.buildMetricKey(config.getDomain(), config.getType(), config.getMetricKey()));
m_alertInfo.addMetric(config, new Date().getTime());
sendAlertInfo(productLine, config, alert.getValue());
}
}
private void processProductLine(ProductLine productLine) {
List<String> domains = m_productLineConfigManager.queryDomainsByProductLine(productLine.getId());
List<MetricItemConfig> configs = m_metricConfigManager.queryMetricItemConfigs(new HashSet<String>(domains));
......@@ -188,28 +325,7 @@ public class MetricAlert implements Task, LogEnabled {
String product = productLine.getId();
for (MetricItemConfig config : configs) {
if ((!config.getAlarm() && !config.isShowAvgDashboard() && !config.isShowSumDashboard() && !config
.isShowCountDashboard())) {
continue;
}
Pair<Boolean, String> alert = null;
if (config.isShowAvg()) {
alert = computeAlertInfo(minute, product, config, MetricType.AVG);
}
if (config.isShowCount()) {
alert = computeAlertInfo(minute, product, config, MetricType.COUNT);
}
if (config.isShowSum()) {
alert = computeAlertInfo(minute, product, config, MetricType.SUM);
}
if (alert != null && alert.getKey()) {
config.setId(m_metricConfigManager.buildMetricKey(config.getDomain(), config.getType(),
config.getMetricKey()));
m_alertInfo.addMetric(config, new Date().getTime());
sendAlertInfo(productLine, config, alert.getValue());
}
processMetricItemConfig(config, minute, product, productLine);
}
}
......@@ -275,6 +391,7 @@ public class MetricAlert implements Task, LogEnabled {
Cat.logError(e);
}
}
t.setStatus(Transaction.SUCCESS);
} catch (Exception e) {
t.setStatus(e);
......
package com.dianping.cat.report.task.metric;
import java.util.LinkedHashMap;
import java.util.Map;
public enum RuleType {
DecreasePercentage{
@Override
public boolean executeRule(double value, double baseline, double ruleValue) {
return value / baseline <= (1 - ruleValue / 100);
}
@Override
public String getId() {
return "DescPer";
}
},
DecreaseValue{
@Override
public boolean executeRule(double value, double baseline, double ruleValue) {
return baseline - value >= ruleValue;
}
@Override
public String getId() {
return "DescVal";
}
},
IncreasePercentage{
@Override
public boolean executeRule(double value, double baseline, double ruleValue) {
return value / baseline >= (1 + ruleValue / 100);
}
@Override
public String getId() {
return "AscPer";
}
},
IncreaseValue{
@Override
public boolean executeRule(double value, double baseline, double ruleValue) {
return value - baseline >= ruleValue;
}
@Override
public String getId() {
return "AscVal";
}
},
absoluteMaxValue{
@Override
public boolean executeRule(double value, double baseline, double ruleValue) {
return value >= ruleValue;
}
@Override
public String getId() {
return "MaxVal";
}
},
absoluteMinValue{
@Override
public boolean executeRule(double value, double baseline, double ruleValue) {
return value <= ruleValue;
}
@Override
public String getId() {
return "MinVal";
}
};
static Map<String,RuleType> s_map = new LinkedHashMap<String,RuleType>();
static {
for(RuleType type : RuleType.values()){
s_map.put(type.getId(), type);
}
}
public abstract boolean executeRule(double value, double baseline, double ruleValue);
public abstract String getId();
public static RuleType getByTypeId(String typeId){
return s_map.get(typeId);
}
}
package com.dianping.cat.report.task.metric;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.unidal.helper.Threads.Task;
import org.unidal.lookup.annotation.Inject;
import org.unidal.tuple.Pair;
import com.dianping.cat.Cat;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.consumer.company.model.entity.ProductLine;
import com.dianping.cat.consumer.metric.MetricAnalyzer;
import com.dianping.cat.consumer.metric.MetricConfigManager;
import com.dianping.cat.consumer.metric.ProductLineConfigManager;
import com.dianping.cat.consumer.metric.model.entity.MetricReport;
import com.dianping.cat.consumer.metric.model.entity.Segment;
import com.dianping.cat.helper.TimeUtil;
import com.dianping.cat.home.monitorrules.entity.Condition;
import com.dianping.cat.home.monitorrules.entity.Config;
import com.dianping.cat.home.monitorrules.entity.Subcondition;
import com.dianping.cat.message.Event;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.report.baseline.BaselineService;
import com.dianping.cat.service.ModelPeriod;
import com.dianping.cat.service.ModelRequest;
import com.dianping.cat.system.config.MetricRuleConfigManager;
import com.dianping.cat.system.tool.MailSMS;
public class SwitchAlert implements Task, LogEnabled {
@Inject
private MetricConfigManager m_metricConfigManager;
@Inject
private ProductLineConfigManager m_productLineConfigManager;
@Inject
private MetricRuleConfigManager m_metricRuleConfigManager;
@Inject
private BaselineService m_baselineService;
@Inject
private MailSMS m_mailSms;
@Inject
private RemoteMetricReportService m_service;
@Inject
private SwitchAlertConfig m_alertConfig;
@Inject
private AlertInfo m_alertInfo;
private static final long DURATION = TimeUtil.ONE_MINUTE;
private static final int DATA_CHECK_MINUTE = 3;
private static final int DATA_AREADY_MINUTE = 1;
private Map<String, MetricReport> m_currentReports = new HashMap<String, MetricReport>();
private Map<String, MetricReport> m_lastReports = new HashMap<String, MetricReport>();
private Logger m_logger;
private void addDescMetricIfNotExist(MetricItemConfig config, List<Config> configs) {
double descPer = config.getDecreasePercentage();
double descVal = config.getDecreaseValue();
boolean isDescPerExist = false;
boolean isDescValExist = false;
String dayBeginTime = "00:00";
String dayEndTime = "24:00";
if (descPer == 0) {
descPer = 50;
}
if (descVal == 0) {
descVal = 100;
}
for (Config con : configs) {
String startTime = con.getStarttime();
String endTime = con.getEndtime();
if (startTime == null || !startTime.equals(dayBeginTime) || endTime == null || !endTime.equals(dayEndTime)) {
continue;
}
for (Condition c : con.getConditions()) {
List<Subcondition> subCons = c.getSubconditions();
if (subCons.size() != 2) {
continue;
}
for (Subcondition sub : subCons) {
RuleType type = RuleType.getByTypeId(sub.getType());
switch (type) {
case DecreasePercentage:
isDescPerExist = true;
break;
case DecreaseValue:
isDescValExist = true;
break;
default:
break;
}
}
if (isDescPerExist && isDescValExist) {
break;
} else {
isDescPerExist = false;
isDescValExist = false;
}
}
}
if (isDescPerExist && isDescValExist) {
return;
} else {
addNewCondition(configs, "DescPer", descPer, "DescVal", descVal, dayBeginTime, dayEndTime);
}
}
private void addNewCondition(List<Config> configs, String type, double val, String type2, double val2,
String dayBeginTime, String dayEndTime) {
configs.add(new Config()
.setStarttime(dayBeginTime)
.setEndtime(dayEndTime)
.addCondition(
new Condition().setTitle("default rule")
.addSubcondition(new Subcondition().setType(type).setText(String.valueOf(val)))
.addSubcondition(new Subcondition().setType(type2).setText(String.valueOf(val2)))));
}
private Pair<Boolean, String> checkDataByJudge(MetricItemConfig config, double[] value, double[] baseline,
MetricType type, List<Config> configs) {
Pair<Boolean, String> originResult = m_alertConfig.checkData(config, value, baseline, type);
addDescMetricIfNotExist(config, configs);
Pair<Boolean, String> ruleJudgeResult = m_alertConfig.checkData(config, value, baseline, type, configs);
if (originResult.getKey() != ruleJudgeResult.getKey()) {
Cat.logError("rule execute error!", new Exception());
}
return originResult;
}
private Pair<Boolean, String> computeAlertInfo(int minute, String product, MetricItemConfig config, MetricType type) {
double[] value = null;
double[] baseline = null;
String domain = config.getDomain();
String key = config.getMetricKey();
String metricKey = m_metricConfigManager.buildMetricKey(domain, config.getType(), key);
List<Config> configs = m_metricRuleConfigManager.getConfigs(product, domain, key, metricKey);
int maxMinute = getMaxMinute(configs);
if (minute >= maxMinute - 1) {
MetricReport report = fetchMetricReport(product, ModelPeriod.CURRENT);
if (report != null) {
int start = minute + 1 - maxMinute;
int end = minute;
value = queryRealData(start, end, metricKey, report, type);
baseline = queryBaseLine(start, end, metricKey, new Date(ModelPeriod.CURRENT.getStartTime()), type);
return checkDataByJudge(config, value, baseline, type, configs);
}
} else if (minute < 0) {
MetricReport lastReport = fetchMetricReport(product, ModelPeriod.LAST);
if (lastReport != null) {
int start = 60 + minute + 1 - (maxMinute);
int end = 60 + minute;
value = queryRealData(start, end, metricKey, lastReport, type);
baseline = queryBaseLine(start, end, metricKey, new Date(ModelPeriod.LAST.getStartTime()), type);
return checkDataByJudge(config, value, baseline, type, configs);
}
} else {
MetricReport currentReport = fetchMetricReport(product, ModelPeriod.CURRENT);
MetricReport lastReport = fetchMetricReport(product, ModelPeriod.LAST);
if (currentReport != null && lastReport != null) {
int currentStart = 0, currentEnd = minute;
double[] currentValue = queryRealData(currentStart, currentEnd, metricKey, currentReport, type);
double[] currentBaseline = queryBaseLine(currentStart, currentEnd, metricKey,
new Date(ModelPeriod.CURRENT.getStartTime()), type);
int lastStart = 60 + 1 - (maxMinute - minute);
int lastEnd = 59;
double[] lastValue = queryRealData(lastStart, lastEnd, metricKey, lastReport, type);
double[] lastBaseline = queryBaseLine(lastStart, lastEnd, metricKey,
new Date(ModelPeriod.LAST.getStartTime()), type);
value = mergerArray(lastValue, currentValue);
baseline = mergerArray(lastBaseline, currentBaseline);
return checkDataByJudge(config, value, baseline, type, configs);
}
}
return null;
}
@Override
public void enableLogging(Logger logger) {
m_logger = logger;
}
private MetricReport fetchMetricReport(String product, ModelPeriod period) {
if (period == ModelPeriod.CURRENT) {
MetricReport report = m_currentReports.get(product);
if (report != null) {
return report;
} else {
ModelRequest request = new ModelRequest(product, ModelPeriod.CURRENT.getStartTime()).setProperty(
"requireAll", "ture");
report = m_service.invoke(request);
if (report != null) {
m_currentReports.put(product, report);
}
return report;
}
} else if (period == ModelPeriod.LAST) {
MetricReport report = m_lastReports.get(product);
if (report != null) {
return report;
} else {
ModelRequest request = new ModelRequest(product, ModelPeriod.LAST.getStartTime()).setProperty("requireAll",
"ture");
report = m_service.invoke(request);
if (report != null) {
m_lastReports.put(product, report);
}
return report;
}
} else {
throw new RuntimeException("internal error, this can't be reached.");
}
}
private int getMaxMinute(List<Config> configs) {
int maxMinute = DATA_CHECK_MINUTE;
for (Config config : configs) {
for (Condition con : config.getConditions()) {
int tmpMinute = con.getMinute();
if (tmpMinute > maxMinute) {
maxMinute = tmpMinute;
}
}
}
return maxMinute;
}
@Override
public String getName() {
return "metric-alert";
}
private double[] mergerArray(double[] from, double[] to) {
int fromLength = from.length;
int toLength = to.length;
double[] result = new double[fromLength + toLength];
int index = 0;
for (int i = 0; i < fromLength; i++) {
result[i] = from[i];
index++;
}
for (int i = 0; i < toLength; i++) {
result[i + index] = to[i];
}
return result;
}
private void processMetricItemConfig(MetricItemConfig config, int minute, String product, ProductLine productLine) {
if ((!config.getAlarm() && !config.isShowAvgDashboard() && !config.isShowSumDashboard() && !config
.isShowCountDashboard())) {
return;
}
Pair<Boolean, String> alert = null;
if (config.isShowAvg()) {
alert = computeAlertInfo(minute, product, config, MetricType.AVG);
}
if (config.isShowCount()) {
alert = computeAlertInfo(minute, product, config, MetricType.COUNT);
}
if (config.isShowSum()) {
alert = computeAlertInfo(minute, product, config, MetricType.SUM);
}
if (alert != null && alert.getKey()) {
config.setId(m_metricConfigManager.buildMetricKey(config.getDomain(), config.getType(), config.getMetricKey()));
m_alertInfo.addMetric(config, new Date().getTime());
sendAlertInfo(productLine, config, alert.getValue());
}
}
private void processProductLine(ProductLine productLine) {
List<String> domains = m_productLineConfigManager.queryDomainsByProductLine(productLine.getId());
List<MetricItemConfig> configs = m_metricConfigManager.queryMetricItemConfigs(new HashSet<String>(domains));
long current = (System.currentTimeMillis()) / 1000 / 60;
int minute = (int) (current % (60)) - DATA_AREADY_MINUTE;
String product = productLine.getId();
for (MetricItemConfig config : configs) {
processMetricItemConfig(config, minute, product, productLine);
}
}
private double[] queryBaseLine(int start, int end, String baseLineKey, Date date, MetricType type) {
double[] baseline = m_baselineService.queryHourlyBaseline(MetricAnalyzer.ID, baseLineKey + ":" + type, date);
int length = end - start + 1;
double[] result = new double[length];
System.arraycopy(baseline, start, result, 0, length);
return result;
}
private double[] queryRealData(int start, int end, String metricKey, MetricReport report, MetricType type) {
double[] all = new double[60];
Map<Integer, Segment> map = report.findOrCreateMetricItem(metricKey).getSegments();
for (Entry<Integer, Segment> entry : map.entrySet()) {
Integer minute = entry.getKey();
Segment seg = entry.getValue();
if (type == MetricType.AVG) {
all[minute] = seg.getAvg();
} else if (type == MetricType.COUNT) {
all[minute] = (double) seg.getCount();
} else if (type == MetricType.SUM) {
all[minute] = seg.getSum();
}
}
int length = end - start + 1;
double[] result = new double[length];
System.arraycopy(all, start, result, 0, length);
return result;
}
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean active = true;
while (active) {
int minute = Calendar.getInstance().get(Calendar.MINUTE);
String minuteStr = String.valueOf(minute);
if (minute < 10) {
minuteStr = '0' + minuteStr;
}
Transaction t = Cat.newTransaction("MetricAlert", "M" + minuteStr);
long current = System.currentTimeMillis();
m_currentReports.clear();
m_lastReports.clear();
try {
Map<String, ProductLine> productLines = m_productLineConfigManager.getCompany().getProductLines();
for (ProductLine productLine : productLines.values()) {
try {
processProductLine(productLine);
} catch (Exception e) {
Cat.logError(e);
}
}
t.setStatus(Transaction.SUCCESS);
} catch (Exception e) {
t.setStatus(e);
} finally {
t.complete();
}
long duration = System.currentTimeMillis() - current;
try {
if (duration < DURATION) {
Thread.sleep(DURATION - duration);
}
} catch (InterruptedException e) {
active = false;
}
}
}
private void sendAlertInfo(ProductLine productLine, MetricItemConfig config, String content) {
List<String> emails = m_alertConfig.buildMailReceivers(productLine);
List<String> phones = m_alertConfig.buildSMSReceivers(productLine);
String title = m_alertConfig.buildMailTitle(productLine, config);
m_logger.info(title + " " + content + " " + emails);
m_mailSms.sendEmail(title, content, emails);
m_mailSms.sendSms(title + " " + content, content, phones);
Cat.logEvent("MetricAlert", productLine.getId(), Event.SUCCESS, title + " " + content);
}
@Override
public void shutdown() {
}
}
\ No newline at end of file
package com.dianping.cat.report.task.metric;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.unidal.tuple.Pair;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.consumer.company.model.entity.ProductLine;
import com.dianping.cat.core.dal.Project;
import com.dianping.cat.home.monitorrules.entity.Condition;
import com.dianping.cat.home.monitorrules.entity.Config;
import com.dianping.cat.home.monitorrules.entity.Subcondition;
public class SwitchAlertConfig {
private DecimalFormat m_df = new DecimalFormat("0.0");
private static final Long ONE_MINUTE_MILLSEC = 60000L;
private static final int JUDGE_DEFAULT_MINUTE = 3;
public List<String> buildExceptionSMSReceivers(ProductLine productLine) {
List<String> phones = new ArrayList<String>();
phones.add("18662513308");
return phones;
}
public List<String> buildMailReceivers(ProductLine productLine) {
List<String> emails = new ArrayList<String>();
//String emailList = productLine.getEmail();
emails.add("leon.li@dianping.com");
//emails.addAll(Splitters.by(",").noEmptyItem().split(emailList));
return emails;
}
public List<String> buildMailReceivers(Project project) {
List<String> emails = new ArrayList<String>();
//String emailList = project.getEmail();
emails.add("leon.li@dianping.com");
//emails.addAll(Splitters.by(",").noEmptyItem().split(emailList));
return emails;
}
public String buildMailTitle(ProductLine productLine, MetricItemConfig config) {
StringBuilder sb = new StringBuilder();
sb.append("[业务告警] [产品线 ").append(productLine.getTitle()).append("]");
sb.append("[业务指标 ").append(config.getTitle()).append("]");
return sb.toString();
}
public List<String> buildSMSReceivers(ProductLine productLine) {
List<String> phones = new ArrayList<String>();
//String phonesList = productLine.getPhone();
phones.add("18662513308");
//phones.addAll(Splitters.by(",").noEmptyItem().split(phonesList));
return phones;
}
public Pair<Boolean, String> checkData(MetricItemConfig config, double[] value, double[] baseline, MetricType type) {
int listLength = value.length;
int length = JUDGE_DEFAULT_MINUTE > listLength ? listLength : JUDGE_DEFAULT_MINUTE;
double[] valueTrim = getLastMinutes(value, length);
double[] baseLineTrim = getLastMinutes(baseline, length);
StringBuilder baselines = new StringBuilder();
StringBuilder values = new StringBuilder();
double decreasePercent = config.getDecreasePercentage();
double decreaseValue = config.getDecreaseValue();
double valueSum = 0;
double baselineSum = 0;
DecimalFormat df = new DecimalFormat("0.0");
if (decreasePercent == 0) {
decreasePercent = 50;
}
if (decreaseValue == 0) {
decreaseValue = 100;
}
for (int i = 0; i < length; i++) {
baselines.append(df.format(baseLineTrim[i])).append(" ");
values.append(df.format(valueTrim[i])).append(" ");
valueSum = valueSum + valueTrim[i];
baselineSum = baselineSum + baseLineTrim[i];
if (baseLineTrim[i] <= 0) {
baseLineTrim[i] = 100;
return new Pair<Boolean, String>(false, "");
}
if (type == MetricType.COUNT || type == MetricType.SUM) {
if (valueTrim[i] / baseLineTrim[i] > (1 - decreasePercent / 100)
|| (baseLineTrim[i] - valueTrim[i]) < decreaseValue) {
return new Pair<Boolean, String>(false, "");
}
}
}
double percent = (1 - valueSum / baselineSum) * 100;
StringBuilder sb = new StringBuilder();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sb.append("[基线值:").append(baselines.toString()).append("] ");
sb.append("[实际值:").append(values.toString()).append("] ");
sb.append("[下降:").append(df.format(percent)).append("%").append("]");
sb.append("[告警时间:").append(sdf.format(new Date()) + "]");
return new Pair<Boolean, String>(true, sb.toString());
}
public Pair<Boolean, String> checkData(MetricItemConfig config, double[] value, double[] baseline, MetricType type,
List<Config> configs) {
int valLength = value.length;
for (Config con : configs) {
int dataLength = getMaxMinute(con);
if (dataLength > valLength) {
continue;
}
double[] validVal = getLastMinutes(value, dataLength);
double[] validBase = getLastMinutes(baseline, dataLength);
Pair<Boolean, String> tmpResult = checkDataByConfig(config, validVal, validBase, type, con);
if (tmpResult.getKey() == true) {
return tmpResult;
}
}
return new Pair<Boolean, String>(false, "");
}
private int getMaxMinute(Config con) {
int maxMinute = 0;
for (Condition condition : con.getConditions()) {
int tmpMinute = condition.getMinute();
if (tmpMinute > maxMinute) {
maxMinute = tmpMinute;
}
}
return maxMinute;
}
private Pair<Boolean, String> checkDataByConfig(MetricItemConfig config, double[] value, double[] baseline,
MetricType type, Config con) {
int length = value.length;
StringBuilder baselines = new StringBuilder();
StringBuilder values = new StringBuilder();
double valueSum = 0;
double baselineSum = 0;
for (int i = 0; i < length; i++) {
baselines.append(m_df.format(baseline[i])).append(" ");
values.append(m_df.format(value[i])).append(" ");
valueSum = valueSum + value[i];
baselineSum = baselineSum + baseline[i];
if (baseline[i] <= 0) {
baseline[i] = 100;
return new Pair<Boolean, String>(false, "");
}
if (type == MetricType.COUNT || type == MetricType.SUM) {
if (!judgeByRule(con, value[i], baseline[i], i, length)) {
return new Pair<Boolean, String>(false, "");
}
}
}
double percent = (1 - valueSum / baselineSum) * 100;
StringBuilder sb = new StringBuilder();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sb.append("[基线值:").append(baselines.toString()).append("] ");
sb.append("[实际值:").append(values.toString()).append("] ");
sb.append("[下降:").append(m_df.format(percent)).append("%").append("]");
sb.append("[告警时间:").append(sdf.format(new Date()) + "]");
return new Pair<Boolean, String>(true, sb.toString());
}
private double[] getLastMinutes(double[] doubleList, int remainCount) {
double[] result = new double[remainCount];
int startIndex = doubleList.length - remainCount;
for (int i = 0; i < remainCount; i++) {
result[i] = doubleList[startIndex + i];
}
return result;
}
private Long getMillsByString(String time) throws Exception {
String[] times = time.split(":");
int hour = Integer.parseInt(times[0]);
int minute = Integer.parseInt(times[1]);
long result = hour * 60 * 60 * 1000 + minute * 60 * 1000;
return result;
}
private boolean judgeByRule(Config ruleConfig, double value, double baseline, int index, int length) {
boolean isRuleTriggered = false;
long ruleStartTime;
long ruleEndTime;
long nowTime = (System.currentTimeMillis() + 8 * 60 * 60 * 1000) % (24 * 60 * 60 * 1000);
try {
ruleStartTime = getMillsByString(ruleConfig.getStarttime());
ruleEndTime = getMillsByString(ruleConfig.getEndtime()) + ONE_MINUTE_MILLSEC;
} catch (Exception ex) {
ruleStartTime = 0L;
ruleEndTime = 86400000L;
}
if (nowTime < ruleStartTime || nowTime > ruleEndTime) {
return false;
}
for (Condition condition : ruleConfig.getConditions()) {
if (isRuleTriggered) {
break;
}
int minute = condition.getMinute();
if (minute == 0) {
minute = JUDGE_DEFAULT_MINUTE;
}
if (index < length - minute) {
continue;
}
boolean isSubRuleTriggered = true;
for (Subcondition subCondition : condition.getSubconditions()) {
if (!isSubRuleTriggered) {
break;
}
String ruleType = subCondition.getType();
int ruleValue = Integer.parseInt(subCondition.getText());
RuleType rule = RuleType.getByTypeId(ruleType);
if (rule == null) {
continue;
} else {
isSubRuleTriggered = rule.executeRule(value, baseline, ruleValue);
}
}
if (isSubRuleTriggered) {
isRuleTriggered = true;
}
}
return isRuleTriggered;
}
}
package com.dianping.cat.system.config;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.dal.jdbc.DalNotFoundException;
import org.unidal.helper.Files;
import org.unidal.lookup.annotation.Inject;
import com.dianping.cat.Cat;
import com.dianping.cat.core.config.Config;
import com.dianping.cat.core.config.ConfigDao;
import com.dianping.cat.core.config.ConfigEntity;
import com.dianping.cat.home.monitorrules.entity.MetricItem;
import com.dianping.cat.home.monitorrules.entity.MonitorRules;
import com.dianping.cat.home.monitorrules.entity.Rule;
import com.dianping.cat.home.monitorrules.transform.DefaultSaxParser;
public class MetricRuleConfigManager implements Initializable {
@Inject
private ConfigDao m_configDao;
private int m_configId;
private MonitorRules m_config;
private static final String CONFIG_NAME = "monitorRulesConfig";
public Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> getMetricIdRuleMap() {
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> map = new HashMap<String, List<com.dianping.cat.home.monitorrules.entity.Config>>();
for (Rule rule : m_config.getRules()) {
for (MetricItem metricItem : rule.getMetricItems()) {
String type = metricItem.getType();
if (type == null || !type.equals("id")) {
continue;
}
String key = metricItem.getText();
List<com.dianping.cat.home.monitorrules.entity.Config> configs = getOrBuildRuleList(map, key);
configs.addAll(rule.getConfigs());
}
}
return map;
}
public MonitorRules getMonitorRules() {
return m_config;
}
private List<com.dianping.cat.home.monitorrules.entity.Config> getOrBuildRuleList(
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> map, String key) {
List<com.dianping.cat.home.monitorrules.entity.Config> configs = map.get(key);
if (configs == null) {
configs = new ArrayList<com.dianping.cat.home.monitorrules.entity.Config>();
map.put(key, configs);
}
return configs;
}
public List<com.dianping.cat.home.monitorrules.entity.Config> getConfigs(String product, String domain, String key,
String metricKey) {
List<com.dianping.cat.home.monitorrules.entity.Config> configs = new ArrayList<com.dianping.cat.home.monitorrules.entity.Config>();
for (Rule rule : m_config.getRules()) {
for (MetricItem metricItem : rule.getMetricItems()) {
String type = metricItem.getType();
if (type == null) {
continue;
} else if (type.equals("id")) {
String context = metricItem.getText();
if (context != null && context.equals(metricKey)) {
configs.addAll(rule.getConfigs());
break;
}
} else if (type.equals("regex")) {
String[] context = metricItem.getText().split(":");
Pattern p = Pattern.compile(context[0]);
Matcher m = p.matcher(product);
if (!m.find()) {
continue;
}
p = Pattern.compile(context[1]);
m = p.matcher(domain);
if (!m.find()) {
continue;
}
p = Pattern.compile(context[2]);
m = p.matcher(key);
if (m.find()) {
configs.addAll(rule.getConfigs());
break;
}
}
}
}
return configs;
}
@Override
public void initialize() throws InitializationException {
try {
Config config = m_configDao.findByName(CONFIG_NAME, ConfigEntity.READSET_FULL);
String content = config.getContent();
m_config = DefaultSaxParser.parse(content);
m_configId = config.getId();
} catch (DalNotFoundException e) {
try {
String content = Files.forIO().readFrom(
this.getClass().getResourceAsStream("/config/default-metric-rule-config.xml"), "utf-8");
Config config = m_configDao.createLocal();
config.setName(CONFIG_NAME);
config.setContent(content);
m_configDao.insert(config);
m_config = DefaultSaxParser.parse(content);
m_configId = config.getId();
} catch (Exception ex) {
Cat.logError(ex);
}
} catch (Exception e) {
Cat.logError(e);
}
if (m_config == null) {
m_config = new MonitorRules();
}
}
public boolean insert(String xml) {
try {
m_config = DefaultSaxParser.parse(xml);
return storeConfig();
} catch (Exception e) {
Cat.logError(e);
return false;
}
}
private boolean storeConfig() {
synchronized (this) {
try {
Config config = m_configDao.createLocal();
config.setId(m_configId);
config.setKeyId(m_configId);
config.setName(CONFIG_NAME);
config.setContent(m_config.toString());
m_configDao.updateByPK(config, ConfigEntity.UPDATESET_FULL);
} catch (Exception e) {
Cat.logError(e);
return false;
}
}
return true;
}
}
......@@ -46,6 +46,8 @@ public enum Action implements org.unidal.web.mvc.Action {
METRIC_CONFIG_ADD_OR_UPDATE_SUBMIT("metricConfigAddSumbit"),
METRIC_CONFIG_DELETE("metricConfigDelete"),
METRIC_RULE_CONFIG_UPDATE("metricRuleConfigUpdate"),
EXCEPTION_THRESHOLDS("exceptionThresholds"),
......
......@@ -49,6 +49,7 @@ import com.dianping.cat.system.config.DomainGroupConfigManager;
import com.dianping.cat.system.config.ExceptionThresholdConfigManager;
import com.dianping.cat.system.config.MetricAggregationConfigManager;
import com.dianping.cat.system.config.MetricGroupConfigManager;
import com.dianping.cat.system.config.MetricRuleConfigManager;
import com.dianping.cat.system.config.UtilizationConfigManager;
public class Handler implements PageHandler<Context> {
......@@ -88,6 +89,9 @@ public class Handler implements PageHandler<Context> {
@Inject
private MetricAggregationConfigManager m_metricAggregationConfigManager;
@Inject
private MetricRuleConfigManager m_metricRuleConfigManager;
@Inject
private DomainNavManager m_manager;
......@@ -285,6 +289,15 @@ public class Handler implements PageHandler<Context> {
payload.getDomain(), payload.getType(), payload.getMetricKey())));
metricConfigList(payload, model);
break;
case METRIC_RULE_CONFIG_UPDATE:
String metricRuleConfig = payload.getContent();
if (!StringUtils.isEmpty(metricRuleConfig)) {
model.setOpState(m_metricRuleConfigManager.insert(metricRuleConfig));
} else {
model.setOpState(true);
}
model.setContent(m_metricRuleConfigManager.getMonitorRules().toString());
break;
case EXCEPTION_THRESHOLDS:
model.setExceptionLimits(m_exceptionConfigManager.queryAllExceptionLimits());
break;
......
......@@ -26,6 +26,8 @@ public enum JspFile {
METRIC_CONFIG_ADD_OR_UPDATE_SUBMIT("/jsp/system/metric/metricConfigs.jsp"),
METRIC_CONFIG_LIST("/jsp/system/metric/metricConfigs.jsp"),
METRIC_RULE_CONFIG_UPDATE("/jsp/system/metricRule/metricRuleConfig.jsp"),
EXCEPTION_THRESHOLD("/jsp/system/exception/exceptionThreshold.jsp"),
......
......@@ -60,6 +60,8 @@ public class JspViewer extends BaseJspViewer<SystemPage, Action, Context, Model>
return JspFile.METRIC_CONFIG_LIST.getPath();
case METRIC_CONFIG_DELETE:
return JspFile.METRIC_CONFIG_LIST.getPath();
case METRIC_RULE_CONFIG_UPDATE:
return JspFile.METRIC_RULE_CONFIG_UPDATE.getPath();
// Excepton Config
case EXCEPTION_THRESHOLDS:
return JspFile.EXCEPTION_THRESHOLD.getPath();
......
<?xml version="1.0" encoding="UTF-8"?>
<model>
<entity name="monitor-rules" root="true">
<entity-ref name="rule" type="list" names="rules" />
</entity>
<entity name="rule">
<attribute name="id" value-type="String" />
<entity-ref name="metric-item" type="list" names="metric-items" />
<entity-ref name="config" type="list" names="configs" />
</entity>
<entity name="metric-item">
<attribute name="type" value-type="String" />
<element name="text" value-type="String" text="true" />
</entity>
<entity name="config">
<attribute name="starttime" value-type="String" />
<attribute name="endtime" value-type="String" />
<entity-ref name="condition" type="list" names="conditions" />
</entity>
<entity name="condition">
<attribute name="title" value-type="String" />
<entity-ref name="subcondition" type="list" names="subconditions" />
</entity>
<entity name="subcondition">
<attribute name="type" value-type="int" />
<element name="text" value-type="String" text="true" />
</entity>
</model>
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<file path="monitor-rules-codegen.xml" />
<file path="monitor-rules-model.xml" />
</manifest>
<?xml version="1.0" encoding="UTF-8"?>
<model model-package="com.dianping.cat.home.monitorrules"
enable-sax-parser="true" enable-xml-parser="true" enable-xml-builder="true">
<entity name="monitor-rules" root="true">
<entity-ref name="rule" type="list" names="rules" />
</entity>
<entity name="rule">
<attribute name="id" value-type="String" />
<entity-ref name="metric-item" type="list" names="metric-items" />
<entity-ref name="config" type="list" names="configs" />
</entity>
<entity name="metric-item">
<attribute name="type" value-type="String" />
<element name="text" value-type="String" text="true" />
</entity>
<entity name="config">
<attribute name="starttime" value-type="String" />
<attribute name="endtime" value-type="String" />
<entity-ref name="condition" type="list" names="conditions" />
</entity>
<entity name="condition">
<attribute name="title" value-type="String" />
<attribute name="minute" value-type="int" default-value="2"/>
<entity-ref name="subcondition" type="list" names="subconditions" />
</entity>
<entity name="subcondition">
<attribute name="type" value-type="String" />
<element name="text" value-type="String" text="true" />
</entity>
</model>
......@@ -3471,6 +3471,9 @@
<requirement>
<role>com.dianping.cat.system.config.MetricAggregationConfigManager</role>
</requirement>
<requirement>
<role>com.dianping.cat.system.config.MetricRuleConfigManager</role>
</requirement>
<requirement>
<role>com.dianping.cat.report.view.DomainNavManager</role>
</requirement>
......@@ -3506,6 +3509,15 @@
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.system.config.MetricRuleConfigManager</role>
<implementation>com.dianping.cat.system.config.MetricRuleConfigManager</implementation>
<requirements>
<requirement>
<role>com.dianping.cat.core.config.ConfigDao</role>
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.system.page.plugin.Handler</role>
<implementation>com.dianping.cat.system.page.plugin.Handler</implementation>
......
......@@ -39,6 +39,9 @@
<model package="com.dianping.cat.home.metricAggregation" name="metric-aggregation-config">
<sample-model>src/main/resources/config/default-metric-aggregation-config.xml</sample-model>
</model>
<model package="com.dianping.cat.home.monitor-rules" name="monitor-rules">
<sample-model>/Users/leon/Documents/GitRepo/cat/rule.xml</sample-model>
</model>
<model package="com.dianping.cat.home.netgraph" name="netgraph">
<sample-model>src/main/resources/config/default-nettopology-config.xml</sample-model>
</model>
......
<monitor-rules>
<rule id="switchErrorAndDiscard">
<metric-item type="regex">
f5[^:]*:[^:]+:.*(?=errors$)
</metric-item>
<metric-item type="regex">
f5[^:]*:[^:]+:.*(?=discards$)
</metric-item>
<metric-item type="regex">
switch[^:]*:[^:]+:.*(?=errors$)
</metric-item>
<metric-item type="regex">
switch[^:]*:[^:]+:.*(?=discards$)
</metric-item>
<config starttime="00:00" endtime="24:00">
<condition minute="3">
<subcondition type="MaxVal">3</subcondition>
</condition>
</config>
</rule>
<rule id="switchInAndOut">
<metric-item type="regex">
f5[^:]*:[^:]+:.*(?=in$)
</metric-item>
<metric-item type="regex">
f5[^:]*:[^:]+:.*(?=out$)
</metric-item>
<metric-item type="regex">
switch[^:]*:[^:]+:.*(?=in$)
</metric-item>
<metric-item type="regex">
switch[^:]*:[^:]+:.*(?=out$)
</metric-item>
<config starttime="00:00" endtime="24:00">
<condition minute="2">
<subcondition type="DescPer">50</subcondition>
</condition>
</config>
</rule>
</monitor-rules>
......@@ -21,6 +21,10 @@
<a id="refresh10" class='btn btn-small btn-primary' onclick="queryFrequency(10)">10秒</a>
<a id="refresh20" class='btn btn-small btn-primary' onclick="queryFrequency(20)">20秒</a>
<a id="refresh30" class='btn btn-small btn-primary' onclick="queryFrequency(30)">30秒</a>
类型
<input type="checkbox" checked="checked" id="show_puppet" class="typeCheckbox"/> puppet
<input type="checkbox" checked="checked" id="show_workflow" class="typeCheckbox"/> workflow
<input type="checkbox" checked="checked" id="show_lazyman" class="typeCheckbox"/> lazyman
<br>
<div class="btn-group">
......@@ -28,6 +32,19 @@
</div>
<script>
function typeCheckStr(){
var result = "";
if(!document.getElementById("show_puppet").checked){
result += "showPuppet=false&";
}
if(!document.getElementById("show_workflow").checked){
result += "showWorkflow=false&";
}
if(!document.getElementById("show_lazyman").checked){
result += "showLazyman=false&";
}
return result;
}
function queryNew(){
var startTime=$("#startTime").val();
var endTime=$("#endTime").val();
......@@ -36,14 +53,16 @@
window.location.href="?op=view&domain="+domain+"&startTime="+startTime+"&endTime="+endTime+"&hostname="+hostname;
}
function queryFullScreen(isFullScreen){
var typeStatus = typeCheckStr();
<c:if test="${payload.refresh}">
window.location.href="?domain=${payload.domain}&hostname=${payload.hostname}&fullScreen="+isFullScreen+"&refresh=${payload.refresh}&frequency=${payload.frequency}";
window.location.href="?"+typeStatus+"domain=${payload.domain}&hostname=${payload.hostname}&fullScreen="+isFullScreen+"&refresh=${payload.refresh}&frequency=${payload.frequency}";
</c:if>
<c:if test="${!payload.refresh}">
window.location.href="?domain=${payload.domain}&hostname=${payload.hostname}&fullScreen="+isFullScreen+"&refresh=${payload.refresh}&frequency=${payload.frequency}&startTime=<fmt:formatDate value="${payload.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/>&endTime=<fmt:formatDate value="${payload.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/>";
window.location.href="?"+typeStatus+"domain=${payload.domain}&hostname=${payload.hostname}&fullScreen="+isFullScreen+"&refresh=${payload.refresh}&frequency=${payload.frequency}&startTime=<fmt:formatDate value="${payload.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/>&endTime=<fmt:formatDate value="${payload.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/>";
</c:if>
}
function queryFrequency(frequency){
window.location.href="?domain=${payload.domain}&hostname=${payload.hostname}&fullScreen=${payload.fullScreen}&refresh=true&frequency="+frequency;
var typeStatus = typeCheckStr();
window.location.href="?"+typeStatus+"domain=${payload.domain}&hostname=${payload.hostname}&fullScreen=${payload.fullScreen}&refresh=true&frequency="+frequency;
}
</script>
\ No newline at end of file
......@@ -23,16 +23,16 @@
<th width="12%">机器名</th>
</tr>
<c:forEach var="item" items="${model.alterations}" varStatus="status">
<tr class="aleration_${item.type}">
<tr class="content_${item.type}" style="display:table-row">
<td>${w:format(item.date,'yyyy-MM-dd HH:mm:ss')}</td>
<td>${item.type}</td>
<td class="aleration_${item.type}">${item.type}</td>
<td class="text-info">
<c:choose>
<c:when test="${empty item.url}">
<span class="hreftip" data-toggle="tooltip" data-placement="top" title="" data-original-title="${item.content}">${item.title}</span>
</c:when>
<c:otherwise>
<a class="hreftip" target="_blank" href="${item.url}" data-toggle="tooltip" data-placement="top" title="" data-original-title="${item.content}">${item.title}</a>
<a class="hreftip out_url" target="_blank" href="${item.url}" data-toggle="tooltip" data-placement="top" title="" data-original-title="${item.content}">${item.title}</a>
</c:otherwise>
</c:choose>
</td>
......@@ -47,6 +47,11 @@
$('i[tips]').popover();
$('.hreftip').tooltip({container:'body', html:true, delay:{show:0, hide:0}});
$(".out_url").each(function(){
var cur = $(this);
cur.attr("href", decodeURIComponent(cur.attr("href")));
});
<c:if test="${payload.fullScreen}">
$('#fullScreen').addClass('btn-danger');
$('.navbar').hide();
......@@ -58,14 +63,31 @@
$('.footer').show();
</c:if>
$(".typeButton").click(function(){
var type = "."+this.id.replace("Button","");
if($(type).css("display")=="table-cell"){
$(this).removeClass("btn-primary");
$(type).css("display","none");
}else if($(type).css("display")=="none"){
$(this).addClass("btn-primary");
$(type).css("display","table-cell");
<c:if test="${!payload.showPuppet}">
$("#show_puppet").attr("checked",false);
$(".content_puppet").css("display","none");
</c:if>
<c:if test="${!payload.showWorkflow}">
$("#show_workflow").attr("checked",false);
$(".content_workflow").css("display","none");
</c:if>
<c:if test="${!payload.showLazyman}">
$("#show_lazyman").attr("checked",false);
$(".content_lazyman").css("display","none");
</c:if>
$(".typeCheckbox").click(function(){
var typeContent = ".content_"+this.id.replace("show_","");
var isChecked = document.getElementById(this.id).checked;
if(!isChecked){
$(this).attr("checked",false);
$(typeContent).css("display","none");
}else{
$(this).attr("checked",true);
$(typeContent).css("display","table-row");
}
})
......
......@@ -21,6 +21,7 @@
<li class="text-right"><a href="#tab1" data-toggle="tab"><strong>版本说明</strong></a></li>
<li class="text-right"><a href="#tab2" data-toggle="tab"><strong>集成文档</strong></a></li>
<li class="text-right"><a href="#tab3" data-toggle="tab"><strong>业务监控</strong></a></li>
<li class="text-right"><a href="#tab12" data-toggle="tab"><strong>规则设置</strong></a></li>
<li class="text-right"><a href="#tab4" data-toggle="tab"><strong>变更监控</strong></a></li>
<li class="text-right"><a href="#tab5" data-toggle="tab"><strong>网络监控</strong></a></li>
<li class="text-right"><a href="#tab6" data-toggle="tab"><strong>异常监控</strong></a></li>
......@@ -43,6 +44,7 @@
<div class="tab-pane" id="tab9"><%@ include file="userDocument.jsp"%></div>
<div class="tab-pane" id="tab10"><%@ include file="problem.jsp"%></div>
<div class="tab-pane" id="tab11"><%@ include file="plugin.jsp"%></div>
<div class="tab-pane" id="tab12"><%@ include file="monitorRule.jsp"%></div>
</div>
</div>
</div>
......
<%@ page session="false" language="java" pageEncoding="UTF-8" %>
<h3 class="text-error">监控规则配置文档</h3>
</br>
<h4 class="text-info">配置规则的要点</h4>
<h5>合理、灵活的监控规则可以帮助更快、更精确的发现业务线上故障。目前Cat的监控规则有五个要素,请按照以下五点要素制定规则:</h5>
<h5>a).时间段。同一项业务指标在每天不同的时段可能有不同的趋势。设定该项,可让Cat在每天不同的时间段执行不同的监控规则。</h5>
<h5>b).规则组合。在一个时间段中,可能指标触发了多个监控规则中的一个规则就要发出警报,也有可能指标要同时触发了多个监控规则才需要发出警报。这种关系好比电路图中的并联和串联。规则的组合合理有助于提高监控的准确度。</h5>
<h5>c).监控类型。通过以下六种类型对指标进行监控:下降百分比、下降数值、上升百分比、上升数值、最大值、最小值。</h5>
<h5>d).持续时间。设定时间后(单位为分钟),当指标在设定的时间长度内连续触发了监控规则,才会发出警报。</h5>
<h5>e).规则与指标的匹配。监控规则可以按照名称、正则表达式与监控的对象(指标)进行匹配。</h5>
</br>
<h4 class="text-info">监控规则的设定方法</h4>
<h4 class="text-success">第一步:进入配置页面</h4>
<p>点击导航栏右侧的"Config"选项</p>
<p>在新页面中点击左侧边栏下方的“业务告警配置”选项</p>
<p>右方的页面上会显示一个xml,对其进行下步的配置。</p>
</br>
<h4 class="text-success">第二步:更改配置信息</h4>
<h5>配置文件格式如下:</h5>
<img class="img-polaroid" width='60%' src="${model.webapp}/images/rule.png"/>
<h5>配置方式如下:</h5>
<p> 1).每一个rule元素为规则的基本单位。请按照需求添加一个rule元素或者对某一个rule进行修改</p>
<p> 2).rule元素由两个部分组成:监控对象与监控规则</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;a.监控对象:由metric-item元素匹配。metric-item元素可以有多个。metric-item支持两种匹配方式:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1) 按照id匹配。此种方式适用于匹配一个具体的监控指标。此时type为id,内容为 <b>产品线:项目名:指标</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(2) 按照正则表达式匹配。此种情况适用于同时匹配多个监控对象。此时type为regex,内容仍形如 <b>产品线:项目名:指标</b>,三者用冒号分割。三者每一项都可以写为正则表达式。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;b.监控条件配置:由config元素组成,每个config代表一个时间段的规则,由starttime和endtime两个属性确定。时间的配置格式为:“hh:mm”,请注意hh为24小时制。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;config元素由多个监控条件组成,条件由condition元素表示。一个config下的多个condition为并联关系,当一个condition被触发,conditon所在的整个rule就被触发。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;condition元素中的minute属性表示该条件的持续时间。设定时间单位为分钟。当指标在设定的时间长度内连续触发了该条规则,才会出发该condition。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;condition由subcondition组成。一个condition下的多个subcondition为串联关系,只有当一个condition下的全部subcondition被触发,该condition才被触发。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;subcondition有六个类型,由type属性指定。subcondition的内容为对应的阈值,请注意阈值只能由数字组成,当阈值表达百分比时,不能在最后加上百分号。六种类型如下:</p>
<table style="width:50%" class="table table-striped table-bordered table-condensed">
<tr><th width="30%">类型</th><th>说明</th></tr>
<tr><td>DescPer</td><td>下降百分比</td></tr>
<tr><td>DescVal</td><td>下降数值</td></tr>
<tr><td>AscPer</td><td>上升百分比</td></tr>
<tr><td>AscVal</td><td>上升数值</td></tr>
<tr><td>MaxVal</td><td>最大值</td></tr>
<tr><td>MinVal</td><td>最小值</td></tr>
</table>
<p> 3).点击提交功能。如果标题“业务监控规则相关信息”上方出现“操作成功”的提示,代表规则添加成功,将会在下次执行时被应用</p>
\ No newline at end of file
......@@ -10,6 +10,7 @@
<li class="text-right" id="exceptionConfigList"><a href="?op=exceptionThresholds"><strong>异常阀值配置</strong></a></li>
<li class='nav-header'><h4>其他配置</h4></li>
<li class="text-right" id="metricConfigList"><a href="?op=metricConfigList"><strong>业务监控规则</strong></a></li>
<li class="text-right" id="metricRuleConfigUpdate"><a href="?op=metricRuleConfigUpdate"><strong>业务告警配置</strong></a></li>
<li class="text-right" id="metricGroupConfigUpdate"><a href="?op=metricGroupConfigUpdate"><strong>业务指标分组</strong></a></li>
<li class="text-right" id="metricAggregationConfigUpdate"><a href="?op=metricAggregationConfigUpdate"><strong>业务指标汇总</strong></a></li>
<li class="text-right" id="bugConfigUpdate"><a href="?op=bugConfigUpdate"><strong>异常规范配置</strong></a></li>
......
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="a" uri="/WEB-INF/app.tld"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="res" uri="http://www.unidal.org/webres"%>
<%@ taglib prefix="w" uri="http://www.unidal.org/web/core"%>
<a:body>
<res:useJs value="${res.js.local['jquery.validate.min.js']}" target="head-js" />
<res:useJs value="${res.js.local['dependencyConfig.js']}" target="head-js" />
<res:useJs value="${res.js.local['alarm_js']}" target="head-js" />
<res:useCss value="${res.css.local['select2.css']}" target="head-css" />
<res:useJs value="${res.js.local['select2.min.js']}" target="head-js" />
<div class="row-fluid">
<div class="span2">
<%@include file="../configTree.jsp"%>
</div>
<div class="span10">
<form name="metricRuleConfigUpdate" id="form" method="post"
action="${model.pageUri}?op=metricRuleConfigUpdate">
<h4 class="text-center text-error" id="state">&nbsp;</h4>
<h4 class="text-center text-error">业务监控规则相关信息</h4>
<table class="table table-striped table-bordered table-condensed table-hover">
<tr>
<td><textarea name="content" style="width:auto" rows="20" cols="150">${model.content}</textarea></td>
</tr>
<tr>
<td style="text-align:center"><input class='btn btn-primary'
type="submit" name="submit" value="提交" /></td>
</tr>
</table>
</form>
</div>
</div>
</a:body>
<script type="text/javascript">
$(document).ready(function() {
$('#metricRuleConfigUpdate').addClass('active');
var state = '${model.opState}';
if(state=='Success'){
$('#state').html('操作成功');
}else{
$('#state').html('操作失败');
}
setInterval(function(){
$('#state').html('&nbsp;');
},3000);
});
</script>
\ No newline at end of file
package com.dianping.cat.demo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.unidal.helper.Files;
import org.unidal.tuple.Pair;
import com.dianping.cat.Cat;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.home.monitorrules.entity.MonitorRules;
import com.dianping.cat.home.monitorrules.entity.Rule;
import com.dianping.cat.home.monitorrules.transform.DefaultSaxParser;
import com.dianping.cat.report.task.metric.AlertConfig;
import com.dianping.cat.report.task.metric.MetricType;
public class RuleConfigTest {
private MonitorRules buildMonitorRuleFromFile(String path) {
try {
String content = Files.forIO().readFrom(this.getClass().getResourceAsStream(path), "utf-8");
return DefaultSaxParser.parse(content);
} catch (Exception ex) {
Cat.logError(ex);
return null;
}
}
private Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> buildConfigMap(MonitorRules monitorRules) {
if (monitorRules == null || monitorRules.getRules().size() == 0) {
return null;
}
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> map = new HashMap<String, List<com.dianping.cat.home.monitorrules.entity.Config>>();
for (Rule rule : monitorRules.getRules()) {
map.put(rule.getId(), rule.getConfigs());
}
return map;
}
@Test
public void testRule() {
AlertConfig alertConfig = new AlertConfig();
MetricItemConfig config = new MetricItemConfig();
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> configMap = buildConfigMap(buildMonitorRuleFromFile("/config/demo-rule-monitor.xml"));
Assert.assertNotNull(configMap);
double baseline[] = { 200, 200 };
double value[] = { 100, 100 };
Pair<Boolean, String> result = alertConfig.checkData(config, value, baseline, MetricType.COUNT,
configMap.get("demo1"));
Assert.assertEquals(result.getKey().booleanValue(), true);
}
@Test
public void testCondition() {
AlertConfig alertConfig = new AlertConfig();
MetricItemConfig config = new MetricItemConfig();
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> configMap = buildConfigMap(buildMonitorRuleFromFile("/config/demo-rule-monitor.xml"));
Pair<Boolean, String> result;
Assert.assertNotNull(configMap);
double[] baseline7 = { 200, 200 };
double[] value7 = { 100, 100 };
result = alertConfig
.checkData(config, value7, baseline7, MetricType.COUNT, configMap.get("conditionCombination"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline8 = { 200, 200 };
double[] value8 = { 100, 100 };
result = alertConfig.checkData(config, value8, baseline8, MetricType.COUNT,
configMap.get("subconditionCombination"));
Assert.assertEquals(result.getKey().booleanValue(), false);
}
@Test
public void testMinute() {
AlertConfig alertConfig = new AlertConfig();
MetricItemConfig config = new MetricItemConfig();
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> configMap = buildConfigMap(buildMonitorRuleFromFile("/config/test-minute-monitor.xml"));
Assert.assertNotNull(configMap);
double baseline[] = { 50, 200, 200 };
double value[] = { 50, 100, 100 };
Pair<Boolean, String> result = alertConfig.checkData(config, value, baseline, MetricType.COUNT,
configMap.get("two-minute"));
Assert.assertEquals(result.getKey().booleanValue(), true);
}
}
package com.dianping.cat.report.task.metric;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import org.unidal.helper.Files;
import org.unidal.tuple.Pair;
import com.dianping.cat.Cat;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.home.monitorrules.entity.MonitorRules;
import com.dianping.cat.home.monitorrules.entity.Rule;
import com.dianping.cat.home.monitorrules.transform.DefaultSaxParser;
public class AlertConfigTest {
private MonitorRules buildMonitorRuleFromFile(String path) {
try {
String content = Files.forIO().readFrom(this.getClass().getResourceAsStream(path), "utf-8");
return DefaultSaxParser.parse(content);
} catch (Exception ex) {
Cat.logError(ex);
return null;
}
}
private Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> buildConfigMap(MonitorRules monitorRules) {
if (monitorRules == null || monitorRules.getRules().size() == 0) {
return null;
}
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> map = new HashMap<String, List<com.dianping.cat.home.monitorrules.entity.Config>>();
for (Rule rule : monitorRules.getRules()) {
map.put(rule.getId(), rule.getConfigs());
}
return map;
}
@Test
public void test() {
AlertConfig alertConfig = new AlertConfig();
......@@ -48,17 +81,17 @@ public class AlertConfigTest {
config.setDecreasePercentage(79);
result = alertConfig.checkData(config, value4, baseline4, MetricType.COUNT);
Assert.assertEquals(result.getKey().booleanValue(), true);
config.setDecreaseValue(40);
config.setDecreasePercentage(80);
result = alertConfig.checkData(config, value4, baseline4, MetricType.COUNT);
Assert.assertEquals(result.getKey().booleanValue(), false);
config.setDecreaseValue(40);
config.setDecreasePercentage(80);
result = alertConfig.checkData(config, value4, baseline4, MetricType.COUNT);
Assert.assertEquals(result.getKey().booleanValue(), false);
double[] baseline5 = { 117, 118 };
double[] value5 = { 43, 48 };
config.setDecreasePercentage(50);
......@@ -66,4 +99,71 @@ public class AlertConfigTest {
result = alertConfig.checkData(config, value5, baseline5, MetricType.COUNT);
Assert.assertEquals(result.getKey().booleanValue(), true);
}
@Test
public void testRule() {
AlertConfig alertConfig = new AlertConfig();
MetricItemConfig config = new MetricItemConfig();
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> configMap = buildConfigMap(buildMonitorRuleFromFile("/config/test-rule-monitor.xml"));
Assert.assertNotNull(configMap);
double baseline[] = { 200, 200 };
double value[] = { 100, 100 };
Pair<Boolean, String> result = alertConfig.checkData(config, value, baseline, MetricType.COUNT,
configMap.get("decreasePercentage"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline2 = { 200, 300 };
double[] value2 = { 100, 100 };
result = alertConfig.checkData(config, value2, baseline2, MetricType.COUNT, configMap.get("decreaseValue"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline3 = { 200, 50 };
double[] value3 = { 400, 100 };
result = alertConfig.checkData(config, value3, baseline3, MetricType.COUNT, configMap.get("increasePercentage"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline4 = { 200, 50 };
double[] value4 = { 400, 100 };
result = alertConfig.checkData(config, value4, baseline4, MetricType.COUNT, configMap.get("increaseValue"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline5 = { 200, 200 };
double[] value5 = { 500, 600 };
result = alertConfig.checkData(config, value5, baseline5, MetricType.COUNT, configMap.get("absoluteMaxValue"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline6 = { 200, 200 };
double[] value6 = { 50, 40 };
result = alertConfig.checkData(config, value6, baseline6, MetricType.COUNT, configMap.get("absoluteMinValue"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline7 = { 200, 200 };
double[] value7 = { 100, 100 };
result = alertConfig
.checkData(config, value7, baseline7, MetricType.COUNT, configMap.get("conditionCombination"));
Assert.assertEquals(result.getKey().booleanValue(), true);
double[] baseline8 = { 200, 200 };
double[] value8 = { 100, 100 };
result = alertConfig.checkData(config, value8, baseline8, MetricType.COUNT,
configMap.get("subconditionCombination"));
Assert.assertEquals(result.getKey().booleanValue(), false);
}
@Test
public void testMinute() {
AlertConfig alertConfig = new AlertConfig();
MetricItemConfig config = new MetricItemConfig();
Map<String, List<com.dianping.cat.home.monitorrules.entity.Config>> configMap = buildConfigMap(buildMonitorRuleFromFile("/config/test-minute-monitor.xml"));
Assert.assertNotNull(configMap);
double baseline[] = { 50, 200, 200 };
double value[] = { 50, 100, 100 };
Pair<Boolean, String> result = alertConfig.checkData(config, value, baseline, MetricType.COUNT,
configMap.get("two-minute"));
Assert.assertEquals(result.getKey().booleanValue(), true);
}
}
<monitor-rules>
<rule id="demo1">
<metric-item type="id">
f5-2400-1-dianping-com:2400-1-dianping-com:1/1-1-in
</metric-item>
<metric-item type="regex">
switch\w*:\w*:\w*in\w*
</metric-item>
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescPer">40</subcondition>
</condition>
<condition>
<subcondition type="DescVal">200</subcondition>
</condition>
</config>
</rule>
<rule id="conditionCombination">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">400</subcondition>
</condition>
<condition>
<subcondition type="DescPer">400</subcondition>
<subcondition type="DescVal">900</subcondition>
</condition>
<condition> <!-- trigger alert -->
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">100</subcondition>
</condition>
</config>
</rule>
<rule id="subconditionCombination">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">80</subcondition>
<!-- block alert -->
<subcondition type="MinVal">10</subcondition>
</condition>
</config>
</rule>
</monitor-rules>
<monitor-rules>
<rule id="two-minute">
<config starttime="00:00" endtime="24:00">
<condition minute="2">
<subcondition type="DescPer">40</subcondition>
</condition>
<condition minute="2">
<subcondition type="DescVal">80</subcondition>
</condition>
</config>
</rule>
</monitor-rules>
<monitor-rules>
<rule id="decreasePercentage">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
</condition>
<condition>
<subcondition type="DescVal">200</subcondition>
</condition>
</config>
</rule>
<rule id="decreaseValue">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">200</subcondition>
</condition>
<condition>
<subcondition type="DescVal">95</subcondition>
</condition>
</config>
</rule>
<rule id="increasePercentage">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">200</subcondition>
</condition>
<condition>
<subcondition type="AscPer">49</subcondition>
</condition>
</config>
</rule>
<rule id="increaseValue">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">200</subcondition>
</condition>
<condition>
<subcondition type="AscVal">49</subcondition>
</condition>
</config>
</rule>
<rule id="absoluteMaxValue">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">200</subcondition>
</condition>
<condition>
<subcondition type="MaxVal">450</subcondition>
</condition>
</config>
</rule>
<rule id="absoluteMinValue">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">200</subcondition>
</condition>
<condition>
<subcondition type="MinVal">51</subcondition>
</condition>
</config>
</rule>
<rule id="conditionCombination">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">400</subcondition>
</condition>
<condition>
<subcondition type="DescPer">400</subcondition>
<subcondition type="DescVal">900</subcondition>
</condition>
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">100</subcondition>
</condition>
</config>
</rule>
<rule id="subconditionCombination">
<config starttime="00:00" endtime="24:00">
<condition>
<subcondition type="DescPer">400</subcondition>
</condition>
<condition>
<subcondition type="DescPer">400</subcondition>
<subcondition type="DescVal">900</subcondition>
</condition>
<condition>
<subcondition type="DescPer">40</subcondition>
<subcondition type="DescVal">200</subcondition>
<subcondition type="MinVal">10</subcondition>
</condition>
</config>
</rule>
</monitor-rules>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册