需求:自动化组提出需要,要对IIS上的站点进行监控,异常停止后报警


需求分析:这站点的运行正常需要多方面的监控,如站点,程序池,资源,所以针对这需求做了三方面的监控。

  1. 站点状态的监控

  2. 站点对应的程序池的监控

  3. URL的监控,监控url能返回200的状态码


数据库设计:

wKioL1YeHYPj1P_mAAHKAcf9ix0756.jpg


wKiom1YeHWOQEqVIAAC7lpySFrM750.jpg


页面展示:

配置list页

wKioL1YeHZyDqHgYAAJ5ToYxFio410.jpg

配置Detail页

wKiom1YeHXyhSMb2AAHbM4aJ-0E560.jpg

预警邮件:

wKioL1YeHZyQ9u8xAAFXFCmaev4319.jpg


核心代码:

  1. 配置页面代码

    index.cshtml

  1. @model IEnumerable<Ctrip.Hotel.QA.Platform.Data.Dao.EnvRunStatusMonitorConfig>
  2. @{
  3.     ViewBag.Title = "Run Monitor";
  4. }
  5. @Styles.Render("~/Content/themes/metro/css")
  6. @Styles.Render("~/Content/themes/custom/chcore.css")
  7. @Styles.Render("~/Content/themes/fakeloader/fakeloader.css")
  8. @Scripts.Render("~/scripts/metro/jquery.dataTables.min.js")
  9. @Scripts.Render("~/Scripts/custom/chcoreui.js")
  10. @Scripts.Render("~/scripts/pages/runmonitor.js")
  11. <div class="grid" style="margin-top:50px;">
  12.     <div class="row cells12">
  13.         <div class="cell colspan10 offset1" id="divState">
  14.         </div>
  15.     </div>
  16.     <div class="row cells12">
  17.         <div class="cell colspan10 offset1" id="divContainer">
  18.             <div style="margin-left:0px;">
  19.                 <button class="refreshbtn button primary" style="width:100px" οnclick="eidtRunStatusMonitorConfigPage.refresh();">
  20.                     <span class="mif-loop2"></span> 刷新
  21.                 </button>&nbsp;
  22.                 <button class="addapppoolmonitorbtn button success" style="width:100px" οnclick="eidtRunStatusMonitorConfigPage.showEditDialog('editConfigDialog', 0)">
  23.                     <span class="mif-plus"></span> 新建
  24.                 </button>
  25.             </div>
  26.             <table id="runMonitorTable" class="dataTable striped border bordered hovered" data-role="datatable" data-searching="true">
  27.                 <thead>
  28.                     <tr>
  29.                         <th><button class="invokeallbtn button warning" style="width:50px;">唤醒</button></th>
  30.                         <th>监控器名</th>
  31.                         <th>站点名</th>
  32.                         <th>字站点名</th>
  33.                         <th>机器名</th>
  34.                         <th style="text-align:center">ip</th>
  35.                         <th style="text-align:center">启动</th>
  36.                         <th style="text-align:center">Action</th>
  37.                     </tr>                    
  38.                 </thead>
  39.                 <tfoot>
  40.                     <tr>
  41.                         <th><button class="invokeallbtn button warning">唤醒</button></th>
  42.                         <th>监控器名</th>
  43.                         <th>站点名</th>
  44.                         <th>字站点名</th>
  45.                         <th>机器名</th>
  46.                         <th style="text-align:center">ip</th>
  47.                         <th style="text-align:center">开启</th>
  48.                         <th style="text-align:center">Action</th>
  49.                     </tr>
  50.                 </tfoot>
  51.                 <tbody>
  52.                     @foreach (var item in Model)
  53.                     {
  54.                         <tr>
  55.                             <td style="text-align:center;"><span class="fg-cyan mif-play invokebtn"></span></td>
  56.                             <td>
  57.                                 @Html.DisplayFor(modelItem => item.Name)
  58.                             </td>
  59.                             <td>
  60.                                 @Html.DisplayFor(modelItem => item.DomainName)
  61.                             </td>
  62.                             <td>
  63.                                 @Html.DisplayFor(modelItem => item.NodeName)
  64.                             </td>
  65.                             <td>
  66.                                 @Html.DisplayFor(modelItem => item.MachineName)
  67.                             </td>
  68.                             <td>
  69.                                 @Html.DisplayFor(modelItem => item.Ip)
  70.                             </td>
  71.                             <td>
  72.                                 <label class="switch">
  73.                                     @if (item.TurnOn == 1)
  74.                                     {
  75.                                         <input type="checkbox" id="turnOn" checked οnchange="eidtRunStatusMonitorConfigPage.postTurnOff(@Html.DisplayFor(modelItem => item.Id))" />
  76.                                     }
  77.                                     else
  78.                                     {
  79.                                         <input type="checkbox" id="turnOn" οnchange="eidtRunStatusMonitorConfigPage.postTurnOn(@Html.DisplayFor(modelItem => item.Id))" />
  80.                                     }
  81.                                     <span class="check"></span>
  82.                                 </label>        
  83.                              
  84.                             </td>
  85.                             <td>
  86.                                 <span class="mif-pencil fg-green" οnclick="eidtRunStatusMonitorConfigPage.showEditDialog('editConfigDialog',  @Html.DisplayFor(modelItem => item.Id))"></span>
  87.                                 <span class="mif-cancel fg-red" οnclick="eidtRunStatusMonitorConfigPage.deleteConfig(@Html.DisplayFor(modelItem => item.Id))"></span>                             
  88.                             </td>
  89.                         </tr>
  90.                     }
  91.                   
  92.                 </tbody>
  93.             </table>
  94.         </div>
  95.     </div>
  96. </div>
  97. <div data-role="dialog" id="editConfigDialog" class="padding20" data-close-button="true" data-overlay="true" data-overlay-color="op-dark" >
  98.     <h3>运行状态监控配置:</h3><hr/>
  99.     <div class="metro">
  100.         <div style="width:620px">
  101.             <div class="grid">
  102.                 <div class="row">
  103.              
  104.                         <div id="subDiv" class="input-control full-size" data-role="select" data-placeholder="请选择环境" data-allow-clear="true">
  105.                             <select class="full-size" id="sub"></select>
  106.                         </div>
  107.                     <div id="templateDiv" class="input-control full-size" data-role="select" data-placeholder="请选择站点" data-allow-clear="true">
  108.                         <select class="full-size" id="template"></select>
  109.                     </div>
  110.                     <div id="nodeDiv" class="input-control full-size" data-role="select" data-placeholder="请选择应用" data-allow-clear="true">
  111.                         <select class="full-size" id="node"></select>
  112.                     </div>                        
  113.                         
  114.                     </div>
  115.                 <div class="row" id="ipAndPoolInfoDiv" style="display:none">
  116.                     <div class="span2">
  117.                         <div style="float:left;display:inline;font-weight:bold;margin-left:10px">
  118.                             IP:
  119.                         </div>
  120.                         <div id="ip" style="float:left;display:inline;">
  121.                             10.2.3.410
  122.                         </div>
  123.                     </div>
  124.                     <div class="span6">
  125.                         <div style="float:left;display:inline;font-weight:bold;">
  126.                             程序池:
  127.                         </div>
  128.                         <div id="apppool" style="float:left;display:inline;">
  129.                             hotel-vendor-interfaceadapter 
  130.                         </div>
  131.                     </div>
  132.                 </div>
  133.                     <div class="row">
  134.                         <div class="span8">
  135.                             <label class="switch" style="float:left;display:inline;margin-left:10px;">
  136.                                 <input type="checkbox" checked id="turnOn">
  137.                                 <span class="check"></span>
  138.                                 &nbsp; 开启监控
  139.                             </label>
  140.                             <label class="switch" style="float:left;display:inline;margin-left:50px;">
  141.                                 <input type="checkbox" checked id="emailOn">
  142.                                 <span class="check"></span>
  143.                                 &nbsp;收邮件
  144.                             </label>                         
  145.                         </div>
  146.                     </div>
  147.                     <div class="row">
  148.                         <div class="span8">
  149.                             <div style="float:left;display:inline;margin-top:10px;margin-left:10px;font-weight:bold;">
  150.                                 Monitor Name:
  151.                             </div>
  152.                             <div style="float:left;display:inline;margin-left:10px;width:490px">
  153.                                 <!-- Input with clear helper -->
  154.                                 <div class="input-control text" data-role="input">
  155.                                     <input type="text" id="monitorName">
  156.                                     <button class="button helper-button clear"><span class="mif-cross"></span></button>
  157.                                 </div>                             
  158.                             </div>
  159.                         </div>
  160.                     </div>
  161.                     <div class="row">
  162.                         <div class="span8">
  163.                             <label class="switch" style="float:left;display:inline;margin-left:10px;">
  164.                                 <input type="checkbox" id="siteOn">
  165.                                 <span class="check"></span>
  166.                                 &nbsp;监控站点
  167.                             </label>           
  168.                             <label class="switch" style="float:left;display:inline;margin-left:50px;">
  169.                                 <input type="checkbox" id="poolOn">
  170.                                 <span class="check"></span>
  171.                                 &nbsp;监控程序池
  172.                             </label>           
  173.                             <label class="switch" style="float:left;display:inline;margin-left:50px;">
  174.                                 <input type="checkbox" checked id="urlOn">
  175.                                 <span class="check"></span>
  176.                                 &nbsp;监控Url返回200
  177.                             </label>           
  178.                            
  179.                         </div>
  180.                     </div>
  181.                     <div class="row" id="urlDiv">
  182.                         <div class="span8">
  183.                             <div style="float:left;display:inline;margin-top:10px;margin-left:10px;font-weight:bold;">
  184.                                 url:
  185.                             </div>
  186.                             <!-- Input with clear helper -->
  187.                             <div class="input-control text" data-role="input" style="float:left;display:inline;margin-left:10px;width:566px">
  188.                                 <input type="text" id="url">
  189.                                 <button class="button helper-button clear"><span class="mif-cross"></span></button>
  190.                             </div>     
  191.                         
  192.                         </div>
  193.                     </div>
  194.                     <div class="row">
  195.                         <div class="span8">
  196.                             <div style="float:left;display:inline;margin-left:10px;font-weight:bold;">
  197.                                 收件人:
  198.                             </div>
  199.                             <div class="input-control textarea " data-role="input-control" style="float:left;display:inline;width:100%">
  200.                                 <textarea id="recievers"></textarea>
  201.                             </div>
  202.                         </div>
  203.                     </div>
  204.                 </div>
  205.                 <div style="display:inline-block; text-align:right;width:100%">
  206.                     <button id="comitSettingBtn" class="primary"><i class="icon-checkmark on-left"></i>确认</button>&nbsp;
  207.                     <button id="cancelCommitBtn" class="danger"><i class=" icon-cancel-2 on-left"></i>取消</button>&nbsp;
  208.                     <button id="closeCommitBtn" class="warning"><i class=" icon-cancel-2 on-left"></i>关闭</button>
  209.                 </div>
  210.             </div>
  211.         </div>
  212.     </div>


