C#监控-机器资源监控:CPU、内存、C盘、D盘资源监控及邮件预警
针对CPU、内存、C盘、D盘资源监控及邮件预警,要实现在页面上配置资源监控选项,并且页面上能看到资源使用情况,超出阈值,邮件预警,效果图如下:
配置监控列表页
2. 配置监控详情页
3. 实时监控信息展示页
4. 监控信息图标展示
5. 超出阈值发送预警邮件
实现详情:
处于性能上的优化,每个监控都写成了个单例,并且通过多线程来取得各个监控数据
CPU监控
通过PerformanceCounter("Processor", "% Processor Time", "_Total")的NextValue()来获取获取cpu占用率,注意该Counter的第一个值是无效的0,要等一个时间片后方能取得有效值
CPUMonitor.cs
using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Text;namespace XXX.XXX.QA.Platform.Core.Monitor{ public sealed class CPUMonitor { private static readonly CPUMonitor instance = new CPUMonitor(); private PerformanceCounter pcCpuLoad; private CPUMonitor() { //初始化CPU计数器 pcCpuLoad = new PerformanceCounter("Processor", "% Processor Time", "_Total"); pcCpuLoad.MachineName = "."; pcCpuLoad.NextValue(); System.Threading.Thread.Sleep(1000); } public static CPUMonitor getMonitor() { return instance; } public static float getValue() { return instance.pcCpuLoad.NextValue(); } }}
2. 核数
由于有些指标要除以核数,所以这边也把核数读下
ProcessorCountMonitor.cs
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace xxx.xxx.QA.Platform.Core.Monitor{ public sealed class ProcessorCountMonitor { public static readonly ProcessorCountMonitor instance = new ProcessorCountMonitor(); private int m_ProcessorCount = 0; //CPU个数 private ProcessorCountMonitor() { //CPU个数 m_ProcessorCount = Environment.ProcessorCount; } public static ProcessorCountMonitor getMonitor() { return instance; } public static int getValue() { return getMonitor().m_ProcessorCount; } }}
3. 内存、C、D盘监控监控
MemoryInfo.cs
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices;using System.Text;namespace xxx.xxx.QA.Platform.Core.Monitor{ [StructLayout(LayoutKind.Sequential)] public struct MEMORY_INFO { public uint dwLength; public uint dwMemoryLoad;//内存占用比 public UInt64 dwTotalPhys; //总的物理内存大小 public UInt64 dwAvailPhys; //可用的物理内存大小 public UInt64 dwTotalPageFile; public UInt64 dwAvailPageFile; //可用的页面文件大小 public UInt64 dwTotalVirtual; //返回调用进程的用户模式部分的全部可用虚拟地址空间 public UInt64 dwAvailVirtual; // 返回调用进程的用户模式部分的实际自由可用的虚拟地址空间 } [StructLayout(LayoutKind.Sequential)] public struct MEMORYSTATUSEX { public uint dwLength; public uint dwMemoryLoad; public ulong ullTotalPhys; public ulong ullAvailPhys; public ulong ullTotalPageFile; public ulong ullAvailPageFile; public ulong ullTotalVirtual; public ulong ullAvailVirtual; public ulong ullAvailExtendedVirtual; } ////// 存放内存信息 /// public class MemoryInfo { public uint memoryLoad { get; set; }//返回00形式 public ulong totalPhys { get; set; } //以Bite为单位 public ulong availPhys { get; set; }//以Bite为单位 } public class MemoryMonitor { ////// 获取内存信息 /// /// [DllImport("kernel32")] public static extern void GlobalMemoryStatus(ref MEMORY_INFO meminfo); [DllImport("kernel32")] public static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX stat); ////// 获取内存信息 /// ///public static MemoryInfo getMemoryInfo() { MEMORY_INFO memInfo = new MEMORY_INFO(); MEMORYSTATUSEX memEx = new MEMORYSTATUSEX(); memEx.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX)); GlobalMemoryStatusEx(ref memEx); GlobalMemoryStatus(ref memInfo); MemoryInfo memoryInfo = new MemoryInfo(); memoryInfo.memoryLoad = memInfo.dwMemoryLoad; memoryInfo.availPhys = memInfo.dwAvailPhys; memoryInfo.totalPhys = memInfo.dwTotalPhys; return memoryInfo; } /// /// 获取内存占用率 /// ///public static uint GetMenoryLoad() { MEMORY_INFO memInfo = new MEMORY_INFO(); MEMORYSTATUSEX memEx = new MEMORYSTATUSEX(); memEx.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX)); GlobalMemoryStatusEx(ref memEx); GlobalMemoryStatus(ref memInfo); return memInfo.dwMemoryLoad; } /// /// 获取指定驱动器的空间总大小(单位为B) /// /// 只需输入代表驱动器的字母即可 (大写) ///public static long GetHardDiskSpace(string str_HardDiskName) { long totalSize = new long(); str_HardDiskName = str_HardDiskName + ":\\"; System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives(); foreach (System.IO.DriveInfo drive in drives) { if (drive.Name == str_HardDiskName) { totalSize = drive.TotalSize; } } return totalSize; } /// /// 获取指定驱动器的剩余空间总大小(单位为B) /// /// 只需输入代表驱动器的字母即可 ///public static long GetHardDiskFreeSpace(string str_HardDiskName) { long freeSpace = new long(); str_HardDiskName = str_HardDiskName + ":\\"; System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives(); foreach (System.IO.DriveInfo drive in drives) { if (drive.Name == str_HardDiskName) { freeSpace = drive.TotalFreeSpace; } } return freeSpace; } }}
4. 把所有这些监控指标放入一个Util中
MonitorUtil.cs
using NLog;using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace xxx.xxx.QA.Platform.Core.Monitor{ public class MonitorUtil { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public static MachineMonitorInfo GetMachineMonitorInfo() { MachineMonitorInfo info = new MachineMonitorInfo(); ArrayList listThread = new ArrayList(); // 获取CPU占用比 Thread thread1 = new Thread(delegate() { GetCpu(ref info); }); thread1.Start(); listThread.Add(thread1); // 获取CPU核数 Thread thread2 = new Thread(delegate() { GetCpuCount(ref info); }); thread2.Start(); listThread.Add(thread2); // 获取可用内存 Thread thread3 = new Thread(delegate() { GetMenoryAvaliable(ref info); }); thread3.Start(); listThread.Add(thread3); // 获取总内存 Thread thread4 = new Thread(delegate() { GetMenoryTotal(ref info); }); thread4.Start(); listThread.Add(thread4); // 获取C盘可用空间 Thread thread5 = new Thread(delegate() { GetCAvaliable(ref info); }); thread5.Start(); listThread.Add(thread5); // 获取C盘总空间 Thread thread6 = new Thread(delegate() { GetCTotal(ref info); }); thread6.Start(); listThread.Add(thread6); // 获取D盘可用空间 Thread thread7 = new Thread(delegate() { GetDAvaliable(ref info); }); thread7.Start(); listThread.Add(thread7); // 获取D盘总空间 Thread thread8 = new Thread(delegate() { GetDTotal(ref info); }); thread8.Start(); listThread.Add(thread8); foreach (Thread thread in listThread) { thread.Join(); } return info; } public static void GetCpu(ref MachineMonitorInfo info) { lock (info) { info.CpuUsage = CPUMonitor.getValue(); } } public static void GetCpuCount(ref MachineMonitorInfo info) { lock (info) { info.CoreNumber = ProcessorCountMonitor.getValue(); } } public static void GetMenoryAvaliable(ref MachineMonitorInfo info) { lock (info) { info.MemoryAvailable = (MemoryMonitor.getMemoryInfo().availPhys/(1024*1024)); } } public static void GetMenoryTotal(ref MachineMonitorInfo info) { lock (info) { info.PhysicalMemory = (MemoryMonitor.getMemoryInfo().totalPhys / (1024 * 1024)); } } public static void GetCAvaliable(ref MachineMonitorInfo info) { lock (info) { info.CHardDiskFreeSpace = (MemoryMonitor.GetHardDiskFreeSpace("C") / (1024 * 1024)); } } public static void GetCTotal(ref MachineMonitorInfo info) { lock (info) { info.CHardDiskSpace = (MemoryMonitor.GetHardDiskSpace("C") / (1024 * 1024)); } } public static void GetDAvaliable(ref MachineMonitorInfo info) { lock (info) { info.DHardDiskFreeSpace = (MemoryMonitor.GetHardDiskFreeSpace("D") / (1024 * 1024)); } } public static void GetDTotal(ref MachineMonitorInfo info) { lock (info) { info.DHardDiskSpace = (MemoryMonitor.GetHardDiskSpace("D") / (1024 * 1024)); } } } [Serializable] public class MachineMonitorInfo { public float CpuUsage { get; set; } public int CoreNumber { get; set; } public float MemoryAvailable { get; set; } public float PhysicalMemory { get; set; } public float CHardDiskFreeSpace { get; set; } public float DHardDiskFreeSpace { get; set; } public float CHardDiskSpace { get; set; } public float DHardDiskSpace { get; set; } }}
5. 新建个定时触发的task来监控
MonitorTask.cs
using FluentScheduler;using NLog;using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Web;namespace xxx.xxx.QA.Platform.EnvAgent.Services.Tasks{ public class MonitorTask : 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 机器监控 EnvMachineMonitorConfig monitorConfig = EnvMachineMonitorConfigBiz.GetCurrentMachineMonitorConfig(); // 判断监控开启 if (monitorConfig != null && monitorConfig.Turnon == 1) { //Logger.Info("监控开始时间:" + DateTime.Now.ToLocalTime()); // 获取机器实时监控信息 MachineMonitorInfo info = MonitorUtil.GetMachineMonitorInfo(); int cpu = (int)info.CpuUsage; int memory = (int)((info.MemoryAvailable / info.PhysicalMemory) * 100); int c = (int)(((info.CHardDiskSpace - info.CHardDiskFreeSpace) / info.CHardDiskSpace) * 100); int d = (int)(((info.DHardDiskSpace - info.DHardDiskFreeSpace) / info.DHardDiskSpace) * 100); DateTime time = DateTime.Now.ToLocalTime(); // 实时监控信息插入数据库 Logger.Info("Add Machine Monitor info (" + envMachine.Id + ", " + cpu + ", " + memory + ", " + time + ")"); EnvMachineMonitor newInfo = EnvMachineMonitorBiz.AddMachineMonitorInfo(envMachine.Id, cpu, memory, c, d, time); //Logger.Info("Result: success, return EnvMachineMonitor id is " + newInfo.Id); #region 机器预警 if (monitorConfig.Issendmail == 1) { DateTime dn = DateTime.Now.ToLocalTime(); //Logger.Info("现在时间:"+dn.ToLocalTime()); //Logger.Info("时间器时间:" + EmailSendTime.GetTime().ToLocalTime()); //Logger.Info("时间差:" + EmailSendTime.GetTimeSpanSecond(dn).ToString()+"s"); if (EmailSendTime.GetTimeSpanSecond(dn) > 15) { string reciever = monitorConfig.Recievers; // 未设置情况默认为该账户 if (reciever == null || reciever.Equals("")) { reciever = "[email protected]"; } bool flag = false; string body = envMachine.IP + "时间
" + time; // CPU占用率过高报警:邮件告知 if (monitorConfig.Cpu != null && cpu > monitorConfig.Cpu || cpu > 95) { body += "CPU占用率超标
CPU占用率: " + cpu + "(阈值:" + monitorConfig.Cpu + ")
"; flag = true; } // 内存占用率过高报警:邮件告知 if (memory > monitorConfig.Memery || memory > 95) { body += "内存占用率超标
内存占用率:" + memory + "(阈值:" + monitorConfig.Memery + ")
"; flag = true; } // C盘占用率过高报警:邮件告知 if (c > monitorConfig.C || c > 95) { body += "C盘占用率超标
C盘占用率:" + c + "(阈值:" + monitorConfig.C + ")
"; flag = true; } // D盘占用率过高报警:邮件告知 if (d > monitorConfig.D || d > 95) { body += "D盘占用率超标
D盘占用率:" + d + "(阈值:" + monitorConfig.D + ")
"; flag = true; } if (flag) { Mail.SendMailWithHtml2(reciever, "机器预警:" + envMachine.Name, body, "[email protected]"); Logger.Info("Send 机器预警 mail:" + body); EmailSendTime.SetTime(dn); //Logger.Info("时间器时间设为:"+EmailSendTime.GetTime().ToLocalTime()); //Logger.Info("监控结束时间:" + DateTime.Now.ToLocalTime()); } } } #endregion } #endregion } catch (Exception ex) { Logger.Error("MonitorTask异常信息:" + ex.ToString()); } finally { ChangeState(false); } } private void ChangeState(bool running) { lock (Locker) { _isRunning = running; } } } public class AppPoolMonitorInfo { public string name {get;set;} public string turnOn {get;set;} }}
6. 注册下task
public class TaskRegistry : Registry { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public TaskRegistry() { Logger.Info("每1分钟执行下机器监控"); Schedule().ToRunNow().AndEvery(1).Minutes(); } }
存数据基本完成了,所用表如下:
配置表:
监控数据表:
前端展示:
用的引用有:
@Styles.Render("~/Content/themes/metro/css")
@Styles.Render("~/Content/themes/custom/chcore.css")
@Styles.Render("~/Content/themes/fakeloader/fakeloader.css")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/Scripts/jquery.mousewheel.js")
@Scripts.Render("~/Scripts/jquery.widget.min.1.9.1.js")
@Scripts.Render("~/Scripts/highcharts4.1.8/highcharts.js")
@Scripts.Render("~/Scripts/highcharts4.1.8/exporting.js")
@Scripts.Render("~/Scripts/jquery.datatables.js")
@Scripts.Render("~/Scripts/custom/chcoreui.js")
@Scripts.Render("~/Scripts/custom/Chart.js")
@Scripts.Render("~/Scripts/pages/envhomepage.js")
@Scripts.Render("~/Scripts/control/fakeloader/fakeloader.min.js")
@*@Scripts.Render("~/Scripts/combined/envhome.min.js")*@
@Scripts.Render("~/Scripts/metro.min.js")
显示页面js
图标用highcharts4.1.8实现
/// Machine-Infomation ///var informationpage = { render: function () { var mainContainer = $(pageid.mainContent); mainContainer.empty(); // toolbar mainContainer.append(''); // #region 注册载 入机器监控信息按钮事件 $('#btnloadMachineMonitorInfo').click(function () { informationpage.getMachineMonitorInfo(); }); }, IISReset: function (id) { var machine = pagefind.currentMachine(); var sender = $("#" + id); var ip = machine.IP; iisresetpage.postReset(ip, sender); }, getMachineMonitorInfo: function () { var container = $("#machinemonitor"); var machine = pagefind.currentMachine(); container.empty(); if (machine == null) { $.note(null, '请先选择环境&机器', 'error'); return; } container.append(''); var container1 = $("#container1"); var container2 = $("#container2"); chcoreui.attachLoader(container1, pageid.loader, 410, 100); var url = 'http://' + machine.IP + ':8167/MachineMonitor/GetMachineMonitorInfo'; var pack = new Object(); pack.Token = $.readCookie('accessToken'); var submitData = JSON.stringify(pack); $.ajax({ type: "POST", url: url, data: submitData, dataType: "json", contentType: "application/json", crossDomain: true, success: function (results) { if (results.StateCode == 0) { var bodyContent = ''; var memoryvalue = ((results.Data.PhysicalMemory - results.Data.MemoryAvailable) / results.Data.PhysicalMemory).toFixed(4) * 100; var cvalue = (1 - results.Data.CHardDiskFreeSpace / results.Data.CHardDiskSpace).toFixed(4) * 100; var dvalue = (1-results.Data.DHardDiskFreeSpace / results.Data.DHardDiskSpace).toFixed(4) * 100 ; bodyContent += ''; bodyContent += ' CPU ' + results.Data.CoreNumber + '核 '; bodyContent += ' 内存 ' + results.Data.PhysicalMemory + 'MB ' + results.Data.MemoryAvailable + 'MB '; bodyContent += ' C盘 ' + results.Data.CHardDiskSpace + 'MB ' + results.Data.CHardDiskFreeSpace + 'MB '; container1.html(' D盘 ' + results.Data.DHardDiskSpace + 'MB ' + results.Data.DHardDiskFreeSpace + 'MB
Name | 占用百分比 | 总数 | 可用 | Action |
---|
图标显示js
(function ($){ $.cpuandmemorychart = function (container, monitorinfo) { var time = new Array(); var cpu = new Array(); var memory = new Array(); var c = new Array(); var d = new Array(); var i=0; $.each(monitorinfo, function (name, value) { time[i] = $.convertToDateStr(value.Time); cpu[i] = value.Cpu; memory[i] = value.Memory; c[i] = value.C; d[i] = value.D; i++; }); container.highcharts({ title: { text: '机器资源监控', x: -20 //center }, subtitle: { text: 'CPU、内存、C盘、D盘占用率', x: -20 }, xAxis: { categories: time }, yAxis: { title: { text: '百分比(%)' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, tooltip: { valueSuffix: '%' }, legend: { layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0 }, series: [{ name: 'CPU', data: cpu }, { name: '内存', data: memory }, { name: 'C盘', data: c }, { name: 'D盘', data: d }] }); } })(jQuery);
2. 配置页面js
var monitorconfigpage = { render: function () { var container = $(pageid.mainContent); container.empty(); chcoreui.attachLoader(container, pageid.loader, 410, 100); var url = '/MachineMonitor/MonitorConfig'; $.getJSON('/MachineMonitor/MonitorConfig', function (results) { if (results.StateCode == 0) { // 成功 var bodyContent = ''; $.each(results.Data, function (idx, item) { bodyContent += ''; }); container.empty(); container.html(' ' + item.MachineName + ' ' + item.IPAddress + ' ' + item.DomainName + '  
机器名 | IP地址 | 环境名称 | CPU占用比 | 内存占用比 | 开启监控 | Actions |
---|