美文网首页
C#进程监控小程序

C#进程监控小程序

作者: 蓬篙人 | 来源:发表于2021-05-29 16:56 被阅读0次

背景

由于历史原因,存在一些旧服务程序,无法修改其源代码,但是某个客户更换新服务器后,可能由于兼容性问题导致服务经常会掉线或报错卡死。因此,开发一个程序对指定的服务进程进行监控,在服务掉线后自动重启服务,在服务报错卡死时自动关掉服务进程并重启。

程序设计

程序是使用C#开发的一个托盘程序,主要包含操作系统进程监测,操作系统应用程序日志监测和服务程序维护三部分功能。


监控程序框架图
  • 操作系统进程监测:定时获取当前操作系统所有正在运行的进程进行循环判断。如果被监控服务程序存在且非标记为错误进程则无需重启;如果被监控服务程序不存在或被标记为错误进程则进行重启操作。流程如下:


    进程监控流程
  • 操作系统应用程序日志监测:捕获操作系统应用程序中的错误日志,并根据日志信息,判断是否为所监控的服务程序,是则将服务程序名称放入错误服务程序列表中。

  • 服务程序维护:使用xml文件保存需要监控的服务程序名称和路径。

程序实现

1. C#托盘程序

C#的托盘程序是使用NotifyIcon控件来实现。主要步骤如下:

  • 窗体Load事件中关闭窗体
private void FormMain_Load(object sender, EventArgs e)
{
    Close();
}
  • 窗体FormClosing事件中取消窗体关闭和显示NotifyIcon控件等。注意:一定要给NotifyIcon控件设置图标,不然电脑右下角不会显示。
private void FormMain_FormClosing(object sender, EventArgs e)
{
    if (e.CloseReason != CloseReason.WindowShutDown)
    {
        e.Cancel = true;
        Hide();
        ShowInTaskbar = false;
        nIconMonitor.Visible = true;      // show NotifyIcon
    }
}
  • 根据需要添加ContextMenuStrip控件及相应菜单项,在NotifyIconMouseDown事件中绑定。下面代码采用右键显示菜单:
// nIconMonitor为NotifyIcon控件,cmsMonitor为ContextMenuStrip控件
private void nIconMonitor_MouseDown(object sender, MouseEventArgs e)
{
    if(e.Button == MouseButtons.Right)
    {
        nIconMonitor.ContextMenuStrip = cmsMonitor;
    }
}

2. 进程监测实现

主要使用System.Diagnostics.Process类获取当前正在运行的所有进程,判断被监控服务程序是否存在或被标记为错误。主要代码如下:

Process[] sysProcess = Process.GetProcesses();
List<int> killIndex = new List<int>();
for (int i = 0; i < sysProcess.Length; i++)
{
    string processName = sysProcess[i].ProcessName;
    if (mMonitorServices.Services.ContainsKey(processName))
    {
         string path = mMonitorServices.Services[processName].Path;
         if (path == sysProcess[i].MainModule.FileName)
         {
            if (mErrorApp.Contains(processName))
            {
               killIndex.Add(i);
            }
           else
                mMonitorServices.Services[processName].Reboot = false;
         }
    }
}
for (int i = 0; i < killIndex.Count; i++)
{
    string processName = sysProcess[killIndex[i]].ProcessName;
    sysProcess[killIndex[i]].Kill();
    mMonitorServices.Services[processName].Reboot = true;
    mErrorApp.Remove(processName);
}

程序重启直接调用Process.Start("path")即可,其中path为程序绝对路径。

3. 日志监测实现

操作系统应用程序错误日志监测主要使用EventLogWatcherEventLogQuery这两个类,其中EventLogQuery设定日志的查询条件,而通过EventLogWatcherEventRecordWritten事件捕获错误日志并进行服务程序错误标记。

private void StartEventLogWatcher()
{
    EventLogQuery query = new EventLogQuery("Application", PathType.FilePath, "*[System/Level=2]");
    mWatcher = new EventLogWatcher(query);
    mWatcher.EventRecordWritten += Watcher_EventRecordWritten;
    mWatcher.Enabled = true;
}

private void Watcher_EventRecordWritten(object sender, EventRecordWrittenEventArgs e)
{
    if (e.EventRecord != null)
    {
        var properties = e.EventRecord.Properties;
        foreach (var data in properties)
        {
            string info = data.Value.ToString();
            if(info.Contains(".exe"))
            {
                string appName = info.Replace(".exe", "");
                if (mMonitorServices.Services.ContainsKey(appName))
                {
                    mErrorApp.Add(appName);
                    break;
                }
            }
        }
    }
}
  • EventLogQuery类中的"Application"指定监测应用程序日志,"*[System/Level=2]"指定捕获级别为2的日志,即错误日志。

  • e.EventRecord.Properties是日志记录保存自定义数据的属性,下图中的EventData。该属性是一个IList<EventProperty>对象,我们主要是想获取其中表示程序名称的信息。

    应用程序错误日志.png
  • mErrorApp是一个保存错误服务程序名称的List<string>对象。

4. 服务程序维护

因为只是一个小程序,所以监控的服务程序信息使用xml文件保存和维护。因此该模块功能主要是xml文件的一些操作。保存服务程序的xml文件格式如下:

<?xml version="1.0" encoding="utf-8" ?>
<services>
  <service name="Service1">
    <path>D:\Services\DicomService.exe</path>
  </service>
</services>

其中每一个监控的服务程序使用一个<service>节点进行保存,节点的name属性保存服务程序的名称(不含程序后缀.exe),子节点<path>保存服务程序的绝对路径。维护类代码如下:

using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml;

namespace WinformServiceMonitor
{
    public class ServicesXml
    {
        private readonly string mFileName = $"{Application.StartupPath}\\Services.xml";
        // 保存监控的服务程序字典
        private Dictionary<string, MonitorService> mServicesDict = new Dictionary<string, MonitorService>();

        public Dictionary<string, MonitorService> Services
        {
            get { return mServicesDict; }
        }

        public ServicesXml()
        {
            if (!File.Exists(mFileName))
                CreateXmlFile();
            ReadServices();
        }

        private void ReadServices()
        {
            XmlDocument document = new XmlDocument();
            document.Load(mFileName);
            XmlNode root = document.SelectSingleNode("services");
            foreach(XmlNode node in root.ChildNodes)
            {
                string name = node.Attributes["name"].Value;
                if (!mServicesDict.ContainsKey(name))
                {
                    mServicesDict.Add(name, new MonitorService { Name = name, Path = node["path"].InnerText });
                }
            }
        }

        public void AddServiceNode(string name, string path)
        {
            XmlDocument document = new XmlDocument();
            document.Load(mFileName);
            XmlNode root = document.SelectSingleNode("services");

            XmlElement serviceNode = document.CreateElement("service");
            serviceNode.SetAttribute("name", name);
            XmlElement pathNode = document.CreateElement("path");
            pathNode.InnerText = path;
            serviceNode.AppendChild(pathNode);
            root.AppendChild(serviceNode);

            mServicesDict.Add(name, new MonitorService { Name = name, Path = path, Reboot = false });

            document.Save(mFileName);
        }

        public void RemoveServiceNode(string name)
        {
            XmlDocument document = new XmlDocument();
            document.Load(mFileName);
            XmlNode root = document.SelectSingleNode("services");
            bool remove = false;
            foreach (XmlNode node in root.ChildNodes)
            {
                if (node.Attributes["name"].Value == name)
                {
                    root.RemoveChild(node);
                    remove = true;
                    break;
                }
            }
            if (remove)
                mServicesDict.Remove(name);
            document.Save(mFileName);
        }

        private void CreateXmlFile()
        {
            XmlDocument document = new XmlDocument();
            XmlDeclaration declaration = document.CreateXmlDeclaration("1.0", "UTF-8", "");
            document.AppendChild(declaration);

            XmlElement services = document.CreateElement("services");
            document.AppendChild(services);
            document.Save(mFileName);
        }
    }
}
namespace WinformServiceMonitor
{
    // 监控服务程序实体类
    public class MonitorService
    {
        /// <summary>
        /// 服务程序名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 服务绝对路径
        /// </summary>
        public string Path { get; set; }
        /// <summary>
        /// 是否需要重启
        /// </summary>
        public bool Reboot { get; set; }

        public MonitorService()
        {
            Reboot = false;
        }
    }
}
  • 注意:其中为了方便,添加和移除功能都是直接打开xml文件进行操作,如果不是这种小程序不建议这样操作。

参考文章

相关文章

  • C#进程监控小程序

    背景 由于历史原因,存在一些旧服务程序,无法修改其源代码,但是某个客户更换新服务器后,可能由于兼容性问题导致服务经...

  • 20笔记---进程1

    今日内容 1.进程是什么 2.程序和进程的区别 ps:每个进程都有父进程,是PPID,子进程则叫PID 2.监控进...

  • 第九章 使用日志监控 - 系统监控工具

    第九章 使用日志监控 - 系统监控工具 日志监控器监控 数据平台实例的消息日志,以查找守护程序和用户进程报告的错误...

  • Python监控脚本异常和进程异常

    脚本程序监控:通过python装饰器监控脚本是否异常,如果异常发送报警邮件通知开发人员 脚本进程监控:因为使用的是...

  • Linux进程管理

    1.进程基本概述 2.程序和进程的区别 3.进程的生命周期 4.监控进程状态 5.STAT详解 STAT基本状态描...

  • 2020-03-31 获取微信好友真实地址

    监控微信网络事件 首先打开火绒剑点击进程,查看微信程序(WeChat.exe)的进程ID,列如下面我的微信程序的进...

  • supervisor

    supervisor 一个Linux/Unix系统上的进程监控工具一个Python开发的通用的进程管理程序可以管理...

  • 命令行工具监控linux系统性能

    现在介绍一些linux系统调试工具 1. top —Linux系统进程监控 top 命令是性能监控程序,它可以在很...

  • 2017-08-06学习日迹

    C#进程基础 进程:一个正在运行的程序,操作系统根据进程分配各种资源(内存) 线程:操作系统为了提高效率会将一个进...

  • 第五十九章 使用 ^PERFSAMPLE 监控进程 - 收集样本

    第五十九章 使用 ^PERFSAMPLE 监控进程 - 收集样本 本主题介绍 ^PERFSAMPLE 实用程序,这...

网友评论

      本文标题:C#进程监控小程序

      本文链接:https://www.haomeiwen.com/subject/pgbysltx.html