js代码:

  1. // 页面初始化加载 //
  2. $(document).ready(function () {
  3. });
  4. function showDialog(dialogId) {
  5.     var dialog = $("#" + dialogId).data('dialog');
  6.     if (!dialog.element.data('opened')) {
  7.         dialog.open();
  8.     } else {
  9.         dialog.close();
  10.     }
  11. }
  12. function closeDialog(dialogId) {
  13.     var dialog = $("#" + dialogId).data('dialog');
  14.     if (!dialog.element.data('closed')) {
  15.         dialog.close();
  16.     } else {
  17.         dialog.open();
  18.     }
  19. }
  20. var RunStatusMonitorConfigListPage = {
  21.     refresh: function () {
  22.         window.location.href = window.location.href;
  23.     }
  24. }
  25. var eidtRunStatusMonitorConfigPage = {
  26.     showEditDialog: function (dialogId, configId) {
  27.         eidtRunStatusMonitorConfigPage.bingConfigDialogInfo(configId);
  28.         $('#comitSettingBtn').click(function () {
  29.             eidtRunStatusMonitorConfigPage.commitMonitorConfig();            
  30.         });
  31.         $('#cancelCommitBtn').click(function () {
  32.             eidtRunStatusMonitorConfigPage.showEditDialog(dialogId, configId);
  33.         });
  34.         $('#closeCommitBtn').click(function () {
  35.             closeDialog(dialogId);
  36.         });
  37.         showDialog(dialogId);
  38.     },
  39.     bingConfigDialogInfo: function (id) {
  40.         var subSelect = $("#sub");
  41.         var templateSelect = $("#template");
  42.         var nodeSelect = $("#node");
  43.         // 绑定数据
  44.         if (id != 0) {
  45.             $.getJSON('/RunMonitor/GetMonitorSetting?id=' + id, null, function (data) {
  46.                 if (data) {
  47.                     subSelect.empty();
  48.                     subSelect.append("<option></option><option value=" + data.Data.SubId + " select>" + data.Data.SubName + "</option>");
  49.                     templateSelect.empty();
  50.                     templateSelect.append("<option></option><option value=" + data.Data.DomainId + " select>" + data.Data.DomainName + "</option>");
  51.                     nodeSelect.empty();
  52.                     nodeSelect.append("<option></option><option value=" + data.Data.NodeId + " select >" + data.Data.NodeName + "</option>");
  53.                     $("#ipAndPoolInfoDiv").removeAttr("style");
  54.                     $("#ip").html(data.Data.Ip);
  55.                     $("#apppool").html(data.Data.PoolName);
  56.                     if (data.Data.TurnOn == 1) {
  57.                         $("#turnOn").attr("checked", true);
  58.                     }
  59.                     else {
  60.                         $("#turnOn").attr("checked", false);
  61.                     }
  62.                     if (data.Data.EmailOn == 1) {
  63.                         $("#emailOn").attr("checked", true);
  64.                     }
  65.                     else {
  66.                         $("#emailOn").attr("checked", false);
  67.                     }
  68.                     if (data.Data.CheckSiteOn == 1) {
  69.                         $("#siteOn").attr("checked", true);
  70.                     }
  71.                     else {
  72.                         $("#siteOn").attr("checked", false);
  73.                     }
  74.                     if (data.Data.CheckPoolOn == 1) {
  75.                         $("#poolOn").attr("checked", true);
  76.                     }
  77.                     else {
  78.                         $("#poolOn").attr("checked", false);
  79.                     }
  80.                     if (data.Data.CheckUrlOn == 1) {
  81.                         $("#urlOn").attr("checked", true);
  82.                     }
  83.                     else {
  84.                         $("#urlOn").attr("checked", false);
  85.                     }
  86.                     $("#monitorName").val(data.Data.Name);
  87.                     $("#url").val(data.Data.Url);
  88.                     $("#recievers").val(data.Data.Reciever);
  89.                 }
  90.             });
  91.         }
  92.         else {
  93.             // 绑定环境         
  94.             subSelect.empty();
  95.             $.getJSON('/env/GetAllEnvSubs', null, function (data) {
  96.                 if (data.StateCode == 0) {
  97.                     var content = "<option></option>";
  98.                     $.each(data.Data, function (idx, item) {
  99.                         content += "<option value=" + item.EnvSubId + ">" + item.EnvSubName + "</option>"
  100.                     });
  101.                     subSelect.append(content);
  102.                 }
  103.             });
  104.             // 绑定站点           
  105.             templateSelect.empty();
  106.             $.getJSON('/DomainTemplate/GetAllEnvDomainTemplates', null, function (data) {
  107.                 if (data.StateCode == 0) {
  108.                     var content = "<option></option>";
  109.                     $.each(data.Data, function (idx, item) {
  110.                         content += "<option value=" + item.Id + ">" + item.DomainName + "</option>"
  111.                     });
  112.                     templateSelect.append(content);
  113.                 }
  114.             });
  115.             //绑定onchange事件
  116.             templateSelect.change(function () {
  117.                 // 绑定子站点
  118.                 eidtRunStatusMonitorConfigPage.bingDomainNode(templateSelect.val(), 0);
  119.             });
  120.         }
  121.     },
  122.     bingDomainNode: function (templateid, nodeid) {
  123.         var nodeSelect = $("#node");
  124.         nodeSelect.empty();
  125.         $.getJSON('/DomainTemplate/GetDomainNodeTemplate?id=' + templateid, null, function (data) {
  126.             if (data.StateCode == 0) {
  127.                 var content = "<option select>请选择子站点</option><option>全部</option>";
  128.                 $.each(data.Data, function (idx, item) {
  129.                     content += "<option value=" + item.Id + ">" + item.NodeName + "</option>"
  130.                 });
  131.                 nodeSelect.append(content);
  132.                 if (nodeid != 0) {
  133.                     $("#node option[@value='" + nodeid + "']").attr("selected", "true")
  134.                 }
  135.                 else {
  136.                     $("#monitorName").text = $("#domain").val() + "-" + $("#template").val();
  137.                 }
  138.             }
  139.         });
  140.     },
  141.     commitMonitorConfig: function () {
  142.         var config = new Object();
  143.         config.Name = $("#monitorName").val();
  144.         config.SubId = $("#sub").val();
  145.         config.SubName = $("#sub").find("option:selected").text();
  146.         config.DomainId = $("#template").val();
  147.         config.DomainName = $("#template").find("option:selected").text();
  148.         config.NodeId = $("#node").val();
  149.         config.NodeName = $("#node").find("option:selected").text();
  150.         if ($("#turnOn").is(':checked')) {
  151.             config.TurnOn = "1";
  152.         }
  153.         else {
  154.             config.TurnOn = "0";
  155.         }
  156.         if ($("#emailOn").is(':checked')) {
  157.             config.EmailOn = "1";
  158.         }
  159.         else {
  160.             config.EmailOn = "0";
  161.         }
  162.         if ($("#siteOn").is(':checked')) {
  163.             config.CheckSiteOn = "1";
  164.         }
  165.         else {
  166.             config.CheckSiteOn = "0";
  167.         }
  168.         if ($("#poolOn").is(':checked')) {
  169.             config.CheckPoolOn = "1";
  170.         }
  171.         else {
  172.             config.CheckPoolOn = "0";
  173.         }
  174.         if ($("#urlOn").is(':checked')) {
  175.             config.CheckUrlOn = "1";
  176.         }
  177.         else {
  178.             config.CheckUrlOn = "0";
  179.         }
  180.         config.Url = $("#url").val();
  181.         config.Reciever = $("#recievers").val();
  182.         if (config.NodeName == "全部") {
  183.             $("#node option").each(function () { //遍历全部option
  184.                 var txt = $(this).text(); //获取option的内容
  185.                 if (txt != "全部") //如果不是“全部”和"请选择子站点"
  186.                 {
  187.                     config.NodeName = txt;
  188.                     eidtRunStatusMonitorConfigPage.postMonitorConfig(config);
  189.                 }
  190.             });
  191.         }
  192.         else {
  193.             eidtRunStatusMonitorConfigPage.postMonitorConfig(config);
  194.         }
  195.     },
  196.     postMonitorConfig: function (postData) {
  197.         var url = '/RunMonitor/CommitMonitorConfig';
  198.         var pack = new Object();
  199.         pack.Token = $.readCookie('accessToken');
  200.         pack.config = postData;
  201.         var submitData = JSON.stringify(pack);
  202.         $.ajax({
  203.             type: "POST",
  204.             url: url,
  205.             data: submitData,
  206.             dataType: "json",
  207.             contentType: "application/json",
  208.             crossDomain: true,
  209.             success: function (results) {
  210.                 if (results.Data == "0") {
  211.                     $.note(null, "修改" + name + "运行状态监控配置成功!");
  212.                     RunStatusMonitorConfigListPage.refresh();
  213.                 }
  214.                 else {
  215.                     $.note(null, "修改" + name + "运行状态监控配置失败!" + results.Message, 'error');
  216.                 }
  217.             },
  218.             error: function (xhr, status, error) {
  219.                 $.note(null, "发送修改" + name + "运行状态监控配置请求失败!", 'error');
  220.             }
  221.         });
  222.     },
  223.     postTurnOn: function (id) {
  224.         token = $.readCookie('accessToken');
  225.         $.post("/RunMonitor/TurnOnMonitor", { "id": id, "alis": token }, function (data) {
  226.             if (data.StateCode == 0) {
  227.                 $.note(null, '开启监控成功.');
  228.             }
  229.             else {
  230.                 $.note(null, '开启监控失败.', "error");
  231.             }
  232.         });
  233.     },
  234.     postTurnOff: function (id) {
  235.         token = $.readCookie('accessToken');
  236.         $.post("/RunMonitor/TurnOffMonitor", { "id": id, "alis": token }, function (data) {
  237.             if (data.StateCode == 0) {
  238.                 $.note(null, '关闭监控成功.');
  239.             }
  240.             else {
  241.                 $.note(null, '关闭监控失败.', "error");
  242.             }
  243.         });
  244.     },
  245.     startInvoke: function (sender) {
  246.         var parentObj = sender.parent();
  247.         parentObj.empty();
  248.         parentObj.append('<img src="../img/loading.jpg" style="width:30px;" id="iloader" />');
  249.         var ip = parentObj.next().next().next().next().next().text();
  250.         var url = 'http://' + ip + ':8167/Monitor/Ping';
  251.         $.ajax({
  252.             type: "POST",
  253.             url: url,
  254.             data: null,
  255.             dataType: "json",
  256.             contentType: "application/json",
  257.             crossDomain: true,
  258.             success: function (results) {
  259.                 parentObj.empty();
  260.                 var reg = /\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}/;
  261.                 if (reg.test(results)) {
  262.                     $.note(null, '唤醒' + ip + '监控成功!');
  263.                     parentObj.append('<button class="link invokesuccessbtn" style="margin-left:30px;"><i class="icon-checkmark fg-green" style="margin-left:45px;"></i></button>');
  264.                     $('.invokesuccessbtn').click(function () {
  265.                         monitorconfigpage.startInvoke($(this));
  266.                     });
  267.                 } else {
  268.                     $.note('Error', '唤醒' + ip + '失败!', 'error');
  269.                     parentObj.append('<button class="link invokefailbtn" style="margin-left:30px;"><i class="icon-cancel-2 fg-red"></i></button>');
  270.                     $('.invokefailbtn').click(function () {
  271.                         monitorconfigpage.startInvoke($(this));
  272.                     });
  273.                 }
  274.             },
  275.             error: function (xhr, status, error) {
  276.                 $.note('Error', '唤醒' + ip + '失败!' + error, 'error');
  277.                 parentObj.empty();
  278.                 parentObj.append('<button class="link invokefailbtn" style="margin-left:30px;"><i class="icon-cancel-2 fg-red"></i></button>');
  279.                 $('.invokefailbtn').click(function () {
  280.                     monitorconfigpage.startInvoke($(this));
  281.                 });
  282.             }
  283.         });
  284.     },
  285.     deleteConfig:function(id)
  286.     {
  287.         var r = confirm("确定删除该配置信息?")
  288.         if (r == true) {
  289.             var config = new Object();
  290.             config.id = id;
  291.         }
  292.         else {
  293.             $.note(null, "你已取消删除配置信息id:" + id);
  294.         }
  295.     },
  296.     postDeleteConfig:function(postData)
  297.     {
  298.         var url = '/RunMonitor/DeleteMonitorConfig';
  299.         var pack = new Object();
  300.         pack.Token = $.readCookie('accessToken');
  301.         pack.config = postData;
  302.         var submitData = JSON.stringify(pack);
  303.         $.ajax({
  304.             type: "POST",
  305.             url: url,
  306.             data: submitData,
  307.             dataType: "json",
  308.             contentType: "application/json",
  309.             crossDomain: true,
  310.             success: function (results) {
  311.                 if (results.Data == "0") {
  312.                     $.note(null, "删除运行状态监控配置成功!");
  313.                     RunStatusMonitorConfigListPage.refresh();
  314.                 }
  315.                 else {
  316.                     $.note(null, "删除运行状态监控配置失败!" + results.Message, 'error');
  317.                 }
  318.             },
  319.             error: function (xhr, status, error) {
  320.                 $.note(null, "发送删除运行状态监控配置请求失败!", 'error');
  321.             }
  322.         });
  323. }
  324. }

