diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/css/uav.notifystgy.css b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/css/uav.notifystgy.css index a5b777ce..6d992646 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/css/uav.notifystgy.css +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/css/uav.notifystgy.css @@ -231,6 +231,40 @@ body { height: 34px; } +/**时间控件按钮样式**/ +.control-group { + margin-bottom: 10px; +} + +.control-group input { + background-color: #eeeeee; + border:1px solid #cccccc; + border-radius:4px 0 0 4px; + padding: 4px 6px; + color:#333333 +} +.control-group .add-on { + background-color: #eeeeee; + border:1px solid #cccccc; + border-radius:0 4px 4px 0; + padding: 4.5px 6px; + color:#333333 +} + +/** +*条件定义 +*/ +.btn-default.active:focus{ + color: #333; + background-color: #d4d4d4; + border-color: #8c8c8c; +} + +.btn-default.active, .btn-default:active{ + color: #333; + background-color: #d4d4d4; + border-color: #337ab7; +} /** *触发策略 begin diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.add.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.add.js index 962849a4..9fb5737e 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.add.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.add.js @@ -57,20 +57,26 @@ function saveNotify(checkIsExist){ /** * 策略 */ - var cJson = { - "expr" : json.expr - }; - if (json.range) { - cJson["range"] = parseInt(json.range); - } - if ("0" != json.func && "count" == json.func) { - cJson["func"] = "count>" + json.cparam; - } else if ("0" != json.func) { - cJson["func"] = json.func; + if(!json.type||json.type=="stream"){ + var cJson = { + "expr" : json.expr, + "type" :"stream" + }; + if (json.range) { + cJson["range"] = parseInt(json.range); + } + if ("0" != json.func && "count" == json.func) { + cJson["func"] = "count>" + json.cparam; + } else if ("0" != json.func) { + cJson["func"] = json.func; + } + + cJson["id"]=json.id; + conditions.push(cJson); + }else{ + conditions.push(json); } - cJson["id"]=json.id; - conditions.push(cJson); }catch(e){ console.log(e); diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.init.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.init.js index 10d68234..02262c59 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.init.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.init.js @@ -44,6 +44,5 @@ var list = new AppHubTable(listConfig); $(document).ready(function() { initHeadDiv(); initListClass(); - initConditionsDiv(); }); diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.win.js b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.win.js index 5195d38e..194d1e31 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.win.js +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/js/notifystgy.win.js @@ -22,6 +22,13 @@ window.winmgr.build({ order : 999, theme : "StgyDiv" }); +window.winmgr.build({ + id : "condDiv", + height : "auto", + "overflow-y" : "auto", + order : 999, + theme : "condDiv" +}); window.winmgr.show("notifyList"); /** @@ -151,7 +158,7 @@ function showAddDiv() { sb.append( '
'); sb.append( '
'); - sb.append( '
条件定义
'); + sb.append( '
条件定义
'); sb.append( '
'); sb.append( '
'); @@ -289,7 +296,7 @@ function showEditNotifyDiv(jsonObjParam) { sb.append( '
'); sb.append( '
'); sb.append( '条件定义'); - sb.append( '
'); + sb.append( '
'); $.each(jsonObj.conditions,function(index,obj){ if(obj.func && obj.func.indexOf("count>")>-1){ obj.cparam = obj.func.substr(6); @@ -304,9 +311,9 @@ function showEditNotifyDiv(jsonObjParam) { } var html; if(isOwner){ - html = '
'+StgyClass.formatShowWhere(obj)+'
'; + html = '
'+StgyClass.formatShowWhere(obj)+'
'; }else{ - html = '
'+StgyClass.formatShowWhere(obj)+'
'; + html = '
'+StgyClass.formatShowWhere(obj)+'
'; } sb.append( html); }); @@ -427,46 +434,7 @@ function showEditNotifyDiv(jsonObjParam) { } -/** - * 条件窗口操作 begin - */ - -function initConditionsDiv(thisObj) { - var sb=new StringBuffer(); - - sb.append(''); - var div = document.createElement('div'); - div.innerHTML = sb.toString(); - document.body.appendChild(div); -} /** * 触发动作添加窗口 @@ -496,7 +464,7 @@ function initActionDiv(isOwner) { sb.append( ''); sb.append( ''); sb.append( ''); - sb.append( '') + sb.append( ''); sb.append( ''); if(isOwner=="true"){ @@ -527,59 +495,210 @@ function initActionDiv(isOwner) { */ function showCon(thisObj,type){ actionConf.actionObj=thisObj.parentNode; - $("#contype").val(type); - //clear - $("#contExpr").val(""); - $("#conRange").val(""); - $("#conFunc").val("0"); - $("#conFuncParam").val(""); - $("#conFuncParam").hide(); - $("#conditionsErrMsg").hide(); - //还原只读 - $("#whereSaveButton").show(); - $("#contExpr").removeAttr("readonly"); - $("#conRange").removeAttr("readonly"); - $("#conFunc").removeAttr("disabled"); - $("#conFuncParam").removeAttr("readonly"); - + $("#pageType").val(type); if("EDIT" == type){ var jsonValue = JSON.parse(thisObj.parentNode.getElementsByTagName("span")[0].textContent); - $("#contExpr").val(jsonValue.expr); - $("#conRange").val(jsonValue.range); - $("#conFunc").val((null == jsonValue.func?0:jsonValue.func)); - if("count" == jsonValue.func){ - $("#conFuncParam").val(jsonValue.cparam); - $("#conFuncParam").show(); - } - //不是归属用户,则只读 + $("#condType").attr("disabled","disabled"); var isOwner = $("#isOwner").val(); - if(isOwner!="true"){ - $("#whereSaveButton").hide(); - $("#contExpr").attr("readonly","readonly"); - $("#conRange").attr("readonly","readonly"); - $("#conFunc").attr("disabled","disabled"); - $("#conFuncParam").attr("readonly","readonly"); - - //只读CSS - $("#contExpr").attr("class","displayMsgInput listIndex"); - $("#conRange").attr("class","displayMsgInput listIndex"); - $("#conFuncParam").attr("class","displayMsgInput listIndex"); - }else{ - //还原默认CSS - $("#contExpr").attr("class","form-control input_must"); - $("#conRange").attr("class","form-control"); - $("#conFuncParam").attr("class","form-control input_must"); + if(!jsonValue.type||jsonValue.type=="stream"){ + $("#condType").val("stream"); + $("#contExpr").val(jsonValue.expr); + $("#conRange").val(jsonValue.range); + $("#conFunc").val((null == jsonValue.func?0:jsonValue.func)); + if("count" == jsonValue.func){ + $("#conFuncParam").val(jsonValue.cparam); + $("#conFuncParam").show(); + } + //不是归属用户,则只读 + if(isOwner!="true"){ + $("#whereSaveButton").hide(); + $("#contExpr").attr("readonly","readonly"); + $("#conRange").attr("readonly","readonly"); + $("#conFunc").attr("disabled","disabled"); + $("#conFuncParam").attr("readonly","readonly"); + + //只读CSS + $("#contExpr").attr("class","form-control"); + $("#conRange").attr("class","form-control"); + $("#conFuncParam").attr("class","form-control"); + $("#whereSaveButton").hide(); + } + }else{ + var type; + if(jsonValue.interval){ + type="link-relative"; + }else{ + type="base-relative"; + } + $("#condType").val(type); + typeChangeShow(type); + $("#time_from").val(jsonValue.time_from); + $("#time_to").val(jsonValue.time_to); + $("#conMetric").val(jsonValue.metric); + $("#conUpperLimit").val(jsonValue.upperLimit); + $("#conLowerLimit").val(jsonValue.lowerLimit); + $("#conAggr").val(jsonValue.aggr); + if(type=="link-relative"){ + $("#conInterval").val(jsonValue.interval); + showUnit(jsonValue.unit); + }else{ + showUnit(jsonValue.unit); + } + if(isOwner!="true"){ + $("#time_from").attr("readonly","readonly"); + $("#time_to").attr("readonly","readonly"); + $("#conMetric").attr("readonly","readonly"); + $("#conUpperLimit").attr("readonly","readonly"); + $("#conLowerLimit").attr("readonly","readonly"); + $("#conMetric").attr("class","form-control"); + $("#conUpperLimit").attr("class","form-control"); + $("#conLowerLimit").attr("class","form-control"); + $("#conAggr").attr("disabled","disabled"); + if(type=="link-relative"){ + $("#conInterval").attr("readonly","readonly"); + $("#conInterval").attr("class","form-control"); + } + $("#whereSaveButton").hide(); + } } - }else{ - //默认CSS - $("#contExpr").attr("class","form-control input_must"); - $("#conRange").attr("class","form-control"); - $("#conFuncParam").attr("class","form-control input_must"); + } - $("#conditionsDiv").modal({backdrop: 'static', keyboard: false}); - $("#conditionsDiv").modal(); +} + +function showUnit(unit){ + $("#unit").val(unit); + $("#opt"+unit).attr("class","btn btn-default active"); +} +/** + * 条件定义页面 + */ +function showCondDiv(thisObj,type) { + + var isOwner = $("#isOwner").val(); + /** + * 显示条件定义(弹出新元素) + */ + actionConf.actionObj=thisObj.parentNode; + + var sb = new StringBuffer(); + sb.append("
"); + sb.append("条件定义"); + sb.append("
"); + sb.append("
"); + sb.append( "
'); + + sb.append( '
'); + /** + * 普通预警条件编辑 + */ + sb.append( '
'); + + sb.append( '
'); + sb.append( '
'); + sb.append( "
'); + sb.append( ')\" style="display:none" onkeyup="this.value=this.value.replace(\/\\D/g,\'\')" onafterpaste="this.value=this.value.replace(\/\\D/g,\'\')">
'); + sb.append( '
'); + + /** + * 同环比预警条件编辑 + */ + sb.append( ''); + sb.append( '
'); + + /** + * 保存按钮 + */ + sb.append( '
'); + sb.append( ''); + sb.append( ''); + sb.append( '
'); + + HtmlHelper.id("condDiv").innerHTML = sb.toString(); + initTimeControl(); + showCon(thisObj,type); + window.winmgr.hide("objectDiv"); + window.winmgr.show("condDiv"); } @@ -591,6 +710,73 @@ function funcChangeShow(thisObj,showId){ } } +function typeChangeShow(type){ + var divs=["stream","timer","link-relative","base-relative"]; + divs.forEach(div=>{ + $("#"+div).hide(); + }) + if("stream"!=type){ + $("#timer").show(); + } + $("#"+type).show(); + +} +/** + * 初始化时间控件 + */ +function initTimeControl(){ + $('.form_datetime').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + todayBtn : true, + }); + + $('.form_datetime_start').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + todayBtn : true, + }); + + $('.form_datetime_end').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + todayBtn : true, + }); + + + //事件绑定 + $(".form_datetime").on('show', function(ev){ + /*背景灰层添加*/ + var hideBg = '
'; + $('body').append(hideBg); + //document.body.innerHTML += hideBg; + + }); + $(".form_datetime").on('hide', function(ev){ + /*背景灰层移除*/ + document.getElementById("hideBg").style.display="none"; + var removeObj = document.getElementById("hideBg"); + removeObj.parentNode.removeChild(removeObj); + }); + + $('.my_datetime_pick').datetimepicker({ + language : 'zh-CN', + autoclose : true, + minuteStep : 1, + minView: 1, + todayBtn : true, + }); +} + +function changeTimeUnit(value){ + $("#unit").val(value); +} + + + function actionChangeShow(type){ if("ADD" == type){ if("threadanalysis" == $("#actionTypeSel").val()){ @@ -710,22 +896,50 @@ function getSelUiConfKeysValue(a, b) { return result; } function conditionsAppend(){ - if(checkFunc()){ - var jsonObject = {"expr":HtmlHelper.inputXSSFilter($("#contExpr").val()),"range":HtmlHelper.inputXSSFilter($("#conRange").val()),"func":HtmlHelper.inputXSSFilter($("#conFunc").val()),"cparam":HtmlHelper.inputXSSFilter($("#conFuncParam").val())}; + if(checkFunc()){ + var jsonObject; + if("stream"==$("#condType").val()){ + jsonObject = {"type":"stream","expr":HtmlHelper.inputXSSFilter($("#contExpr").val()),"range":HtmlHelper.inputXSSFilter($("#conRange").val()),"func":HtmlHelper.inputXSSFilter($("#conFunc").val()),"cparam":HtmlHelper.inputXSSFilter($("#conFuncParam").val())}; + }else{ + jsonObject = {"type":"timer","time_from":HtmlHelper.inputXSSFilter($("#time_from").val()),"time_to":HtmlHelper.inputXSSFilter($("#time_to").val()),"metric":HtmlHelper.inputXSSFilter($("#conMetric").val()),"upperLimit":HtmlHelper.inputXSSFilter($("#conUpperLimit").val()),"lowerLimit":HtmlHelper.inputXSSFilter($("#conLowerLimit").val()),"aggr":HtmlHelper.inputXSSFilter($("#conAggr").val())}; + if("link-relative"==$("#condType").val()){ + jsonObject["interval"]=HtmlHelper.inputXSSFilter($("#conInterval").val()); + jsonObject["unit"]=HtmlHelper.inputXSSFilter($("#unit").val()); + }else{ + jsonObject["unit"]=HtmlHelper.inputXSSFilter($("#unit").val()); + } + } appendConditions(jsonObject); - $("#conditionsDiv").modal('hide'); + window.winmgr.hide("condDiv"); + window.winmgr.show("objectDiv"); } } function checkFunc(){ var result = true; - if(!$("#contExpr").val()){ - result = false; - }else if("count" == $("#conFunc").val() && !$("#conFuncParam").val()){ - result = false; + if("stream"==$("#condType").val()){ + if(!$("#contExpr").val()){ + result = false; + }else if("count" == $("#conFunc").val() && !$("#conFuncParam").val()){ + result = false; + } + }else{ + if(!$("#time_from").val()||!$("#time_to").val()||!$("#conMetric").val()||!$("#conUpperLimit").val()||!$("#conLowerLimit").val()||!$("#conAggr").val()){ + result = false; + } + if("link-relative"==$("#condType").val()){ + if(!$("#conInterval").val()||!$("#unit").val()){ + result = false; + } + }else{ + if(!$("#unit").val()){ + result = false; + } + } } + if(result){ $("#conditionsErrMsg").hide(); }else{ @@ -735,7 +949,7 @@ function checkFunc(){ return result; } function appendConditions(jsonObj) { - var type = $("#contype").val(); + var type = $("#pageType").val(); if("ADD"==type){ var newNode = document.createElement("div"); var stgyDivId = StgyClass.randomId()+"_stgySpan"; @@ -750,7 +964,7 @@ function appendConditions(jsonObj) { function getHtmlAndSetId(stgyDivId){ jsonObj.id = stgyDivId;//赋值id - var html = StgyClass.formatShowWhere(jsonObj)+''; + var html = StgyClass.formatShowWhere(jsonObj)+''; return html; } } @@ -1004,6 +1218,7 @@ function openHelpDiv() { window.open("file/help.htm","apphub.help"); } + /** * 策略表达式处理类 */ @@ -1192,17 +1407,47 @@ var StgyClass = { return ""; } - var result = json.expr; - - if(json.range && json.range!=""){ - result += ","+json.range; - } + var result; - if(json.func && json.func!=0 && json.func=="count"){ - result += ","+json.func+">"+json.cparam; - }else if(json.func && json.func!=0){ - result += ","+json.func; - } + if(!json.type||json.type=="stream"){ + result = json.expr; + + if(json.range && json.range!=""){ + result += ","+json.range; + } + + if(json.func && json.func!=0 && json.func=="count"){ + result += ","+json.func+">"+json.cparam; + }else if(json.func && json.func!=0){ + result += ","+json.func; + } + }else{ + result = json.metric+","+json.time_from+"-"+json.time_to+","+json.aggr+","; + if(json.interval){ + result+=json.interval+" "; + + } + switch(json.unit){ + case "6": + result+="min"; + break; + case "5": + result+="hour"; + break; + case "1": + result+="day"; + break; + case "2": + result+="week"; + break; + case "3": + result+="month"; + break; + case "4": + result+="year"; + break; + } + } return result; }, diff --git a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/main.html b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/main.html index 7f7bdae3..007d703b 100644 --- a/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/main.html +++ b/com.creditease.uav.console/src/main/webapp/uavapp_godeye/notifystgy/main.html @@ -10,7 +10,8 @@ - + + @@ -25,7 +26,9 @@ - + + + @@ -34,5 +37,6 @@ + \ No newline at end of file diff --git a/com.creditease.uav.healthmanager.buildComponent/config/agent.properties b/com.creditease.uav.healthmanager.buildComponent/config/agent.properties index 55ed244c..6812feea 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/agent.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/agent.properties @@ -317,11 +317,14 @@ feature.runtimenotify.storecm.server=127.0.0.1:6379 feature.runtimenotify.storecm.minsize=50 feature.runtimenotify.storecm.maxsize=100 feature.runtimenotify.storecm.qsize=5 +#timernotifyworker +feature.runtimenotify.timernotify.enable=true +feature.runtimenotify.queryservice=healthmanager-HealthMangerServerWorker-/hm/query #nodeinfotimer feature.runtimenotify.nodeinfotimer.enable=true feature.runtimenotify.nodeinfotimer.period=15000 #nodeinfoprocess -feature.runtimenotify.nodeinfoprocess.sendmq=false +feature.runtimenotify.nodeinfoprocess.sendmq=true feature.runtimenotify.nodeinfoprocess.exchange=false #http service feature.runtimenotify.rnswhandlers=com.creditease.uav.feature.runtimenotify.http.RuntimeNotifyServerHandler diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_rtserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_rtserver.properties index da2d75c7..c6f567c7 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_rtserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_pro_rtserver.properties @@ -93,6 +93,9 @@ feature.runtimenotify.storecm.server=127.0.0.1:6379 feature.runtimenotify.storecm.minsize=100 feature.runtimenotify.storecm.maxsize=300 feature.runtimenotify.storecm.qsize=5 +#timernotifyworker +feature.runtimenotify.timernotify.enable=true +feature.runtimenotify.queryservice=healthmanager-HealthMangerServerWorker-/hm/query #nodeinfotimer feature.runtimenotify.nodeinfotimer.enable=false feature.runtimenotify.nodeinfotimer.period=15000 diff --git a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_rtserver.properties b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_rtserver.properties index 6a334db0..1a6e7659 100644 --- a/com.creditease.uav.healthmanager.buildComponent/config/hm_test_rtserver.properties +++ b/com.creditease.uav.healthmanager.buildComponent/config/hm_test_rtserver.properties @@ -95,6 +95,9 @@ feature.runtimenotify.qworker.coresize=25 feature.runtimenotify.qworker.maxsize=50 feature.runtimenotify.qworker.bqsize=20 feature.runtimenotify.qworker.keepalivetimeout=60000 +#timernotifyworker +feature.runtimenotify.timernotify.enable=true +feature.runtimenotify.queryservice=healthmanager-HealthMangerServerWorker-/hm/query #nodeinfotimer feature.runtimenotify.nodeinfotimer.enable=false feature.runtimenotify.nodeinfotimer.period=15000 diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/RuntimeNotifyCatcher.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/RuntimeNotifyCatcher.java index 71a9dee3..5c86ba2c 100644 --- a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/RuntimeNotifyCatcher.java +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/RuntimeNotifyCatcher.java @@ -45,6 +45,7 @@ import com.creditease.uav.feature.runtimenotify.http.RuntimeNotifyServerWorker; import com.creditease.uav.feature.runtimenotify.scheduler.NodeInfoWatcher; import com.creditease.uav.feature.runtimenotify.scheduler.RuntimeNotifyStrategyMgr; +import com.creditease.uav.feature.runtimenotify.scheduler.TimerNotifyWorker; import com.creditease.uav.feature.runtimenotify.task.JudgeNotifyTask; import com.creditease.uav.messaging.api.MessageConsumer; @@ -75,8 +76,6 @@ public RuntimeNotifyCatcher(String cName, String feature) { @Override public void start() { - new StrategyJudgement("StrategyJudgement", this.feature); - // reset aredis bootstrap executor pool size AsyncRedisConnection.setBootstrapExecutorPoolSize(getCfgInt("cm.bootstrappoolsize", 10)); @@ -110,6 +109,8 @@ public void start() { storeCMServer, storeCMMinSize, storeCMMaxSize, storeCMQueueSize)); } + new StrategyJudgement("StrategyJudgement", this.feature); + // init strategyMgr String strategy = getCfg("strategy.config"); RuntimeNotifyStrategyMgr rtNotifyStrategyMgr = new RuntimeNotifyStrategyMgr("RuntimeNotifyStrategyMgr", feature, @@ -211,6 +212,19 @@ public void start() { if (log.isTraceEnable()) { log.info(this, "RuntimeNotifyCatcher-RuntimeNotifyServerWorker started"); } + + // init RuntimeNotifyTimerWorker + if (DataConvertHelper.toBoolean(this.getCfg("timernotify.enable"), false)) { + + TimerNotifyWorker timerNotifyWorker = new TimerNotifyWorker("TimerNotifyWorker", feature); + + this.getTimerWorkManager().scheduleWork("TimerNotifyWorker", timerNotifyWorker, 0, 60000); + + if (log.isTraceEnable()) { + log.info(this, "RuntimeNotifyCatcher-RuntimeNotifyStrategyMgr started: " + strategy); + } + } + } @Override @@ -262,6 +276,13 @@ public void stop() { log.info(this, "RuntimeNotifyCatcher-RuntimeNotifyStrategyMgr stopped"); } + // stop RuntimeNotifyTimerWorker + this.getTimerWorkManager().cancel("timerNotifyWorker"); + + if (log.isTraceEnable()) { + log.info(this, "RuntimeNotifyCatcher-timerNotifyWorker stopped"); + } + // shutdown CacheManager CacheManager RNStorageCacheManager = (CacheManager) this.getConfigManager().getComponent(this.feature, STORAGE_CACHE_MANAGER_NAME); @@ -374,7 +395,7 @@ private List extractSlice(MonitorDataFrame mdf) { List list = new ArrayList<>(); Map> frames = mdf.getDatas(); - + String appgroup = mdf.getExt("appgroup"); for (Map.Entry> frame : frames.entrySet()) { List servers = frame.getValue(); for (Map server : servers) { @@ -384,7 +405,9 @@ private List extractSlice(MonitorDataFrame mdf) { for (Map ins : instances) { String id = (String) ins.get("id"); Map values = (Map) ins.get("values"); - + values.put("ip", mdf.getIP()); + values.put("host", mdf.getHost()); + values.put("appgroup", appgroup); String key = frame.getKey() + RuntimeNotifyCatcher.STRATEGY_SEPARATOR + meId + RuntimeNotifyCatcher.STRATEGY_SEPARATOR + id; Slice slice = new Slice(key, mdf.getTimeFlag()); diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/NotifyStrategy.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/NotifyStrategy.java index 16ff19a0..91c9d5d0 100644 --- a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/NotifyStrategy.java +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/NotifyStrategy.java @@ -29,6 +29,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.creditease.agent.helpers.DateTimeHelper; +import com.creditease.agent.helpers.EncodeHelper; import com.creditease.agent.helpers.JSONHelper; /** @@ -36,11 +38,28 @@ */ public class NotifyStrategy { + public enum Type { + STREAM("stream"), TIMER("timer"); + + private String name; + + Type(String name) { + this.name = name; + } + + @Override + public String toString() { + + return name; + } + } + private static final String[] OPERATORS = { ":=", "!=", ">", "<", "=" }; private static final Pattern INDEX_PATTERN = Pattern.compile("\\[\\d+\\]"); - // + private Type type; + private String scope; private List condtions; @@ -55,11 +74,14 @@ public class NotifyStrategy { private long maxRange = 0; + private String name; + public NotifyStrategy() { } - public NotifyStrategy(String scope, List context, Map action, List instances, - String msgTemplate) { + public NotifyStrategy(String name, String scope, List context, Map action, + List instances, String msgTemplate) { + this.name = name; this.scope = scope; if (context != null && context.size() != 0) { this.context = context; @@ -88,11 +110,21 @@ public void setConditions(List conditions, List relations) { else { @SuppressWarnings("unchecked") Map cond = (Map) o; - String expr = (String) cond.get("expr"); - String func = (String) cond.get("func"); - Long range = cond.get("range") == null ? null : Long.valueOf(cond.get("range").toString()); - Float sampling = cond.get("sampling") == null ? null : Float.valueOf(cond.get("sampling").toString()); - Expression expression = new Expression(expr, func, range, sampling); + Expression expression; + if (cond.get("type") == null || cond.get("type").equals(Type.STREAM.name)) { + String expr = (String) cond.get("expr"); + String func = (String) cond.get("func"); + Long range = cond.get("range") == null ? null : Long.valueOf(cond.get("range").toString()); + Float sampling = cond.get("sampling") == null ? null + : Float.valueOf(cond.get("sampling").toString()); + expression = new Expression(expr, func, range, sampling); + } + else { + String metricPrefix = name.substring(name.indexOf('@') + 1, name.lastIndexOf('@')); + cond.put("metric", metricPrefix + "." + cond.get("metric")); + expression = new Expression(cond); + this.type = Type.TIMER; + } expression.setIdx(idx++); exprs.add(expression); } @@ -143,7 +175,7 @@ public void setConditions(List conditions, List relations) { } @SuppressWarnings({ "rawtypes", "unchecked" }) - public static NotifyStrategy parse(String json) { + public static NotifyStrategy parse(String name, String json) { Map m = JSONHelper.toObject(json, Map.class); String scope = (String) m.get("scope"); @@ -154,7 +186,7 @@ public static NotifyStrategy parse(String json) { String msgTemplate = (String) m.get("msgTemplate"); List instances = (List) m.get("instances"); - NotifyStrategy stra = new NotifyStrategy(scope, context, action, instances, msgTemplate); + NotifyStrategy stra = new NotifyStrategy(name, scope, context, action, instances, msgTemplate); stra.setConditions(conditions, relations); @@ -216,6 +248,16 @@ public void setInstances(List instances) { this.instances = instances; } + public String getName() { + + return name; + } + + public Type getType() { + + return type; + } + public List getCondtions() { return condtions; @@ -224,16 +266,23 @@ public List getCondtions() { protected static class Expression { private int idx; + private Type type; private String arg; private String operator; private String expectedValue; - private long range = 0; private String func; private float sampling = 1; private Set matchArgExpr = new HashSet(); + private long time_from; + private long time_to; + private long interval; + private int unit; + private String upperLimit; + private String lowerLimit; + public Expression(String exprStr) { for (String op : OPERATORS) { if (exprStr.contains(op)) { @@ -248,6 +297,7 @@ public Expression(String exprStr) { break; } } + this.type = Type.STREAM; } public Expression(String exprStr, String func, Long range, Float sampling) { @@ -259,6 +309,39 @@ public Expression(String exprStr, String func, Long range, Float sampling) { if (sampling != null) { this.sampling = sampling; } + + } + + public Expression(Map cond) { + + this.arg = (String) cond.get("metric"); + this.unit = Integer.parseInt((String) cond.get("unit")); + this.time_from = DateTimeHelper + .dateFormat(DateTimeHelper.getToday("yyyy-MM-dd") + " " + cond.get("time_from"), "yyyy-MM-dd HH:mm") + .getTime(); + this.time_to = DateTimeHelper + .dateFormat(DateTimeHelper.getToday("yyyy-MM-dd") + " " + cond.get("time_to"), "yyyy-MM-dd HH:mm") + .getTime(); + if (cond.get("interval") != null) { + long interval = Long.parseLong((String) cond.get("interval")); + switch (unit) { + case DateTimeHelper.INTERVAL_DAY: + interval = interval * 24 * 3600 * 1000; + break; + case DateTimeHelper.INTERVAL_HOUR: + interval = interval * 3600 * 1000; + break; + case DateTimeHelper.INTERVAL_MINUTE: + interval = interval * 60000; + break; + } + this.interval = interval; + } + + this.upperLimit = (String) cond.get("upperLimit"); + this.lowerLimit = (String) cond.get("lowerLimit"); + this.func = (String) cond.get("aggr"); + this.type = Type.TIMER; } private void initMatchArgExpr() { @@ -298,6 +381,11 @@ public Set matchTargetArgs(Set srcArgs) { return targetArgs; } + public String getHashCode() { + + return EncodeHelper.encodeMD5(arg + func + lowerLimit + upperLimit + time_from + time_to + interval + unit); + } + public String getArg() { return arg; @@ -333,6 +421,41 @@ public int getIdx() { return idx; } + public Type getType() { + + return type; + } + + public long getTime_from() { + + return time_from; + } + + public long getTime_to() { + + return time_to; + } + + public long getInterval() { + + return interval; + } + + public String getUpperLimit() { + + return upperLimit; + } + + public String getLowerLimit() { + + return lowerLimit; + } + + public int getUnit() { + + return unit; + } + public void setIdx(int idx) { this.idx = idx; diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/StrategyJudgement.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/StrategyJudgement.java index bb60fb39..72a8c0a0 100644 --- a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/StrategyJudgement.java +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/StrategyJudgement.java @@ -20,8 +20,10 @@ package com.creditease.uav.feature.runtimenotify; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -29,17 +31,37 @@ import java.util.Map; import java.util.Set; +import com.creditease.agent.helpers.DateTimeHelper; import com.creditease.agent.helpers.JSONHelper; import com.creditease.agent.helpers.JsHelper; import com.creditease.agent.helpers.StringHelper; +import com.creditease.agent.http.api.UAVHttpMessage; +import com.creditease.agent.monitor.api.MonitorDataFrame; import com.creditease.agent.spi.AbstractComponent; +import com.creditease.agent.spi.AbstractSystemInvoker; +import com.creditease.agent.spi.ISystemInvokerMgr.InvokerType; +import com.creditease.uav.cache.api.CacheManager; +import com.creditease.uav.feature.RuntimeNotifyCatcher; +import com.creditease.uav.feature.runtimenotify.NotifyStrategy.Expression; public class StrategyJudgement extends AbstractComponent { private static final int MIN_SAMPLING_COUNT = 3; + private static final String TIMER_JUDGE_RESULT = "strategy.timer.result"; + + private CacheManager cm; + + @SuppressWarnings("rawtypes") + private AbstractSystemInvoker invoker; + + private String queryServiceName; + public StrategyJudgement(String cName, String feature) { super(cName, feature); + cm = (CacheManager) this.getConfigManager().getComponent(feature, RuntimeNotifyCatcher.CACHE_MANAGER_NAME); + invoker = this.getSystemInvokerMgr().getSystemInvoker(InvokerType.HTTP); + queryServiceName = this.getConfigManager().getFeatureConfiguration(feature, "queryservice"); } /** @@ -77,14 +99,19 @@ private void judgeCondition(JudgeResult re, Slice cur, NotifyStrategy.Condition List exprs = cond.getExpressions(); ConditionResult cr = new ConditionResult(cond); for (NotifyStrategy.Expression expr : exprs) { - judgeExpression(cr, expr, cur, slices); + if (expr.getType() == NotifyStrategy.Type.TIMER) { + judgeTimerExpression(cr, expr, cur); + } + else if (expr.getType() == NotifyStrategy.Type.STREAM) { + judgeExpression(cr, expr, cur, slices); + } } re.add(cr); } /** - * judge single expression + * judge stream expression * * @param re * @param expr @@ -94,14 +121,17 @@ private void judgeCondition(JudgeResult re, Slice cur, NotifyStrategy.Condition private void judgeExpression(ConditionResult re, NotifyStrategy.Expression expr, Slice cur, List slices) { boolean fire = false; - + String showActualValue = ""; + if (cur.getKey().indexOf('@') == -1) { + fire = false; + re.setIsJudgeTime(true); + re.addExprResult(fire, expr, showActualValue); + return; + } long range = expr.getRange(); String func = expr.getFunc(); List rangeSlices = rangeSlices(slices, cur, range); List samplingSlices = samplingSlice(rangeSlices, expr.getSampling()); - - String showActualValue = ""; - /** * Step 1: collect all possible arg keys for this expression */ @@ -176,8 +206,273 @@ else if (func.indexOf("percent") == 0) { fire = true; } - + re.setIsJudgeTime(true); re.addExprResult(fire, expr, showActualValue); + + } + + /** + * * judge timer expression + * + * @param re + * @param expr + * @param cur + * @param slices + */ + + private void judgeTimerExpression(ConditionResult cr, NotifyStrategy.Expression expr, Slice slice) { + + // get this expr's last judgeResult from cache + Map judgeResult = getJudgeResult(slice.getKey(), expr); + + if (judgeResult == null) { + judgeResult = new HashMap(); + judgeResult.put("fire", false); + } + + // if the judge is called by slice stream, just return the last result + if (slice.getKey().indexOf('@') > -1) { + if (judgeResult.get("time_to") != null) { + Date date = DateTimeHelper.dateFormat(String.valueOf(judgeResult.get("time_to")), "yyyy-MM-dd HH:mm"); + // if the time is not the time expr's judge time,return false + if (slice.getTime() - date.getTime() > 120000) { + judgeResult.put("fire", false); + } + } + } + + // if the judge is called by timerTask + else { + Map timeMap = getJudgeTime(expr, slice.getTime()); + + // if it's not the judge time ,return the last result. if the last result is out of time,return false. + if (timeMap == null && judgeResult.get("time_to") != null + && isOverdue(DateTimeHelper + .dateFormat(String.valueOf(judgeResult.get("time_to")), "yyyy-MM-dd HH:mm").getTime(), + slice.getTime(), expr)) { + + judgeResult.put("fire", false); + } + else if (timeMap != null) { + caculateJudgeResult(timeMap, judgeResult, slice.getKey(), expr, cr); + } + + } + + cr.addTimerExprResult((Boolean) judgeResult.get("fire"), expr, judgeResult); + } + + private void caculateJudgeResult(Map timeMap, Map judgeResult, String instance, + Expression expr, ConditionResult cr) { + + // if this time's judge has been done, return the last result. + if (judgeResult.get("time_to") != null && judgeResult.get("time_to") + .equals(DateTimeHelper.toFormat("yyyy-MM-dd HH:mm", timeMap.get("time_to")))) { + return; + } + + Double currentValue = queryOpentsdb(instance, expr.getArg(), expr.getFunc(), timeMap.get("time_from"), + timeMap.get("time_to")); + Double lastValue = 0.0; + + // if the last judgeResult is really the last judgeTime's result, use it's currentValue as lastValue. + if (judgeResult.get("time_to") != null + && judgeResult.get("time_to") + .equals(DateTimeHelper.toFormat("yyyy-MM-dd HH:mm", timeMap.get("last_time_to"))) + && judgeResult.get("currentValue") != null) { + lastValue = Double.parseDouble(String.valueOf(judgeResult.get("currentValue"))); + } + else { + lastValue = queryOpentsdb(instance, expr.getArg(), expr.getFunc(), timeMap.get("last_time_from"), + timeMap.get("last_time_to")); + } + + judgeResult.put("instance", instance); + + for (String key : timeMap.keySet()) { + judgeResult.put(key, DateTimeHelper.dateFormat(new Date(timeMap.get(key)), "yyyy-MM-dd HH:mm")); + + } + judgeResult.put("currentValue", currentValue); + judgeResult.put("lastValue", lastValue); + + if (currentValue == null || lastValue == null) { + judgeResult.put("fire", false); + } + else { + judgeResult.put("fire", caculate(currentValue, lastValue, expr, judgeResult)); + } + + // cache the judgeResult + cm.putHash(RuntimeNotifyCatcher.UAV_CACHE_REGION, TIMER_JUDGE_RESULT, instance + expr.getHashCode(), + JSONHelper.toString(judgeResult)); + + // set there is a judge event + cr.setIsJudgeTime(true); + + } + + private boolean isOverdue(long time, long currentTime, Expression expr) { + + long interval = expr.getInterval() == 0 ? 24 * 3600 * 1000 : expr.getInterval(); + return (currentTime - time > interval); + } + + /** + * caculate and judge if the expr's result is true. + */ + private boolean caculate(double currentValue, double lastValue, NotifyStrategy.Expression expr, + Map judgeResult) { + + boolean result = false; + + String limitString = null; + + double diff = currentValue - lastValue; + + String prefix = (diff > 0) ? "" : "-"; + + diff = (diff > 0) ? diff : 0 - diff; + + limitString = (diff >= 0) ? expr.getUpperLimit() : expr.getLowerLimit(); + + double limit; + String suffix = ""; + if (limitString.endsWith("%")) { + limit = Double.parseDouble(limitString.substring(0, limitString.length() - 1)); + diff = diff * 100 / lastValue; + suffix = "%"; + } + else { + limit = Double.parseDouble(limitString); + } + + if (!"-1".equals(limitString) && diff > limit) { + result = true; + } + + judgeResult.put("actualValue", prefix + String.format("%.2f", diff) + suffix); + judgeResult.put("expectedValue", limitString); + + return result; + + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private Double queryOpentsdb(String instance, String metric, String func, Long startTime, Long endTime) { + + Double result = null; + for (int i = 0; i < 3 && result == null; i++) { + + try { + UAVHttpMessage message = new UAVHttpMessage(); + + String data = String.format( + "{\"start\":%d,\"end\":%d,\"queries\":[{\"aggregator\":\"avg\",\"downsample\":\"%s\",\"metric\":\"%s\",\"filters\":[{\"filter\":\"%s\",\"tagk\":\"instid\",\"type\":\"regexp\",\"groupBy\":false}]}]}", + startTime, endTime, func, metric, + instance.replace(":", "/u003a").replace("%", "/u0025").replace("#", "/u0023")); + message.putRequest("opentsdb.query.json", data); + message.putRequest("datastore.name", MonitorDataFrame.MessageType.Monitor.toString()); + + String queryResponse = String.valueOf(invoker.invoke(queryServiceName, message, String.class)); + + if (queryResponse.equals("null") || queryResponse.equals("{}") + || queryResponse.equals("{\"rs\":\"[]\"}")) { + continue; + } + + Map responseMap = JSONHelper.toObject(queryResponse, Map.class); + + List rsList = JSONHelper.toObjectArray((String) responseMap.get(UAVHttpMessage.RESULT), Map.class); + + for (Object value : ((Map) rsList.get(0).get("dps")).values()) { + result = ((BigDecimal) value).doubleValue(); + } + } + catch (Exception e) { + log.err(this, "TimerExpression judgement query opentsdb failed ", e); + } + } + return result; + } + + /** + * get judgeResult from redis + */ + @SuppressWarnings("unchecked") + private Map getJudgeResult(String instance, Expression expr) { + + if (instance.contains("@")) { + instance = instance.substring(instance.lastIndexOf('@') + 1); + if (instance.endsWith("_")) { + instance = instance.substring(0, instance.length() - 1); + } + } + Map resultMap = cm.getHash(RuntimeNotifyCatcher.UAV_CACHE_REGION, TIMER_JUDGE_RESULT, + instance + expr.getHashCode()); + + String result = resultMap.get(instance + expr.getHashCode()); + + return JSONHelper.toObject(result, Map.class); + } + + /** + * judge if this time is the expr's judge time. if it's the judge time, return the time slot and last time slot, + * else return null; + */ + private Map getJudgeTime(Expression expr, long time) { + + Map timeMap = new HashMap(); + long time_to = time; + long time_from = time - (expr.getTime_to() - expr.getTime_from()); + timeMap.put("time_from", time_from); + timeMap.put("time_to", time_to); + long last_time_to; + if (expr.getInterval() != 0) { + + if ((time_to - expr.getTime_to()) % expr.getInterval() == 0) { + + timeMap.put("last_time_from", time_from - expr.getInterval()); + timeMap.put("last_time_to", time_to - expr.getInterval()); + } + else { + return null; + } + } + else { + if ((time_to - expr.getTime_to()) % (24 * 3600 * 1000) == 0) { + switch (expr.getUnit()) { + case DateTimeHelper.INTERVAL_DAY: + + timeMap.put("last_time_from", time_from - 24 * 3600 * 1000); + timeMap.put("last_time_to", time_to - 24 * 3600 * 1000); + break; + case DateTimeHelper.INTERVAL_WEEK: + + timeMap.put("last_time_from", time_from - 7 * 24 * 3600 * 1000); + timeMap.put("last_time_to", time_to - 7 * 24 * 3600 * 1000); + break; + case DateTimeHelper.INTERVAL_MONTH: + + last_time_to = DateTimeHelper.getMonthAgo(new Date(time_to)).getTime(); + timeMap.put("last_time_to", last_time_to); + timeMap.put("last_time_from", last_time_to - (time_to - time_from)); + break; + case DateTimeHelper.INTERVAL_YEAR: + + last_time_to = DateTimeHelper.getYearAgo(new Date(time_to)).getTime(); + timeMap.put("last_time_to", last_time_to); + timeMap.put("last_time_from", last_time_to - (time_to - time_from)); + break; + } + } + else { + return null; + } + + } + + return timeMap; } private List rangeSlices(List slices, Slice cur, long range) { @@ -254,7 +549,7 @@ public Map buildReadableResult() { for (boolean b : cr.getCondResult()) { fire = fire || b; } - if (fire) { + if (fire && cr.isJudgeTime()) { map.put(String.valueOf(cond.getIndex()), toReadable(cr.getExprResult(), null)); } } @@ -269,7 +564,7 @@ public Map buildReadableResult() { continue; } - if (Boolean.parseBoolean(result.toString())) { + if (Boolean.parseBoolean(result.toString()) && cr.isJudgeTime()) { map.put(String.valueOf(cond.getIndex()), toReadable(cr.getExprResult(), cond.getRelation())); } } @@ -309,18 +604,30 @@ private String toReadable(Map[] exprResult, String relation) { private String makeReadableString(Map m) { - String description = null; - long range = Long.parseLong(m.get("range")); - if (range > 0 && m.get("func") != null) { - // convert to seconds - long sencodRange = range / 1000; - description = String.format("%s秒内%s的%s值%s%s,当前值:%s", sencodRange, m.get("actualArg"), m.get("func"), - m.get("operator"), m.get("expectedValue"), m.get("actualValue")); + String description = ""; + if (NotifyStrategy.Type.STREAM.toString().equals(m.get("type"))) { + long range = Long.parseLong(m.get("range")); + if (range > 0 && m.get("func") != null) { + // convert to seconds + long sencodRange = range / 1000; + description = String.format("%s秒内%s的%s值%s%s,当前值:%s", sencodRange, m.get("actualArg"), m.get("func"), + m.get("operator"), m.get("expectedValue"), m.get("actualValue")); + } + else { + description = String.format("%s%s%s,当前值:%s", m.get("actualArg"), m.get("operator"), + m.get("expectedValue"), m.get("actualValue")); + } } - else { - description = String.format("%s%s%s,当前值:%s", m.get("actualArg"), m.get("operator"), - m.get("expectedValue"), m.get("actualValue")); + else if (NotifyStrategy.Type.TIMER.toString().equals(m.get("type"))) { + + description = ("true".equals(m.get("fire"))) ? String.format( + "%s在%s至%s时间段的%s值%s比%s至%s%s超过%s,当前值:%s。上期值:%s,本期值:%s", m.get("metric"), m.get("time_from"), + m.get("time_to"), m.get("func"), m.get("tag"), m.get("last_time_from"), m.get("last_time_to"), + (m.get("actualValue").contains("-")) ? "降幅" : "增幅", m.get("expectedValue"), + (m.get("actualValue").contains("-")) ? m.get("actualValue").substring(1) : m.get("actualValue"), + m.get("lastValue"), m.get("currentValue")) : "false"; } + return description; } } @@ -331,6 +638,7 @@ private class ConditionResult { private boolean[] condResult; private Map[] exprResult; private int idx = 0; + private boolean isJudgeTime = false; @SuppressWarnings("unchecked") private ConditionResult(NotifyStrategy.Condition cond) { @@ -346,6 +654,20 @@ private void addExprResult(int i, boolean result, Map reMap) { exprResult[i] = reMap; } + public void addTimerExprResult(boolean result, NotifyStrategy.Expression expr, Map reMap) { + + Map m = new HashMap<>(); + for (String key : reMap.keySet()) { + m.put(key, String.valueOf(reMap.get(key))); + } + + m.put("tag", expr.getInterval() == 0 ? "同" : "环"); + m.put("metric", expr.getArg()); + m.put("func", expr.getFunc()); + m.put("type", NotifyStrategy.Type.TIMER.toString()); + addExprResult(idx++, result, m); + } + public void addExprResult(boolean result, NotifyStrategy.Expression expr, String actualValue) { Map m = new HashMap<>(); @@ -355,6 +677,7 @@ public void addExprResult(boolean result, NotifyStrategy.Expression expr, String m.put("expectedValue", expr.getExpectedValue()); m.put("actualArg", expr.getArg()); m.put("actualValue", actualValue); + m.put("type", NotifyStrategy.Type.STREAM.toString()); addExprResult(idx++, result, m); } @@ -373,6 +696,15 @@ public Map[] getExprResult() { return exprResult; } + public boolean isJudgeTime() { + + return isJudgeTime; + } + + public void setIsJudgeTime(boolean isJudgeTime) { + + this.isJudgeTime = isJudgeTime; + } } private static class Function { diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/scheduler/RuntimeNotifyStrategyMgr.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/scheduler/RuntimeNotifyStrategyMgr.java index 637c4e8f..5a493f10 100644 --- a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/scheduler/RuntimeNotifyStrategyMgr.java +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/scheduler/RuntimeNotifyStrategyMgr.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -56,6 +57,7 @@ public class RuntimeNotifyStrategyMgr extends AbstractTimerWork { private Map mScope = new ConcurrentHashMap<>(); private Map fScope = new ConcurrentHashMap<>(); private Map> multiInsts = new HashMap<>(); + private HashSet strategies = new HashSet<>(); private Lock strategyLock = new ReentrantLock(); @@ -76,6 +78,11 @@ public void setCacheManager(CacheManager cm) { this.cm = cm; } + public HashSet getStrategies() { + + return strategies; + } + /** * only for development load from local configuration file * @@ -89,7 +96,7 @@ public void loadStrategy(String json) { String key = entry.getKey(); Map m = (Map) entry.getValue(); - NotifyStrategy stra = NotifyStrategy.parse(JSONHelper.toString(m)); + NotifyStrategy stra = NotifyStrategy.parse(key, JSONHelper.toString(m)); if (log.isDebugEnable()) { log.debug(this, "Parse NotifyStrategy: " + JSONHelper.toString(stra)); @@ -223,10 +230,11 @@ public void run() { mScope.clear(); iScope.clear(); multiInsts.clear(); + strategies.clear(); for (String key : strategyMap.keySet()) { String json = strategyMap.get(key); - NotifyStrategy stra = NotifyStrategy.parse(json); + NotifyStrategy stra = NotifyStrategy.parse(key, json); if (log.isDebugEnable()) { log.debug(this, "Parse NotifyStrategy: " + JSONHelper.toString(stra)); @@ -239,6 +247,7 @@ public void run() { } putStrategy(key, stra); + } } catch (InterruptedException e) { @@ -272,7 +281,7 @@ private void putMultiInstStrategy(String key, NotifyStrategy stra) { } multiInsts.put(key, nkeys); - + strategies.add(stra); } /** @@ -325,6 +334,9 @@ private void putStrategy(String key, NotifyStrategy stra) { if ("I".equals(stra.getScope())) { iScope.put(key, stra); + List instances = new ArrayList(); + instances.add(key.substring(key.lastIndexOf('@') + 1)); + stra.setInstances(instances); } else if ("M".equals(stra.getScope())) { mScope.put(key, stra); @@ -334,6 +346,8 @@ else if ("F".equals(stra.getScope())) { } else { log.err(this, "UNKNOWN strategy scope: " + stra.getScope() + ", key: " + key); + return; } + strategies.add(stra); } } diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/scheduler/TimerNotifyWorker.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/scheduler/TimerNotifyWorker.java new file mode 100644 index 00000000..189a7ee2 --- /dev/null +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/scheduler/TimerNotifyWorker.java @@ -0,0 +1,65 @@ +/*- + * << + * UAVStack + * == + * Copyright (C) 2016 - 2017 UAVStack + * == + * Licensed 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 com.creditease.uav.feature.runtimenotify.scheduler; + +import java.util.HashSet; + +import com.creditease.agent.spi.AbstractTimerWork; +import com.creditease.agent.spi.I1NQueueWorker; +import com.creditease.uav.feature.RuntimeNotifyCatcher; +import com.creditease.uav.feature.runtimenotify.NotifyStrategy; +import com.creditease.uav.feature.runtimenotify.task.JudgeNotifyTask; +import com.creditease.uav.feature.runtimenotify.task.JudgeNotifyTimerTask; + +/** + * + * RuntimeNotifyStrategyMgr description: + * + * 1. provide Strategy function + * + * 2. get the strategy setting interval + * + */ +public class TimerNotifyWorker extends AbstractTimerWork { + + public TimerNotifyWorker(String cName, String feature) { + super(cName, feature); + } + + @Override + public void run() { + + RuntimeNotifyStrategyMgr strategyMgr = (RuntimeNotifyStrategyMgr) getConfigManager().getComponent(this.feature, + "RuntimeNotifyStrategyMgr"); + HashSet strategies = new HashSet(strategyMgr.getStrategies()); + for (NotifyStrategy stra : strategies) { + if (stra.getType() != NotifyStrategy.Type.TIMER) { + continue; + } + I1NQueueWorker n1nqw = get1NQueueWorkerMgr().getQueueWorker(this.feature, + RuntimeNotifyCatcher.QWORKER_NAME); + n1nqw.put(new JudgeNotifyTimerTask(JudgeNotifyTask.class.getSimpleName(), feature, + System.currentTimeMillis(), stra)); + + } + } + +} diff --git a/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/task/JudgeNotifyTimerTask.java b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/task/JudgeNotifyTimerTask.java new file mode 100644 index 00000000..08931fb7 --- /dev/null +++ b/com.creditease.uav.healthmanager/src/main/java/com/creditease/uav/feature/runtimenotify/task/JudgeNotifyTimerTask.java @@ -0,0 +1,227 @@ +/*- + * << + * UAVStack + * == + * Copyright (C) 2016 - 2017 UAVStack + * == + * Licensed 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 com.creditease.uav.feature.runtimenotify.task; + +import java.util.Map; +import java.util.Map.Entry; + +import com.creditease.agent.helpers.JSONHelper; +import com.creditease.agent.helpers.NetworkHelper; +import com.creditease.agent.monitor.api.NotificationEvent; +import com.creditease.agent.spi.Abstract1NTask; +import com.creditease.uav.cache.api.CacheManager; +import com.creditease.uav.cache.api.CacheManager.CacheLock; +import com.creditease.uav.feature.RuntimeNotifyCatcher; +import com.creditease.uav.feature.runtimenotify.NotifyStrategy; +import com.creditease.uav.feature.runtimenotify.Slice; +import com.creditease.uav.feature.runtimenotify.StrategyJudgement; +import com.creditease.uav.feature.runtimenotify.scheduler.RuntimeNotifyStrategyMgr; + +public class JudgeNotifyTimerTask extends Abstract1NTask { + + private NotifyStrategy stra; + private long taskStart = System.currentTimeMillis(); + private long judge_time; + private static final String LOCK_REGION = "lock.region.uav"; + private static final long LOCK_TIMEOUT = 60 * 1000; + private CacheManager cm; + + public JudgeNotifyTimerTask(String name, String feature, long judge_time, NotifyStrategy stra) { + super(name, feature); + this.stra = stra; + this.judge_time = judge_time - judge_time % 60000; + cm = (CacheManager) this.getConfigManager().getComponent(feature, RuntimeNotifyCatcher.CACHE_MANAGER_NAME); + } + + @Override + public void run() { + + CacheLock lock = null; + try { + lock = cm.newCacheLock(LOCK_REGION, stra.getName(), LOCK_TIMEOUT); + + if (!lock.getLock()) { + return; + } + /** + * Step 1:find out instance + */ + for (String instance : stra.getInstances()) { + /** + * Step 2: judge the strategy + */ + + StrategyJudgement judgement = (StrategyJudgement) getConfigManager().getComponent(feature, + "StrategyJudgement"); + Map result = judgement.judge(new Slice(instance, judge_time), stra, null); + + /** + * Step 3: if fire the event, build notification event + */ + if (result != null && !result.isEmpty()) { + NotificationEvent event = this.newNotificationEvent(instance, result); + + // get context + putContext(event); + + // get action + putNotifyAction(event, stra); + + // get msg tempalte + putNotifyMsg(event, stra); + + if (this.log.isTraceEnable()) { + this.log.info(this, "RuntimeNotify Notification Event Happen: event=" + event.toJSONString()); + } + + this.putNotificationEvent(event); + } + } + + } + catch (Exception e) { + log.err(this, "JudgeNotifyTimerTask" + stra.getName() + " RUN FAIL.", e); + } + finally { + if (lock != null && lock.isLockInHand()) { + lock.releaseLock(); + } + } + + if (log.isDebugEnable()) { + long cost = System.currentTimeMillis() - taskStart; + String detail = cost < 10 ? "" : " detail:strategy=" + JSONHelper.toString(stra); + log.debug(this, "whole task lifecycle COST: (" + cost + ")ms" + detail); + } + } + + /** + * get context + * + * TODO: we need support context param in strategy + */ + private void putContext(NotificationEvent event) { + + } + + /** + * newNotificationEvent + * + * + * @return + */ + private NotificationEvent newNotificationEvent(String instance, Map result) { + + String ip = instance; + String host = instance; + String appgroup = "UNKNOWN"; + + instance = formatInstance(instance); + + Map infos = getInfoFromSliceCache(instance); + if (infos != null) { + ip = String.valueOf(infos.get("ip")); + host = String.valueOf(infos.get("host")); + appgroup = String.valueOf(infos.get("appgroup")); + } + + StringBuilder desc = new StringBuilder(); + StringBuilder conditionIndex = new StringBuilder(); + + for (Map.Entry cause : result.entrySet()) { + // description + desc.append(instance + "触发条件[" + cause.getKey() + "]:").append(cause.getValue()).append("\r\n"); + // condition index + conditionIndex.append(" " + cause.getKey()); + } + + String title = ip + "[" + instance + "]触发" + result.size() + "个报警(条件序号:" + conditionIndex.toString() + ")"; + + // fix  (\u00A0) can be shown in email + String description = desc.toString().replace('\u00A0', ' '); + + NotificationEvent ne = new NotificationEvent(NotificationEvent.EVENT_RT_ALERT_THRESHOLD, title, description, + judge_time, ip, host); + + // add appgroup + ne.addArg("appgroup", appgroup); + + return ne; + } + + private String formatInstance(String instance) { + + if (NetworkHelper.isIPV4(instance)) { + instance += "_"; + } + instance = stra.getName().substring(0, stra.getName().lastIndexOf('@') + 1) + instance; + + return instance; + } + + private Map getInfoFromSliceCache(String instance) { + + String cacheKey = "SLICE_" + instance + "_"; + for (int index = 0; index < 60; index++) { + String result = cm.lpop(RuntimeNotifyStrategyMgr.UAV_CACHE_REGION, cacheKey + index); + if (result != null) { + Slice s = new Slice(result); + return s.getArgs(); + } + } + + return null; + } + + private void putNotifyAction(NotificationEvent event, NotifyStrategy stra) { + + Map actions = stra.getAction(); + if (actions == null || actions.isEmpty()) { + return; + } + + for (Entry act : actions.entrySet()) { + event.addArg("action_" + act.getKey(), act.getValue()); + } + } + + private void putNotifyMsg(NotificationEvent event, NotifyStrategy stra) { + + String msgTemplate = stra.getMsgTemplate(); + String msg = makeMsgByTemplate(msgTemplate, stra); + + if (msg != null) { + event.addArg("msg", msg); + } + } + + /** + * + * @param template + * @param slice + * @return + */ + private String makeMsgByTemplate(String template, NotifyStrategy stra) { + + return ""; + } + +} diff --git a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/DateTimeHelper.java b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/DateTimeHelper.java index 90002d29..c8b35dd5 100644 --- a/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/DateTimeHelper.java +++ b/com.creditease.uav.helper/src/main/java/com/creditease/agent/helpers/DateTimeHelper.java @@ -976,4 +976,24 @@ public static Long getTomorrowTime() { tomorrow.set(Calendar.SECOND, 0); return Long.valueOf(String.valueOf(tomorrow.getTimeInMillis()).substring(0, 10)); } + + public static Date getMonthAgo(Date date) { + + Calendar now = Calendar.getInstance(); + now.setTime(date); + + now.add(Calendar.MONTH, -1); + + return now.getTime(); + } + + public static Date getYearAgo(Date date) { + + Calendar now = Calendar.getInstance(); + now.setTime(date); + + now.add(Calendar.YEAR, -1); + + return now.getTime(); + } }