Initial_commit_SecMPS_v2

This commit is contained in:
2026-05-15 23:22:48 +08:00
commit 23ea4fe05f
13830 changed files with 298675 additions and 0 deletions

View File

@@ -0,0 +1,451 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using VolPro.Core.PerformanceMonitor;
using VolPro.Core.Services;
namespace VolPro.Core.PerformanceMonitor
{
/// <summary>
/// 获取服务器参数
/// gaobin
/// </summary>
public static class ComputerHelper
{
/// <summary>
/// 内存使用情况
/// </summary>
/// <returns></returns>
public static MemoryMetrics GetComputerInfo()
{
try
{
MemoryMetricsClient client = new();
MemoryMetrics memoryMetrics = IsUnix() ? client.GetUnixMetrics() : client.GetWindowsMetrics();
//剩余内存
memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB";
//已用内存
memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB";
//总内存
memoryMetrics.TotalRAM = Math.Round(memoryMetrics.Total / 1024, 2) + "GB";
//内存使用率
memoryMetrics.RAMRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%";
//cpu使用率
// double cpurate = Math.Ceiling(GetCPURate());
memoryMetrics.CPURate = GetCPURate();
//cpu数量
//memoryMetrics.Total = client.total
return memoryMetrics;
}
catch { }
//catch (Exception ex)
//{
// Console.WriteLine("获取内存使用出错msg=" + ex.Message + "," + ex.StackTrace);
//}
return new MemoryMetrics();
}
/// <summary>
/// 获取内存大小
/// </summary>
/// <returns></returns>
public static List<DiskInfo> GetDiskInfos()
{
List<DiskInfo> diskInfos = new();
if (IsUnix())
{
try
{
string output = ShellHelper.Bash("df -m / | awk '{print $2,$3,$4,$5,$6}'");
var arr = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
if (arr.Length == 0) return diskInfos;
var rootDisk = arr[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
if (rootDisk == null || rootDisk.Length == 0)
{
return diskInfos;
}
DiskInfo diskInfo = new()
{
DiskName = "/",
TotalSize = long.Parse(rootDisk[0]) / 1024,
Used = long.Parse(rootDisk[1]) / 1024,
AvailableFreeSpace = long.Parse(rootDisk[2]) / 1024,
AvailablePercent = decimal.Parse(rootDisk[3].Replace("%", ""))
};
diskInfos.Add(diskInfo);
}
catch { }
//catch (Exception ex)
//{
// //Console.WriteLine("获取磁盘信息出错了" + ex.Message);
//}
}
else
{
var driv = DriveInfo.GetDrives();
foreach (var item in driv)
{
try
{
if (!item.IsReady || (item.DriveType != DriveType.Fixed && item.DriveType != DriveType.Removable))
{
continue; // 跳过未就绪/非存储类磁盘
}
var obj = new DiskInfo()
{
DiskName = item.Name,
TypeName = item.DriveType.ToString(),
TotalSize = item.TotalSize / 1024 / 1024 / 1024,
AvailableFreeSpace = item.AvailableFreeSpace / 1024 / 1024 / 1024,
};
obj.Used = obj.TotalSize - obj.AvailableFreeSpace;
obj.AvailablePercent = decimal.Ceiling(obj.Used / (decimal)obj.TotalSize * 100);
diskInfos.Add(obj);
}
catch { }
//catch (Exception ex)
//{
// // Console.WriteLine("获取磁盘信息出错了" + ex.Message);
// continue;
//}
}
}
return diskInfos;
}
public static bool IsUnix()
{
var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
return isUnix;
}
/// <summary>
/// iis部署存在权限问题获取不到CPU
/// 打开 Internet Information Services (IIS) 管理器
///在左侧导航栏中展开服务器名称,点击 应用程序池
///找到你的应用程序使用的应用池,右键点击并选择 高级设置
///在 [进程模型] -> [标识] 属性,默认为 ApplicationPoolIdentity改为LocalSystem
/// </summary>
/// <returns></returns>
public static string GetCPURate()
{
try
{
// Console.WriteLine("开始获取CPU使用率...");
if (IsUnix())
{
string output = ShellHelper.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'");
string result = output.Trim();
return result;
}
else
{
// 只在Windows平台上使用Windows特定的方法
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Console.WriteLine("尝试方法1性能计数器增加等待时间");
double rate = GetCpuUsageUsingPerformanceCounterWithLongerWait();
// Console.WriteLine("性能计数器返回值:" + rate);
if (rate > 0 && rate <= 100)
{
string cpuRate = rate.ToString("F1"); // 保留一位小数
return cpuRate;
}
}
}
}
catch (Exception ex)
{
Logger.AddAsync("获取CPU使用率出错" + ex.Message);
Console.WriteLine("获取CPU使用率出错" + ex.Message);
Console.WriteLine("堆栈跟踪:" + ex.StackTrace);
}
//Console.WriteLine("返回默认CPU使用率0.0");
return "0.0";
}
/// <summary>
/// 使用性能计数器获取CPU使用率增加等待时间
/// </summary>
/// <returns>CPU使用率百分比</returns>
private static double GetCpuUsageUsingPerformanceCounterWithLongerWait()
{
// 确保只在Windows平台上执行
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return 0;
}
using (var cpuCounter = new System.Diagnostics.PerformanceCounter(
"Processor", "% Processor Time", "_Total", true))
{
try
{
// 第一次获取是初始值
double initialValue = cpuCounter.NextValue();
// Console.WriteLine("性能计数器初始值:" + initialValue);
// 增加等待时间以获得更准确的值
System.Threading.Thread.Sleep(200); // 增加到500毫秒
// 第二次获取实际值
double value = cpuCounter.NextValue();
// Console.WriteLine("性能计数器实际值:" + value);
// 确保返回值在合理范围内
if (value < 0) value = 0;
if (value > 100) value = 100;
return value;
}
catch (Exception ex)
{
Console.WriteLine("性能计数器操作失败:" + ex.Message);
throw;
}
}
}
/// <summary>
/// 获取系统运行时间
/// </summary>
/// <returns></returns>
public static string GetRunTime()
{
string runTime = string.Empty;
try
{
if (IsUnix())
{
string output = ShellHelper.Bash("uptime -s").Trim();
runTime = FormatTime(ParseToLong((DateTime.Now - ParseToDateTime(output)).TotalMilliseconds.ToString().Split('.')[0]));
}
else
{
string output = ShellHelper.Cmd("wmic", "OS get LastBootUpTime/Value");
string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
if (outputArr.Length == 2)
{
runTime = FormatTime(ParseToLong((DateTime.Now - ParseToDateTime(outputArr[1].Split('.')[0])).TotalMilliseconds.ToString().Split('.')[0]));
}
}
}
catch (Exception ex)
{
Console.WriteLine("获取runTime出错" + ex.Message);
}
return runTime;
}
private static string FormatTime(long value)
{
return "2020-01-01";
}
public static long ParseToLong(string str, long defaultValue)
{
try
{
return long.Parse(str);
}
catch
{
return defaultValue;
}
}
public static long ParseToLong(this object obj)
{
try
{
return long.Parse(obj.ToString());
}
catch
{
return 0L;
}
}
public static DateTime ParseToDateTime(string str)
{
try
{
if (string.IsNullOrWhiteSpace(str))
{
return DateTime.MinValue;
}
else
{
int length = str.Length;
switch (length)
{
case 4:
return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
case 6:
return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
case 8:
return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
case 10:
return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
case 12:
return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
case 14:
return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
default:
return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
}
}
}
catch
{
return DateTime.MinValue;
}
}
}
/// <summary>
/// 内存信息
/// </summary>
public class MemoryMetrics
{
/// <summary>
/// CPU逻辑处理器数量
/// </summary>
public double CPUTotal { get; set; }
/// <summary>
/// CPU核数
/// </summary>
public double CPUNum { get; set; }
/// <summary>
/// 内存大小
/// </summary>
[JsonIgnore]
public double Total { get; set; }
//[JsonIgnore]
public double Used { get; set; }
//[JsonIgnore]
public double Free { get; set; }
public string UsedRam { get; set; }
/// <summary>
/// CPU使用率%
/// </summary>
public string CPURate { get; set; }
/// <summary>
/// 总内存 GB
/// </summary>
public string TotalRAM { get; set; }
/// <summary>
/// 内存使用率 %
/// </summary>
public string RAMRate { get; set; }
/// <summary>
/// 空闲内存
/// </summary>
public string FreeRam { get; set; }
}
public class DiskInfo
{
/// <summary>
/// 磁盘名
/// </summary>
public string DiskName { get; set; }
public string TypeName { get; set; }
public long TotalFree { get; set; }
public long TotalSize { get; set; }
/// <summary>
/// 已使用
/// </summary>
public long Used { get; set; }
/// <summary>
/// 可使用
/// </summary>
public long AvailableFreeSpace { get; set; }
public decimal AvailablePercent { get; set; }
}
public class MemoryMetricsClient
{
#region
public MemoryMetrics GetWindowsMetrics()
{
var metrics = new MemoryMetrics();
metrics.CPUTotal = Environment.ProcessorCount;
MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX();
if (GlobalMemoryStatusEx(memStatus))
{
// ullTotalPhys: 总物理内存(字节)
// ullAvailPhys: 可用物理内存(字节)
metrics.Total = Math.Round((double)memStatus.ullTotalPhys / (1024 * 1024), 0);
metrics.Free = Math.Round((double)memStatus.ullAvailPhys / (1024 * 1024), 0);
metrics.Used = metrics.Total - metrics.Free; // 系统已用内存 = 总内存 - 可用内存
}
return metrics;
}
[StructLayout(LayoutKind.Sequential)]
public class MEMORYSTATUSEX
{
public uint dwLength; // 结构体大小
public uint dwMemoryLoad; // 内存使用率0-100
public ulong ullTotalPhys; // 总物理内存(字节)
public ulong ullAvailPhys; // 可用物理内存(字节)
public ulong ullTotalPageFile; // 总页面文件大小(字节)
public ulong ullAvailPageFile; // 可用页面文件大小(字节)
public ulong ullTotalVirtual; // 总虚拟内存(字节)
public ulong ullAvailVirtual; // 可用虚拟内存(字节)
public ulong ullAvailExtendedVirtual; // 可用扩展虚拟内存(字节)
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
}
}
[DllImport("kernel32.dll")]
public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
/// <summary>
/// Unix系统获取
/// </summary>
/// <returns></returns>
public MemoryMetrics GetUnixMetrics()
{
string output = ShellHelper.Bash("free -m | awk '{print $2,$3,$4,$5,$6}'");
var metrics = new MemoryMetrics();
var lines = output.Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
if (lines.Length <= 0) return metrics;
if (lines != null && lines.Length > 0)
{
var memory = lines[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
if (memory.Length >= 3)
{
metrics.Total = double.Parse(memory[0]);
metrics.Used = double.Parse(memory[1]);
metrics.Free = double.Parse(memory[2]);//m
}
}
//cpu逻辑处理器数量
metrics.CPUTotal = System.Environment.ProcessorCount;
return metrics;
}
#endregion
}
}