Controller代码:

using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ControllerBase = xxx.xxx.QA.Platform.Common.ControllerBase;
namespace xxx.xxx.QA.Platform.Environment.Controllers.Coverage
{
    public class RunMonitorController : ControllerBase
    {
        //
        // GET: /RunMonitor/
        public ActionResult Index()
        {
            IList <EnvRunStatusMonitorConfig> configList = EnvRunStatusMonitorConfigBiz.GetRunStatusMonitorConfig();
            return View(configList);
        }
        public JsonResult GetMonitorSetting(int id)
        {
            var resp = new APIResponse<EnvRunStatusMonitorConfig>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            try
            {
                EnvRunStatusMonitorConfig config = EnvRunStatusMonitorConfigBiz.GetRunStatusMonitorConfig(id);
                resp.Data = config;
            }
            catch (Exception ex)
            {
                resp.StateCode = StateCode.Fail;
                resp.Message += ex.ToString();
            }
            return Json(resp, JsonRequestBehavior.AllowGet);
        }
        public JsonResult TurnOnMonitor(int id, string alis)
        {
            var resp = new APIResponse<string>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            var accessToken = LoginSecurity.DecodeAccessToken(alis);
            if (VerifyToken(ref accessToken, ref resp, "EnvIISResetOperator"))
            {
                try
                {
                    EnvRunStatusMonitorConfig config = EnvRunStatusMonitorConfigBiz.GetRunStatusMonitorConfig(id);
                    EnvRunStatusMonitorConfigBiz.TurnOnEnvRunStatusMonitorConfig(config);
                    string desc = string.Format("{0} turn on run monitor {1}  ", accessToken.Alias, config.DomainId + "-" + config.Id);
                    int machineid = config.Id;
                    EnvOperationLogBiz.LogTurnOnRunMonitor(machineid, accessToken.Alias, desc);
                }
                catch (Exception ex)
                {
                    resp.StateCode = StateCode.Fail;
                    resp.Message += ex.ToString();
                }
            }
            return Json(resp, JsonRequestBehavior.DenyGet);
        }
        public JsonResult TurnOffMonitor(int id, string alis)
        {
            var resp = new APIResponse<string>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            var accessToken = LoginSecurity.DecodeAccessToken(alis);
            if (VerifyToken(ref accessToken, ref resp, "EnvIISResetOperator"))
            {
                try
                {
                    EnvRunStatusMonitorConfig config = EnvRunStatusMonitorConfigBiz.GetRunStatusMonitorConfig(id);
                    EnvRunStatusMonitorConfigBiz.TurnOffEnvRunStatusMonitorConfig(config);
                    string desc = string.Format("{0} turn off run monitor {1}  ", accessToken.Alias, config.DomainId + "-" + config.Id);
                    int machineid = config.Id;
                    EnvOperationLogBiz.LogTurnOffRunMonitor(machineid, accessToken.Alias, desc);
                }
                catch (Exception ex)
                {
                    resp.StateCode = StateCode.Fail;
                    resp.Message += ex.ToString();
                }
            }
            return Json(resp, JsonRequestBehavior.DenyGet);
        }
        public JsonResult CommitMonitorConfig(RunStatusMonitorConfigPack pack)
        {
            var resp = new APIResponse<string>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            var accessToken = LoginSecurity.DecodeAccessToken(pack.Token);
            if (VerifyToken(ref accessToken, ref resp, "EnvIISResetOperator"))
            {
                try
                {
                    EnvRunStatusMonitorConfig config = pack.config;
                    config.DomainName = DomainUtil.GetDomainName(config.SubName, config.DomainName);
                    // 根据环境跟站点获取机器
                    IEnumerable<EnvDomainConfig> domainConfigs = EnvDomainConfigBiz.GetAllDomainsByEnvAndDomainName(config.SubName, config.DomainName);
                    if (domainConfigs != null && domainConfigs.Count() >= 1)
                    {
                        EnvDomainConfig domainConfig = domainConfigs.First();
                        EnvMachine machine = EnvMachineBiz.FindByMachineName(domainConfig.MachineName);
                        config.MachineName = domainConfig.MachineName;
                        config.MachineId = machine.Id;
                        config.Ip = machine.IP;
                        // 查询机器上是否存在该子站点
                        var client = new RestClient("http://" + machine.IP + ":8167");
                        string nodename = config.NodeName;
                        string path = nodename.IndexOf("/") < 0 ? "/" + nodename : nodename;
                        var request = new RestRequest("/IIS/GetAppPoolNameBySite?siteName=" + config.DomainName + "&path=" + path, Method.GET);
                        var response = client.Execute(request);
                        if (!response.Content.ToString().Equals("") && response.Content.ToString().IndexOf("无效的应用程序路径") < 0)
                        {
                            config.PoolName = response.Content.ToString().Replace("\"", "");
                            EnvRunStatusMonitorConfigBiz.CommitRunStatusMonitorConfig(config);
                            resp.Data = "0";
                        }
                        // 存在子站点,查询程序池,提交
                        else
                        {
                            // 程序池不存在,返回102,提示请检查站点是否最近有更新
                            resp.Data = "102";
                            resp.Message = "站点:" + config.DomainName + "子站点" + config.NodeName + "的程序池不存在, 请检查站点是否最近有更新";
                        }
                    }
                    else
                    {
                        // 机器不存在,返回101,提示请检查该站点是否部署
                        resp.Data = "101";
                        resp.Message = "环境:" + config.SubName + "站点" + config.DomainName + "的机器不存在, 请检查站点是否部署";
                    }
                    // EnvAppPoolMonitorConfigBiz.CommitAppPoolMonitorConfigInfo(pack.config);
                }
                catch (Exception ex)
                {
                    resp.StateCode = StateCode.Fail;
                    resp.Message += ex.ToString();
                    resp.Data = "1";
                }
            }
            return Json(resp, JsonRequestBehavior.AllowGet);
        }
        public JsonResult DeleteMonitorConfig(RunStatusMonitorConfigPack pack)
        {
            var resp = new APIResponse<string>()
            {
                StateCode = StateCode.Success,
                Message = ""
            };
            var accessToken = LoginSecurity.DecodeAccessToken(pack.Token);
            if (VerifyToken(ref accessToken, ref resp, "EnvIISResetOperator"))
            {
                try
                {
                    EnvRunStatusMonitorConfigBiz.DeleteEnvAppPoolMonitorConfig(pack.config.Id);
                    resp.Data = "0";
                }
                catch (Exception ex)
                {
                    resp.StateCode = StateCode.Fail;
                    resp.Message += ex.ToString();
                    resp.Data = "1";
                }
            }
            return Json(resp, JsonRequestBehavior.AllowGet);
        }
    }
    public class RunStatusMonitorConfigPack : PostPackBase
    {
        public EnvRunStatusMonitorConfig config { get; set; }
    }
}


