Net6.0 编写看门狗程序

程序名称: GateKeeper

功能:本程序可以监视Windows服务程序和Windows进程,一旦发现被监视的服务或进程停止运行,程序会立即程序启动它。不说废话,直接贴代码。

 

 

 

1、主程序:Program.cs

namespace GateKeeper
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            IHost host = Host.CreateDefaultBuilder(args)
                .UseWindowsService()
                .ConfigureLogging(logging =>
                {
                    logging.ClearProviders();
                    logging.AddProvider(new LoggerFileProvider("GateKeeper"));
                })
                .ConfigureServices(services =>
                {
                    services.AddHostedService<Worker>();
                })
                .Build();

            await host.RunAsync();
        }
    }
}

2、文件日志提供器:LoggerFileProvider.cs

using System.Reflection;

namespace GateKeeper
{
    /// <summary>
    /// 文件日志提供器
    /// </summary>
    public class LoggerFileProvider : ILoggerProvider
    {
        private readonly string _appId;
        public LoggerFileProvider(string appId)
        {
            _appId = appId;
        }

        public ILogger CreateLogger(string categoryName)
        {
            return new Logger(categoryName, _appId);
        }

        public void Dispose()
        {
            
        }

        public class Logger : ILogger
        {
            private readonly string _categoryName;
            private readonly string _appId;
            private static readonly string logFileFmt = "yyyy-MM-dd";
            private static string logDate = DateTime.Now.ToString(logFileFmt);

            public Logger(string categoryName, string appId)
            {
                _categoryName = categoryName;
                _appId = appId;
            }

            public IDisposable BeginScope<TState>(TState state)
            {
                return new NoopDisposable();
            }

            private class NoopDisposable : IDisposable
            {
                public void Dispose()
                {

                }
            }

            public bool IsEnabled(LogLevel logLevel)
            {
                return false;
            }

            public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
            {
                try
                {
                    RecordMsg(logLevel, eventId, state, exception, formatter);
                }
                catch (Exception ex)
                {
                    RecordMsg(logLevel, eventId, state, ex, formatter);
                }
            }

            private void RecordMsg<TState>(LogLevel logLevel, EventId eventId, TState? state, Exception? exception, Func<TState, Exception?, string> formatter)
            {
                string msg = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff} - [{logLevel.ToSingle()}] - {formatter(state!, exception)}";
                msg = msg.Replace("\r", "").Replace("\n", "");
                Console.WriteLine(msg);

                var dirPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "log");
                if (!Directory.Exists(dirPath))
                {
                    Directory.CreateDirectory(dirPath);
                }
                var filePath = Path.Combine(dirPath, "log.txt");
                var date = DateTime.Now.ToString(logFileFmt);
                if (!date.Equals(logDate))
                {
                    var backPath = Path.Combine(dirPath, logDate + ".log");
                    File.Copy(filePath, backPath, true);
                    File.WriteAllText(filePath, "");
                    logDate = date;
                }

                File.AppendAllText(filePath, msg + Environment.NewLine);
            }
        }
    }

    public static class Externsions
    {
        public static string ToSingle(this LogLevel level)
        {
            switch (level)
            {
                case LogLevel.Critical: return "C";
                case LogLevel.Debug: return "D";
                case LogLevel.Error: return "E";
                case LogLevel.Information: return "I";
                case LogLevel.None: return "N";
                case LogLevel.Trace: return "T";
                case LogLevel.Warning: return "W";
                default: return "";
            }
        }
    }

}

3、进程配置信息: ProcessInfo.cs

namespace GateKeeper
{
    public class ProcessInfo
    {
        public string? Name { get; set; }
        public string? Location { get; set; }
    }
}

4、Windows服务控制:WindowsService.cs

using System.ServiceProcess;

namespace GateKeeper
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:验证平台兼容性", Justification = "<挂起>")]
    public class WindowsService
    {
        public static ServiceControllerStatus GetWinServiceStatus(string serviceName)
        {
            var sc = new ServiceController(serviceName);
            return sc.Status;
        }

        public static void StopWinService(string serviceName)
        {
            var sc = new ServiceController(serviceName);
            sc.Stop();
        }

        public static void StartWinService(string serviceName)
        {
            var sc = new ServiceController(serviceName);
            sc.Start();
        }

        public static void RefreshWinService(string serviceName)
        {
            var sc = new ServiceController(serviceName);
            sc.Refresh();
        }
    }
}

5、服务程序:Worker.cs

using System.Diagnostics;

namespace GateKeeper
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IConfiguration _configuration;
        private bool running = true;
        public Worker(ILogger<Worker> logger, IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            running = true;
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            running = false;
            return base.StopAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await Task.Delay(300, stoppingToken);

            var services = _configuration.GetSection("Services").Get<List<string>>() ?? new List<string>();
            _logger.LogInformation("监视的服务:{msg}", string.Join(",", services));

            _ = Task.Run(async () =>
            {
                while (running)
                {
                    ServiceDaemon(services);
                    await Task.Delay(int.Parse(_configuration["Interval"]));
                }
                _logger.LogInformation("ServiceDaemon exit");
            });

            var processes = _configuration.GetSection("Processes").Get<List<ProcessInfo>>() ?? new List<ProcessInfo>();
            _logger.LogInformation("监视的进程:{msg}", string.Join(",", processes.Select(p => $"{p.Name}|{p.Location}")));
            _ = Task.Run(async () =>
            {
                while (running)
                {
                    ProcessDeamon(processes);
                    await Task.Delay(int.Parse(_configuration["Interval"]));
                }
                _logger.LogInformation("ProcessDeamon exit");
            });

            _logger.LogInformation("{msg}", $"时间间隔:{_configuration["Interval"]}毫秒");
        }

        private void ServiceDaemon(List<string> services)
        {
            foreach (var name in services)
            {
                try
                {
                    if (WindowsService.GetWinServiceStatus(name) == System.ServiceProcess.ServiceControllerStatus.Stopped)
                    {
                        WindowsService.StartWinService(name);
                        _logger.LogInformation("{message}", $"{name}停止,已经重新启动");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogWarning("{message}", ex.Message);
                }

            }
        }

        private void ProcessDeamon(List<ProcessInfo> processes)
        {
            foreach (var process in processes)
            {
                var processList = Process.GetProcessesByName(process.Name);
                if (processList.Length == 0)
                {
                    var info = new ProcessStartInfo
                    {
                        FileName = process.Location,
                        Arguments = "",
                        WindowStyle = ProcessWindowStyle.Minimized
                    };
                    Process.Start(info);
                    _logger.LogInformation("{msg}", $"{process.Name}停止, 已重新启动");
                    Task.Delay(4000).Wait();
                }
                Task.Delay(1000).Wait();
            }
        }
    }
}

6、配置文件:AppSettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "Interval": 1000,  /* 循环的时间间隔(毫秒)*/
  "Services": [ "MariaDB" ],  /* 监视的服务 */
  "Processes": [
    {
      "Name": "EmEditor",  /* 监视的进程 */
      "Location": "C:\\Users\\Robot\\AppData\\Local\\Programs\\EmEditor\\EmEditor.exe"    /* 执行路径 */
    }
  ]
}

 

说明:本程序可以作为控制台程序直接运行, 也可安装为Windows服务运行。

运行效果:

 

posted @ 2022-10-20 10:16  RobotChen  阅读(384)  评论(0)    收藏  举报