View File

@@ -0,0 +1,15 @@
using System.Threading.Tasks;
namespace VolPro.Core.PerformanceMonitor
{
/// <summary>
/// 性能监控广播器接口
/// </summary>
public interface IPerformanceMonitorBroadcaster
{
/// <summary>
/// 广播性能监控数据给所有客户端
/// </summary>
Task BroadcastPerformanceMetricsAsync();
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.PerformanceMonitor
{
/// <summary>
/// 性能监控服务接口
/// </summary>
public interface IPerformanceMonitorService
{
/// <summary>
/// 获取当前性能指标
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>性能指标数据</returns>
Task<object> GetCurrentMetricsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// 获取历史性能数据
/// </summary>
/// <param name="from">开始时间</param>
/// <param name="to">结束时间</param>
/// <returns>历史性能数据</returns>
Task<object> GetHistoricalMetricsAsync(DateTime from, DateTime to);
}
}

View File

@@ -0,0 +1,205 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using VolPro.Core.EFDbContext;
using VolPro.Core.Log;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.PerformanceMonitor
{
/// <summary>
/// 服务器监控后台服务,定时采集服务器信息并写入 Sys_Monitor 表
/// </summary>
public class MonitorBackgroundService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger<MonitorBackgroundService> _logger;
private readonly IPerformanceMonitorBroadcaster _broadcaster;
/// <summary>采集间隔(毫秒),默认 20 秒</summary>
private const int IntervalMs = 20_000;
// 缓存的服务器信息
private static string _cachedHostName;
private static string _cachedIp;
private static string _cachedMac;
public MonitorBackgroundService(
IServiceScopeFactory scopeFactory,
ILogger<MonitorBackgroundService> logger,
IPerformanceMonitorBroadcaster broadcaster = null)
{
_scopeFactory = scopeFactory;
_logger = logger;
_broadcaster = broadcaster; // 可以为null如果没有注册广播器
// 初始化时缓存服务器信息
CacheServerInfo();
}
/// <summary>
/// 缓存服务器信息主机名、IP、MAC地址
/// </summary>
private void CacheServerInfo()
{
try
{
var (hostName, ip, mac) = GetHostAndNetwork();
_cachedHostName = hostName ?? "Unknown";
_cachedIp = ip ?? "127.0.0.1";
_cachedMac = mac ?? "-";
//_logger.LogInformation($"服务器信息已缓存 - 主机名: {_cachedHostName}, IP: {_cachedIp}, MAC: {_cachedMac}");
}
catch (Exception ex)
{
_logger.LogError(ex, "缓存服务器信息失败");
_cachedHostName = "Unknown";
_cachedIp = "127.0.0.1";
_cachedMac = "-";
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
string msg = $"服务性能监控启动,采集间隔:{IntervalMs / 1000} 秒";
Console.Write(msg);
Logger.AddAsync(msg);
while (!stoppingToken.IsCancellationRequested)
{
try
{
await CollectAndSaveAsync(stoppingToken);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
_logger.LogError(ex, "采集或保存服务器监控数据失败");
}
try
{
await Task.Delay(IntervalMs, stoppingToken);
}
catch (OperationCanceledException)
{
break;
}
}
Logger.AddAsync("MonitorBackgroundService 已停止");
}
private async Task CollectAndSaveAsync(CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<SysDbContext>();
// 使用缓存的服务器信息
var hostName = _cachedHostName;
var ip = _cachedIp;
var mac = _cachedMac;
var metrics = ComputerHelper.GetComputerInfo();
var disks = ComputerHelper.GetDiskInfos();
decimal? cpuUsage = null;
if (!string.IsNullOrWhiteSpace(metrics?.CPURate) && double.TryParse(metrics.CPURate.TrimEnd('%'), out var cpuVal))
cpuUsage = (decimal)Math.Min(100, Math.Max(0, cpuVal));
decimal? memoryUsage = null;
if (!string.IsNullOrWhiteSpace(metrics?.RAMRate) && double.TryParse(metrics.RAMRate.TrimEnd('%'), out var memVal))
memoryUsage = (decimal)Math.Min(100, Math.Max(0, memVal));
string diskInfoJson = null;
if (disks != null && disks.Count > 0)
{
var diskList = disks.Select(d => new
{
d.DiskName,
d.TypeName,
d.TotalSize,
d.Used,
d.AvailableFreeSpace,
d.AvailablePercent
}).ToList();
diskInfoJson = JsonConvert.SerializeObject(diskList);
}
var record = new Sys_Monitor
{
Id = new IdWorker().NextId(),
HostName = hostName ?? "Unknown",
Ip = ip ?? "127.0.0.1",
MacAddress = mac ?? "-",
CpuUsage = cpuUsage,
MemoryUsage = memoryUsage,
BandwidthUsage = null, // 需基于流量统计,此处暂不实现
DiskInfo = diskInfoJson,
RecordTime = DateTime.Now
};
await db.SqlSugarClient.Insertable(record).ExecuteCommandAsync();
//db.Set<Sys_Monitor>().add(record);
//await db.SaveChangesAsync(cancellationToken);
//// 数据保存成功后,通过广播器推送给所有连接的客户端
//if (_broadcaster != null)
//{
// try
// {
// await _broadcaster.BroadcastPerformanceMetricsAsync();
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "广播性能监控数据失败");
// }
//}
}
private static (string hostName, string ip, string mac) GetHostAndNetwork()
{
var hostName = Environment.MachineName;
if (string.IsNullOrWhiteSpace(hostName))
{
try { hostName = Dns.GetHostName(); } catch { hostName = "Unknown"; }
}
string ip = "127.0.0.1";
string mac = "-";
try
{
var ni = NetworkInterface.GetAllNetworkInterfaces()
.FirstOrDefault(n =>
n.OperationalStatus == OperationalStatus.Up
&& n.NetworkInterfaceType != NetworkInterfaceType.Loopback
&& n.NetworkInterfaceType != NetworkInterfaceType.Tunnel);
if (ni != null)
{
var addr = ni.GetIPProperties().UnicastAddresses
.FirstOrDefault(a => a.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
if (addr != null)
ip = addr.Address.ToString();
var raw = ni.GetPhysicalAddress()?.GetAddressBytes();
if (raw != null && raw.Length > 0)
mac = string.Join("-", raw.Select(b => b.ToString("X2")));
}
}
catch { /* 忽略网络信息获取异常 */ }
return (hostName, ip, mac);
}
}
}

View File

@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Log;
using VolPro.Core.PerformanceMonitor;
namespace VolPro.Core.PerformanceMonitor
{
public static class MonitorExtensions
{
public static IServiceCollection AddMonitor(this IServiceCollection services, WebApplicationBuilder builder)
{
// 注册性能监控广播器
services.AddSingleton<IPerformanceMonitorBroadcaster, PerformanceMonitorBroadcaster>();
// 注册性能监控服务
services.AddScoped<IPerformanceMonitorService, PerformanceMonitorService>();
// builder.Configuration
// Console.WriteLine("mm" + builder.Configuration["montior"]);
//发布后才会启动服务监听 !builder.Environment.IsDevelopment() ||
if (builder.Configuration["montior"] == "1")
{
services.AddHostedService<MonitorBackgroundService>();
}
// services.AddHostedService<MonitorBackgroundService>();
return services;
}
}
}

View File

@@ -0,0 +1,70 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using VolPro.Core.Services;
namespace VolPro.Core.PerformanceMonitor
{
/// <summary>
/// 性能监控广播器实现
/// </summary>
public class PerformanceMonitorBroadcaster : IPerformanceMonitorBroadcaster
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger<PerformanceMonitorBroadcaster> _logger;
private readonly IHubContext<PerformanceMonitorSignalR> _hubContext;
public PerformanceMonitorBroadcaster(
IServiceScopeFactory scopeFactory,
ILogger<PerformanceMonitorBroadcaster> logger,
IHubContext<PerformanceMonitorSignalR> hubContext)
{
_scopeFactory = scopeFactory;
_logger = logger;
_hubContext = hubContext;
}
/// <summary>
/// 广播性能监控数据给所有客户端
/// </summary>
public async Task BroadcastPerformanceMetricsAsync()
{
try
{
using (var scope = _scopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<IPerformanceMonitorService>();
var metrics = await service.GetCurrentMetricsAsync();
// 将object转换为dynamic以便访问属性
dynamic data = metrics;
// SignalR推送时过滤掉diskInfo只推送其他实时更新的数据
var signalRData = new
{
hostName = data.hostName,
ip = data.ip,
macAddress = data.macAddress,
cpuUsage = data.cpuUsage,
memoryUsagePercentage = data.memoryUsagePercentage,
cacheHitRate = data.cacheHitRate,
errorRate = data.errorRate,
apiResponseTimes = data.apiResponseTimes,
requestCount = data.requestCount,
errorCount = data.errorCount,
lastUpdateTime = data.lastUpdateTime
// 注意不包含diskInfo磁盘信息只在首次API调用时获取
};
// 广播数据给所有连接的客户端
await _hubContext.Clients.All.SendAsync("PerformanceMonitorCurrent", signalRData);
}
}
catch (System.Exception ex)
{
Logger.AddAsync($"广播性能监控数据失败:{ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,245 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using VolPro.Core.EFDbContext;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.PerformanceMonitor
{
/// <summary>
/// 性能监控服务实现
/// </summary>
public class PerformanceMonitorService : IPerformanceMonitorService
{
private readonly SysDbContext _dbContext;
private readonly ILogger<PerformanceMonitorService> _logger;
public PerformanceMonitorService(
SysDbContext dbContext,
ILogger<PerformanceMonitorService> logger)
{
_dbContext = dbContext;
_logger = logger;
}
/// <summary>
/// 获取当前服务器的MAC地址
/// </summary>
private static string GetCurrentServerMacAddress()
{
try
{
var ni = NetworkInterface.GetAllNetworkInterfaces()
.FirstOrDefault(n =>
n.OperationalStatus == OperationalStatus.Up
&& n.NetworkInterfaceType != NetworkInterfaceType.Loopback
&& n.NetworkInterfaceType != NetworkInterfaceType.Tunnel);
if (ni != null)
{
var raw = ni.GetPhysicalAddress()?.GetAddressBytes();
if (raw != null && raw.Length > 0)
{
return string.Join("-", raw.Select(b => b.ToString("X2")));
}
}
}
catch { /* 忽略获取MAC地址的异常 */ }
return "-";
}
/// <summary>
/// 获取当前性能指标
/// </summary>
public async Task<object> GetCurrentMetricsAsync(CancellationToken cancellationToken = default)
{
// 获取当前服务器的MAC地址
var currentMacAddress = GetCurrentServerMacAddress();
// 获取最新的监控数据按MacAddress过滤
var latestRecord = await _dbContext.Set<Sys_Monitor>()
.Where(x => x.MacAddress == currentMacAddress)
.OrderByDescending(x => x.Id)
.FirstAsync();
// 解析磁盘信息
var diskInfo = new List<object>();
if (latestRecord != null && !string.IsNullOrWhiteSpace(latestRecord.DiskInfo))
{
try
{
diskInfo = JsonConvert.DeserializeObject<List<object>>(latestRecord.DiskInfo) ?? new List<object>();
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析磁盘信息失败");
}
}
// 获取系统信息
var systemInfo = GetSystemInformation();
if (latestRecord == null)
{
return new
{
// 服务器信息
hostName = "Unknown",
ip = "127.0.0.1",
macAddress = "-",
// 新增系统信息
systemArchitecture = systemInfo.Architecture,
systemVersion = systemInfo.Version,
cpuCoreCount = systemInfo.CpuCoreCount,
totalMemory = systemInfo.TotalMemory,
usedMemory = systemInfo.UsedMemory,
// CPU使用率
cpuUsage = 0.0,
// 内存使用率
memoryUsagePercentage = 0.0,
// 缓存命中率
cacheHitRate = 0.0,
// 错误率
errorRate = 0.0,
// API响应时间暂时模拟数据
apiResponseTimes = new List<object>(),
// 请求计数
requestCount = 0,
// 错误计数
errorCount = 0,
// 磁盘信息
diskInfo,
// 最后更新时间
lastUpdateTime = DateTime.Now
};
}
// 构建返回数据
var metrics = new
{
// 服务器信息
hostName = latestRecord.HostName ?? "Unknown",
ip = latestRecord.Ip ?? "127.0.0.1",
macAddress = latestRecord.MacAddress ?? "-",
// 新增系统信息
systemArchitecture = systemInfo.Architecture,
systemVersion = systemInfo.Version,
cpuCoreCount = systemInfo.CpuCoreCount,
totalMemory = systemInfo.TotalMemory,
usedMemory = systemInfo.UsedMemory,
// CPU使用率
cpuUsage = latestRecord.CpuUsage ?? 0,
// 内存使用率
memoryUsagePercentage = latestRecord.MemoryUsage ?? 0,
// 缓存命中率(暂时固定值,实际需要从缓存系统获取)
cacheHitRate = 85.0,
// 错误率(暂时固定值,实际需要从日志系统获取)
errorRate = 0.5,
// 请求计数
requestCount = 1250,
// 错误计数
errorCount = 6,
// 磁盘信息
diskInfo,
// 最后更新时间
lastUpdateTime = latestRecord.RecordTime
};
return metrics;
}
/// <summary>
/// 获取系统信息
/// </summary>
private static dynamic GetSystemInformation()
{
try
{
// 获取内存信息
var memoryMetrics = ComputerHelper.GetComputerInfo();
// 构建系统信息对象
return new
{
// 系统架构
Architecture = RuntimeInformation.OSArchitecture.ToString(),
// 系统版本
Version = RuntimeInformation.OSDescription,
// CPU核心数量
CpuCoreCount = Environment.ProcessorCount,
// 内存总大小
TotalMemory = memoryMetrics.TotalRAM,
// 内存使用大小
UsedMemory = memoryMetrics.UsedRam
};
}
catch (Exception ex)
{
// 记录错误并返回默认值
Console.WriteLine("获取系统信息失败:" + ex.Message);
return new
{
Architecture = "Unknown",
Version = "Unknown",
CpuCoreCount = 0,
TotalMemory = "0GB",
UsedMemory = "0GB"
};
}
}
/// <summary>
/// 获取历史性能数据
/// </summary>
public async Task<object> GetHistoricalMetricsAsync(DateTime from, DateTime to)
{
var currentMacAddress = GetCurrentServerMacAddress();
var historicalData = await _dbContext.Set<Sys_Monitor>()
// .Where(x => x.RecordTime >= from && x.RecordTime <= to)
.Where(x => x.MacAddress == currentMacAddress)
.OrderByDescending(x => x.Id)
.Select(x => new
{
x.Id,
recordTime = x.RecordTime,
cpuUsage = x.CpuUsage,
memoryUsage = x.MemoryUsage,
//bandwidthUsage = x.BandwidthUsage,
//diskInfo = x.DiskInfo
})
.Take(2000).ToListAsync();
return historicalData.OrderBy(x => x.Id);
}
}
}

View File

@@ -0,0 +1,46 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.PerformanceMonitor
{
/// <summary>
/// 性能监控SignalR Hub
/// </summary>
public class PerformanceMonitorSignalR : Hub
{
private readonly ILogger<PerformanceMonitorSignalR> _logger;
public PerformanceMonitorSignalR(
ILogger<PerformanceMonitorSignalR> logger)
{
_logger = logger;
}
/// <summary>
/// 客户端连接时调用
/// </summary>
public override Task OnConnectedAsync()
{
//var connectionId = Context.ConnectionId;
//_logger.LogInformation($"客户端连接: {connectionId}");
return base.OnConnectedAsync();
}
/// <summary>
/// 客户端断开连接时调用
/// </summary>
public override Task OnDisconnectedAsync(Exception exception)
{
//var connectionId = Context.ConnectionId;
//_logger.LogInformation($"客户端断开连接: {connectionId}");
return base.OnDisconnectedAsync(exception);
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.PerformanceMonitor
{
public class ShellHelper
{
/// <summary>
/// linux 系统命令
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
public static string Bash(string command)
{
var escapedArgs = command.Replace("\"", "\\\"");
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"{escapedArgs}\"",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
process.Dispose();
return result;
}
/// <summary>
/// windows系统命令
/// </summary>
/// <param name="fileName"></param>
/// <param name="args"></param>
/// <returns></returns>
public static string Cmd(string fileName, string args)
{
string output = string.Empty;
var info = new ProcessStartInfo();
info.FileName = fileName;
info.Arguments = args;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;
using (var process = Process.Start(info))
{
output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
}
return output;
}
}
}