2. 服务器端监控代码

监控站点程序池的状态,是放在该服务器上的EnvAgency里面

using FluentScheduler;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace xxx.xxx.QA.Platform.EnvAgent.Services.Tasks
{
    public class RunStatusMonitorTask : ITask
    {
        private static readonly object Locker = new object();
        private static bool _isRunning;
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        public void Execute()
        {
            if (_isRunning)
            {
                return;
            }
            ChangeState(true);
            try
            {
                Logger.Info("Monitor  start");
                EnvMachine envMachine = EnvMachineBiz.GetCurrentMachine();
                #region 监控站点
                IList<EnvRunStatusMonitorConfig> configList = EnvRunStatusMonitorConfigBiz.GetRunStatusSiteMonitorConfigByMachineId(envMachine.Id);
                foreach (EnvRunStatusMonitorConfig config in configList)
                {                    
                    DateTime dt = DateTime.Now.ToLocalTime();
                    bool siteStared = RunStatusMonitorUtil.IsSiteStarted(config.DomainName);
                    EnvRunStatusMonitorLogBiz.AddEnvRunSiteStatusMonitorLog(envMachine.Id, siteStared, dt);
                    if (!siteStared)
                    {
                        string reciever = config.Reciever;
                        string body = "";
                        body += "<h3>机器</h3>" + config.Ip + ")<br/><br/>";
                        body += "<h3>站点</h3>" + config.DomainName + ")<br/><br/>";
                        // 未设置情况默认为该账户
                        if (reciever == null || reciever.Equals(""))
                        {
                            reciever = "chenjz@Ctrip.com";
                        }
                        Mail.SendMailWithHtml2(reciever, "站点未启动预警:" + envMachine.Name+"-"+config.DomainName, body, "chenjz@Ctrip.com");
                        Logger.Info("Send 站点未开启预警 mail:" + body);
                    }
                }
                #endregion
                #region 监控程序池
                IList<EnvRunStatusMonitorConfig> configList2 = EnvRunStatusMonitorConfigBiz.GetRunStatusAppPoolMonitorConfigByMachineId(envMachine.Id);
                foreach (EnvRunStatusMonitorConfig config in configList2)
                {
                    DateTime dt = DateTime.Now.ToLocalTime();
                    bool poolStared = RunStatusMonitorUtil.IsAppPoolStarted(config.PoolName);
                    EnvRunStatusMonitorLogBiz.AddEnvRunSiteStatusMonitorLog(envMachine.Id, poolStared, dt);
                    if (!poolStared)
                    {
                        string reciever = config.Reciever;
                        string body = "";
                        body += "<h3>机器</h3>" + config.Ip + ")<br/><br/>";
                        body += "<h3>程序池</h3>" + config.PoolName + ")<br/><br/>";
                        // 未设置情况默认为该账户
                        if (reciever == null || reciever.Equals(""))
                        {
                            reciever = "chenjz@Ctrip.com";
                        }
                        Mail.SendMailWithHtml2(reciever, "程序池未启动预警:" + envMachine.Name + "-" + config.PoolName, body, "xxx@xxx.com");
                        Logger.Info("Send 程序池未开启预警 mail:" + body);
                    }
                }
                #endregion
                //监控URL放在主站点做比较合适
            }
            catch (Exception ex)
            {
                Logger.Error("MonitorTask异常信息:" + ex.ToString());
            }
            finally
            {
                ChangeState(false);
            }
        }
        private void ChangeState(bool running)
        {
            lock (Locker)
            {
                _isRunning = running;
            }
        }
   
    
    }
}


