using NLog;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PerformanceMonitoring
{
class ProcessMonitor
{
private readonly string _processName;
private bool _isRunning;
private readonly string _logFolder;
private readonly Dictionary<int, DateTime> _lastCpuTime = new Dictionary<int, DateTime>();
private readonly Dictionary<int, TimeSpan> _lastCpuUsage = new Dictionary<int, TimeSpan>();
private readonly Dictionary<int, long> _lastPrivateBytes = new Dictionary<int, long>();
private string MonitorTime= ConfigurationManager.AppSettings["MonitorTime"];
public ProcessMonitor(string processName)
{
_processName = processName;
_logFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
Directory.CreateDirectory(_logFolder);
}
public void Start()
{
if (_isRunning)
{
return;
}
_isRunning = true;
WriteLog("INFO", $"开始监控进程: {_processName}");
WriteLog("DATA", "时间,进程ID,CPU使用率(%),线程数,内存使用(MB)");
new Thread(MonitorLoop) { IsBackground = true }.Start();
}
private void MonitorLoop()
{
while (_isRunning)
{
try
{
var process = Process.GetProcessesByName(_processName).FirstOrDefault();
if (process == null)
{
}
else
{
MonitorProcess(process);
}
}
catch (Exception ex)
{
WriteLog("ERROR", $"监控错误: {ex.Message}");
}
Thread.Sleep(Convert.ToInt32( MonitorTime));
}
}
private void MonitorProcess(Process process)
{
try
{
process.Refresh();
double cpuUsage = CalculateCpuUsage(process);
double privateWorkingSetMB = GetPrivateWorkingSet(process.Id) / (1024.0 * 1024.0);
double workingSetMB = process.WorkingSet64 / (1024.0 * 1024.0);
double privateBytesMB = GetPrivateBytes(process.Id) / (1024.0 * 1024.0);
double virtualMemoryMB = process.VirtualMemorySize64 / (1024.0 * 1024.0);
WriteLog("DATA", $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}," +
$"-----【进程ID】:{process.Id}," +
$"-----【内存占用率】:{cpuUsage:F1}," +
$"-----【线程数量】:{process.Threads.Count}," +
$"-----【工作内存】:{workingSetMB:F2}," +
$"-----【私有内存】:{privateBytesMB:F2}," +
$"-----【共享内存】:{virtualMemoryMB:F2}" +
$"-----【显示】:{privateWorkingSetMB:F2}");
}
catch (InvalidOperationException)
{
WriteLog("INFO", $"进程已退出: {process.Id}");
}
catch (Exception ex)
{
WriteLog("ERROR", $"进程监控错误: {ex.Message}");
}
}
private long GetPrivateWorkingSet(int processId)
{
try
{
string instanceName = GetProcessInstanceName(processId);
if (string.IsNullOrEmpty(instanceName))
return 0;
using (var pc = new PerformanceCounter("Process", "Working Set - Private", instanceName))
{
return (long)pc.NextValue();
}
}
catch
{
try
{
var process = Process.GetProcessById(processId);
return process.WorkingSet64;
}
catch
{
return 0;
}
}
}
private long GetPrivateBytes(int processId)
{
try
{
if (!_lastPrivateBytes.ContainsKey(processId))
{
_lastPrivateBytes[processId] = 0;
}
using (var pc = new PerformanceCounter("Process", "Private Bytes", GetProcessInstanceName(processId)))
{
long bytes = (long)pc.NextValue();
_lastPrivateBytes[processId] = bytes;
return bytes;
}
}
catch
{
return _lastPrivateBytes.ContainsKey(processId) ? _lastPrivateBytes[processId] : 0;
}
}
private string GetProcessInstanceName(int pid)
{
var process = Process.GetProcessById(pid);
string processName = Path.GetFileNameWithoutExtension(process.ProcessName);
PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");
string[] instances = cat.GetInstanceNames()
.Where(inst => inst.StartsWith(processName))
.ToArray();
foreach (string instance in instances)
{
using (PerformanceCounter cnt = new PerformanceCounter("Process", "ID Process", instance, true))
{
if ((int)cnt.RawValue == pid)
{
return instance;
}
}
}
return "";
}
private double CalculateCpuUsage2(Process process)
{
TimeSpan userTime = TimeSpan.FromMilliseconds(process.UserProcessorTime.TotalMilliseconds);
TimeSpan kernelTime = TimeSpan.FromMilliseconds(process.TotalProcessorTime.TotalMilliseconds - process.UserProcessorTime.TotalMilliseconds);
double cpuUsage = (userTime.TotalSeconds + kernelTime.TotalSeconds) / process.PrivilegedProcessorTime.TotalSeconds * 100;
return cpuUsage;
}
private double CalculateCpuUsage(Process process)
{
var now = DateTime.Now;
var currentCpuTime = process.TotalProcessorTime;
if (!_lastCpuTime.ContainsKey(process.Id) || !_lastCpuUsage.ContainsKey(process.Id))
{
_lastCpuTime[process.Id] = now;
_lastCpuUsage[process.Id] = currentCpuTime;
return 0;
}
var timeDiff = (now - _lastCpuTime[process.Id]).TotalSeconds;
var cpuDiff = (currentCpuTime - _lastCpuUsage[process.Id]).TotalMilliseconds;
_lastCpuTime[process.Id] = now;
_lastCpuUsage[process.Id] = currentCpuTime;
return (cpuDiff / (timeDiff * 1000) / Environment.ProcessorCount) * 100;
}
public void Stop()
{
_isRunning = false;
WriteLog("INFO", "监控已停止");
}
private void WriteLog(string logType, string message)
{
try
{
string logFile = Path.Combine(_logFolder, $"{_processName}-{DateTime.Today:yyyyMMdd}.log");
string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{logType}] {message}";
File.AppendAllText(logFile, logEntry + Environment.NewLine);
}
catch (Exception ex)
{
try
{
string fallbackFile = Path.Combine(_logFolder, "monitor-fallback.log");
File.AppendAllText(fallbackFile, $"[{DateTime.Now}] 日志写入失败: {ex.Message}");
}
catch
{
}
}
}
}
}
namespace PerformanceMonitoring
{
using System;
using System.Configuration;
public static class ConfigHelper
{
public static string GetString(string key, string defaultValue = "")
{
try
{
var value = ConfigurationManager.AppSettings[key];
return string.IsNullOrWhiteSpace(value) ? defaultValue : value;
}
catch (Exception ex)
{
Console.WriteLine($"读取配置错误 [{key}]: {ex.Message}");
return defaultValue;
}
}
public static int GetInt(string key, int defaultValue = 0)
{
var value = GetString(key);
if (int.TryParse(value, out int result))
{
return result;
}
return defaultValue;
}
public static bool GetBool(string key, bool defaultValue = false)
{
var value = GetString(key).ToLower();
if (value == "true" || value == "1" || value == "yes")
{
return true;
}
if (value == "false" || value == "0" || value == "no")
{
return false;
}
return defaultValue;
}
public static double GetDouble(string key, double defaultValue = 0.0)
{
var value = GetString(key);
if (double.TryParse(value, out double result))
{
return result;
}
return defaultValue;
}
public static TimeSpan GetTimeSpan(string key, TimeSpan defaultValue)
{
var value = GetString(key);
if (TimeSpan.TryParse(value, out TimeSpan result))
{
return result;
}
return defaultValue;
}
public static T GetEnum<T>(string key, T defaultValue) where T : struct
{
var value = GetString(key);
if (Enum.TryParse(value, true, out T result))
{
return result;
}
return defaultValue;
}
public static string GetConnectionString(string name)
{
try
{
var connectionString = ConfigurationManager.ConnectionStrings[name];
return connectionString?.ConnectionString ?? string.Empty;
}
catch (Exception ex)
{
Console.WriteLine($"读取连接字符串错误 [{name}]: {ex.Message}");
return string.Empty;
}
}
}
}
using NLog;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PerformanceMonitoring
{
internal class Program
{
static void Main(string[] args)
{
string processName = ConfigurationManager.AppSettings["ProcessName"];
var monitor = new ProcessMonitor(processName);
monitor.Start();
var exitEvent = new ManualResetEvent(false);
Console.CancelKeyPress += (sender, e) => {
e.Cancel = true;
exitEvent.Set();
};
exitEvent.WaitOne();
monitor.Stop();
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<appSettings>
<add key="ProcessName" value="ConsoleApp3"/>
<add key="MonitorTime" value="1000"/>
</appSettings>
</configuration>