监控URL状态是放在环境系统平台里面

using FluentScheduler;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace xxx.xxx.QA.Platform.Environment.Services.Task
{
    public class RunStatusMonitorTask : ITask
    {
        private static readonly object Locker = new object();
        private static bool _isRunning;
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        public void Execute()
        {
            if (_isRunning)
            {
                return;
            }
            ChangeState(true);
            try
            {
                Logger.Info("Monitor  start");
                EnvMachine envMachine = EnvMachineBiz.GetCurrentMachine();
                #region 监控URL
                IList<EnvRunStatusMonitorConfig> configList = EnvRunStatusMonitorConfigBiz.GetRunStatusUrlMonitorConfig();
                foreach (EnvRunStatusMonitorConfig config in configList)
                {
                    DateTime dt = DateTime.Now.ToLocalTime();
                    bool urlStared = RunStatusMonitorUtil.IsUrlReturnOK(config.Url);
                    EnvRunStatusMonitorLogBiz.AddEnvRunSiteStatusMonitorLog(config.Id, urlStared, dt);
                    if (!urlStared)
                    {
                        string reciever = config.Reciever;
                        string body = "";
                        body += "<h3>Name</h3>" + config.Name + "<br/><br/>";
                        body += "<h3>URL</h3>" + config.Url + "<br/><br/>";
                        body += "<h3>环境</h3>" + config.SubName + "<br/><br/>";
                        body += "<h3>站点</h3>" + config.DomainName+ "<br/><br/>";
                        body += "<h3>子站点</h3>" + config.NodeName + "<br/><br/>";
                        body += "<h3>IP</h3>" + config.Ip + "<br/><br/>";
                        // 未设置情况默认为该账户
                        if (reciever == null || reciever.Equals(""))
                        {
                            reciever = "xxx@xxx.com";
                        }
                        Mail.SendMailWithHtml2(reciever, "URL未返回成功预警:" + config.Url, body, "chenjz@Ctrip.com");
                        Logger.Info("Send 站点未开启预警 mail:" + body);
                    }
                }             
                #endregion
            }
            catch (Exception ex)
            {
                Logger.Error("MonitorTask异常信息:" + ex.ToString());
            }
            finally
            {
                ChangeState(false);
            }
        }
        private void ChangeState(bool running)
        {
            lock (Locker)
            {
                _isRunning = running;
            }
        }
   
    }
}


监控核心代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
namespace Ctrip.Hotel.QA.Platform.Core.Monitor
{
    public class RunStatusMonitorUtil
    {
        public static bool IsSiteStarted(string siteName)
        {
            return IISUtil.GetSiteState(siteName).Equals("Started");
        }
        public static bool IsAppPoolStarted(string poolName)
        {
            return IISUtil.getAppPoolSatus(poolName).Equals("Started");
        }
        public static bool IsUrlReturnOK(string url)
        {
            string status = GetResponseStatueCode(url);
            return  status.Equals("OK");   
        }
        public static string GetResponseStatueCode(string url)
        {
            HttpWebRequest webrequest = (HttpWebRequest)HttpWebRequest.Create(url);
            try
            {
                HttpWebResponse webreponse = (HttpWebResponse)webrequest.GetResponse();
                return webreponse.StatusCode.ToString();
            }
            catch (Exception ex)
            {
                return "";
            }
        }
    }
}

    /// <summary>
        /// 获取站点状态
        /// </summary>
        /// <param name="siteName"></param>
        /// <returns></returns>
        public static string GetSiteState(string siteName)
        {
            ServerManager manager = new ServerManager();

            Site site = manager.Sites[siteName];

            return site.State.ToString();
        }
        
              /// <summary>
        /// 获取程序池状态
        /// </summary>
        /// <param name="poolName"></param>
        /// <returns></returns>
        public static ObjectState getAppPoolSatus(string poolName)
        {
            ServerManager manager = new ServerManager();
                return manager.ApplicationPools[poolName].State;
        }


如此一来,功能在匆匆忙忙中实现了,但是想想如此现实,有些多余,


光Url的正常返回就能确定站点跟程序池的正常运行,配置url的话,就不需要配很多参数,如环境,站点,应用等,

或者配置站点,程序池,url做成三个页面

  1. 配置站点:需要选择环境,站点名,需要检查该环境上配置该站点的机器,并把机器也保存在数据库中

  2. 配置程序池:需要选择环境,站点,子站点,需要检查该环境上配置该站点的机器,并把机器也保存在数据库中,并且还需要去机子上查找该子站点对应的程序池名,把程序池也保存在数据库里

  3. 配置URL:这个就简单了,只需要配置url就能了,直接在List也增删改查就行了


再加个结果的图标分析页就更好了