823e467078
- Introduced a batch script to simplify the startup process for the Resource Monitor Service. - Included checks for .NET 9.0 Runtime installation. - Added build and run commands for the service with appropriate error handling. - Provided user instructions and API documentation links in the script output.
669 lines
29 KiB
C#
669 lines
29 KiB
C#
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using ResourceMonitorService.Configuration;
|
|
using ResourceMonitorService.Models;
|
|
using System.Diagnostics;
|
|
using System.Management;
|
|
|
|
namespace ResourceMonitorService.Services
|
|
{
|
|
public interface IResourceMonitorService
|
|
{
|
|
Task<ResourceUsage> GetResourceUsageAsync();
|
|
Task<CpuUsage> GetCpuUsageAsync();
|
|
Task<MemoryUsage> GetMemoryUsageAsync();
|
|
Task<GpuUsage> GetGpuUsageAsync();
|
|
Task<List<DiskUsage>> GetDiskUsageAsync();
|
|
Task<NetworkUsage> GetNetworkUsageAsync();
|
|
Task<List<ProcessInfo>> GetTopProcessesAsync(int count = 10);
|
|
}
|
|
|
|
public class ResourceMonitorService : IResourceMonitorService
|
|
{
|
|
private readonly ILogger<ResourceMonitorService> _logger;
|
|
private readonly MonitoringSettings _settings;
|
|
private readonly Dictionary<string, PerformanceCounter> _counters;
|
|
private readonly Dictionary<string, long> _previousNetworkBytes;
|
|
private readonly Dictionary<string, DateTime> _previousNetworkTime;
|
|
|
|
public ResourceMonitorService(ILogger<ResourceMonitorService> logger, IOptions<MonitoringSettings> settings)
|
|
{
|
|
_logger = logger;
|
|
_settings = settings.Value;
|
|
_counters = new Dictionary<string, PerformanceCounter>();
|
|
_previousNetworkBytes = new Dictionary<string, long>();
|
|
_previousNetworkTime = new Dictionary<string, DateTime>();
|
|
InitializeCounters();
|
|
}
|
|
|
|
private void InitializeCounters()
|
|
{
|
|
try
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
_counters["cpu"] = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
|
_counters["memory_available"] = new PerformanceCounter("Memory", "Available MBytes");
|
|
|
|
if (_settings.EnableNetworkMonitoring)
|
|
{
|
|
_counters["network_bytes_sent"] = new PerformanceCounter("Network Interface", "Bytes Sent/sec", "*");
|
|
_counters["network_bytes_received"] = new PerformanceCounter("Network Interface", "Bytes Received/sec", "*");
|
|
}
|
|
|
|
if (_settings.EnableDiskMonitoring)
|
|
{
|
|
_counters["disk_read"] = new PerformanceCounter("PhysicalDisk", "Disk Read Bytes/sec", "_Total");
|
|
_counters["disk_write"] = new PerformanceCounter("PhysicalDisk", "Disk Write Bytes/sec", "_Total");
|
|
_counters["disk_time"] = new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
|
|
// Initialize counters with first reading
|
|
foreach (var counter in _counters.Values)
|
|
{
|
|
try
|
|
{
|
|
counter.NextValue();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to initialize performance counter: {CounterName}", counter.CounterName);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to initialize performance counters");
|
|
}
|
|
}
|
|
|
|
public async Task<ResourceUsage> GetResourceUsageAsync()
|
|
{
|
|
var timestamp = DateTime.Now;
|
|
|
|
var tasks = new List<Task>
|
|
{
|
|
Task.Run(async () => await GetCpuUsageAsync()),
|
|
Task.Run(async () => await GetMemoryUsageAsync())
|
|
};
|
|
|
|
if (_settings.EnableGpuMonitoring)
|
|
tasks.Add(Task.Run(async () => await GetGpuUsageAsync()));
|
|
|
|
if (_settings.EnableDiskMonitoring)
|
|
tasks.Add(Task.Run(async () => await GetDiskUsageAsync()));
|
|
|
|
if (_settings.EnableNetworkMonitoring)
|
|
tasks.Add(Task.Run(async () => await GetNetworkUsageAsync()));
|
|
|
|
if (_settings.EnableProcessMonitoring)
|
|
tasks.Add(Task.Run(async () => await GetTopProcessesAsync(_settings.MaxProcessesToTrack)));
|
|
|
|
await Task.WhenAll(tasks);
|
|
|
|
return new ResourceUsage
|
|
{
|
|
Timestamp = timestamp,
|
|
CPU = await GetCpuUsageAsync(),
|
|
Memory = await GetMemoryUsageAsync(),
|
|
GPU = _settings.EnableGpuMonitoring ? await GetGpuUsageAsync() : new GpuUsage(),
|
|
Disks = _settings.EnableDiskMonitoring ? await GetDiskUsageAsync() : new List<DiskUsage>(),
|
|
Network = _settings.EnableNetworkMonitoring ? await GetNetworkUsageAsync() : new NetworkUsage(),
|
|
TopProcesses = _settings.EnableProcessMonitoring ? await GetTopProcessesAsync(_settings.MaxProcessesToTrack) : new List<ProcessInfo>(),
|
|
Temperature = _settings.EnableTemperatureMonitoring ? await GetTemperatureInfoAsync() : new TemperatureInfo()
|
|
};
|
|
}
|
|
|
|
public async Task<CpuUsage> GetCpuUsageAsync()
|
|
{
|
|
try
|
|
{
|
|
var temperature = await GetCpuTemperatureAsync();
|
|
|
|
return await Task.Run(() =>
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
var usage = _counters.TryGetValue("cpu", out var cpuCounter) ? cpuCounter.NextValue() : 0f;
|
|
|
|
// Get per-core usage
|
|
var coreUsages = new List<float>();
|
|
for (int i = 0; i < Environment.ProcessorCount; i++)
|
|
{
|
|
try
|
|
{
|
|
using var coreCounter = new PerformanceCounter("Processor", "% Processor Time", i.ToString());
|
|
coreCounter.NextValue();
|
|
Thread.Sleep(100); // Small delay for accurate reading
|
|
coreUsages.Add(coreCounter.NextValue());
|
|
}
|
|
catch
|
|
{
|
|
coreUsages.Add(0f);
|
|
}
|
|
}
|
|
|
|
// Get CPU frequency
|
|
var maxFrequency = 0f;
|
|
var currentFrequency = 0f;
|
|
try
|
|
{
|
|
using var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
|
|
using var collection = searcher.Get();
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
maxFrequency = Convert.ToSingle(obj["MaxClockSpeed"]);
|
|
currentFrequency = Convert.ToSingle(obj["CurrentClockSpeed"]);
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not get CPU frequency information");
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
|
|
return new CpuUsage
|
|
{
|
|
Usage = usage,
|
|
CoreUsages = coreUsages.ToArray(),
|
|
MaxFrequency = maxFrequency,
|
|
CurrentFrequency = currentFrequency,
|
|
IsThrottling = currentFrequency < maxFrequency * 0.9f, // Consider throttling if running below 90% max frequency
|
|
Temperature = temperature
|
|
};
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting CPU usage");
|
|
return new CpuUsage();
|
|
}
|
|
}
|
|
|
|
public async Task<MemoryUsage> GetMemoryUsageAsync()
|
|
{
|
|
try
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
var availableMemoryMB = _counters.TryGetValue("memory_available", out var memCounter) ? memCounter.NextValue() : 0f;
|
|
var availableMemory = (ulong)(availableMemoryMB * 1024 * 1024);
|
|
|
|
// Get total memory
|
|
var totalMemory = 0UL;
|
|
using (var searcher = new ManagementObjectSearcher("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem"))
|
|
using (var collection = searcher.Get())
|
|
{
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
totalMemory = (ulong)obj["TotalPhysicalMemory"];
|
|
break;
|
|
}
|
|
}
|
|
|
|
var usedMemory = totalMemory - availableMemory;
|
|
var usagePercentage = totalMemory > 0 ? (float)(usedMemory) / totalMemory * 100 : 0f;
|
|
|
|
// Get additional memory info
|
|
var committedMemory = 0UL;
|
|
var pagedMemory = 0UL;
|
|
var nonPagedMemory = 0UL;
|
|
|
|
try
|
|
{
|
|
using var osSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
|
|
using var osCollection = osSearcher.Get();
|
|
foreach (ManagementObject obj in osCollection)
|
|
{
|
|
var totalVirtualMemory = (ulong)obj["TotalVirtualMemorySize"] * 1024;
|
|
var freeVirtualMemory = (ulong)obj["FreeVirtualMemory"] * 1024;
|
|
committedMemory = totalVirtualMemory - freeVirtualMemory;
|
|
break;
|
|
}
|
|
|
|
using var perfSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_PerfOS_Memory");
|
|
using var perfCollection = perfSearcher.Get();
|
|
foreach (ManagementObject obj in perfCollection)
|
|
{
|
|
pagedMemory = (ulong)obj["PoolPagedBytes"];
|
|
nonPagedMemory = (ulong)obj["PoolNonpagedBytes"];
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not get extended memory information");
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
|
|
return new MemoryUsage
|
|
{
|
|
UsagePercentage = usagePercentage,
|
|
UsedMemory = usedMemory,
|
|
AvailableMemory = availableMemory,
|
|
TotalMemory = totalMemory,
|
|
CommittedMemory = committedMemory,
|
|
PagedMemory = pagedMemory,
|
|
NonPagedMemory = nonPagedMemory
|
|
};
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting memory usage");
|
|
return new MemoryUsage();
|
|
}
|
|
}
|
|
|
|
public async Task<GpuUsage> GetGpuUsageAsync()
|
|
{
|
|
try
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
try
|
|
{
|
|
NvmlWrapper.NvmlInit();
|
|
IntPtr device;
|
|
NvmlWrapper.NvmlDeviceGetHandleByIndex(0, out device);
|
|
|
|
NvmlWrapper.NvmlUtilization utilization;
|
|
NvmlWrapper.NvmlDeviceGetUtilizationRates(device, out utilization);
|
|
|
|
uint temperature;
|
|
NvmlWrapper.NvmlDeviceGetTemperature(device, 0, out temperature);
|
|
|
|
uint fanSpeed;
|
|
NvmlWrapper.NvmlDeviceGetFanSpeed(device, out fanSpeed);
|
|
|
|
// Try to get additional information
|
|
var name = "NVIDIA GPU";
|
|
var driverVersion = "Unknown";
|
|
var memoryTotal = 0UL;
|
|
var memoryUsed = 0UL;
|
|
var powerUsage = 0U;
|
|
|
|
try
|
|
{
|
|
// Get GPU name and memory info via WMI as fallback
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
using var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_VideoController WHERE Name LIKE '%NVIDIA%'");
|
|
using var collection = searcher.Get();
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
name = obj["Name"]?.ToString() ?? name;
|
|
driverVersion = obj["DriverVersion"]?.ToString() ?? driverVersion;
|
|
if (obj["AdapterRAM"] != null)
|
|
{
|
|
memoryTotal = (ulong)obj["AdapterRAM"];
|
|
}
|
|
break;
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not get additional GPU information via WMI");
|
|
}
|
|
|
|
NvmlWrapper.NvmlShutdown();
|
|
|
|
return new GpuUsage
|
|
{
|
|
Usage = utilization.Gpu,
|
|
MemoryUsage = utilization.Memory,
|
|
Temperature = temperature,
|
|
FanSpeed = fanSpeed,
|
|
PowerUsage = powerUsage,
|
|
MemoryTotal = memoryTotal,
|
|
MemoryUsed = memoryUsed,
|
|
IsAvailable = true,
|
|
Name = name,
|
|
DriverVersion = driverVersion,
|
|
Error = string.Empty
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new GpuUsage
|
|
{
|
|
Usage = 0,
|
|
MemoryUsage = 0,
|
|
Temperature = 0,
|
|
FanSpeed = 0,
|
|
PowerUsage = 0,
|
|
MemoryTotal = 0,
|
|
MemoryUsed = 0,
|
|
IsAvailable = false,
|
|
Name = "Unknown",
|
|
DriverVersion = "Unknown",
|
|
Error = ex.Message
|
|
};
|
|
}
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting GPU usage");
|
|
return new GpuUsage { Error = ex.Message };
|
|
}
|
|
}
|
|
|
|
public async Task<List<DiskUsage>> GetDiskUsageAsync()
|
|
{
|
|
try
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
var diskUsages = new List<DiskUsage>();
|
|
|
|
var drives = DriveInfo.GetDrives();
|
|
foreach (var drive in drives)
|
|
{
|
|
if (drive.IsReady)
|
|
{
|
|
var diskUsage = new DiskUsage
|
|
{
|
|
DriveLetter = drive.Name,
|
|
Label = drive.VolumeLabel,
|
|
FileSystem = drive.DriveFormat,
|
|
TotalSize = (ulong)drive.TotalSize,
|
|
FreeSpace = (ulong)drive.AvailableFreeSpace,
|
|
UsedSpace = (ulong)(drive.TotalSize - drive.AvailableFreeSpace),
|
|
UsagePercentage = (float)(drive.TotalSize - drive.AvailableFreeSpace) / drive.TotalSize * 100
|
|
};
|
|
|
|
// Get disk performance data
|
|
try
|
|
{
|
|
var diskName = drive.Name.Replace("\\", "").Replace(":", "");
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
using var readCounter = new PerformanceCounter("LogicalDisk", "Disk Read Bytes/sec", diskName);
|
|
using var writeCounter = new PerformanceCounter("LogicalDisk", "Disk Write Bytes/sec", diskName);
|
|
using var timeCounter = new PerformanceCounter("LogicalDisk", "% Disk Time", diskName);
|
|
|
|
readCounter.NextValue();
|
|
writeCounter.NextValue();
|
|
timeCounter.NextValue();
|
|
|
|
Thread.Sleep(1000);
|
|
|
|
diskUsage.ReadSpeed = readCounter.NextValue() / (1024 * 1024); // Convert to MB/s
|
|
diskUsage.WriteSpeed = writeCounter.NextValue() / (1024 * 1024); // Convert to MB/s
|
|
diskUsage.DiskTime = timeCounter.NextValue();
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not get disk performance data for drive {Drive}", drive.Name);
|
|
}
|
|
|
|
// Try to determine if it's an SSD
|
|
try
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
using var searcher = new ManagementObjectSearcher($"SELECT * FROM Win32_LogicalDisk WHERE DeviceID='{drive.Name.TrimEnd('\\')}'");
|
|
using var collection = searcher.Get();
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
// This is a simplified check; more sophisticated detection would be needed
|
|
var mediaType = obj["MediaType"]?.ToString();
|
|
diskUsage.IsSSD = mediaType?.Contains("SSD") == true || mediaType?.Contains("Solid") == true;
|
|
break;
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not determine disk type for drive {Drive}", drive.Name);
|
|
}
|
|
|
|
diskUsages.Add(diskUsage);
|
|
}
|
|
}
|
|
|
|
return diskUsages;
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting disk usage");
|
|
return new List<DiskUsage>();
|
|
}
|
|
}
|
|
|
|
public async Task<NetworkUsage> GetNetworkUsageAsync()
|
|
{
|
|
try
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
var networkUsage = new NetworkUsage();
|
|
var adapters = new List<NetworkAdapter>();
|
|
|
|
try
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
using var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PerfRawData_Tcpip_NetworkInterface WHERE Name != 'Loopback'");
|
|
using var collection = searcher.Get();
|
|
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
var name = obj["Name"]?.ToString() ?? "";
|
|
if (name.Contains("Loopback") || name.Contains("Isatap") || name.Contains("Teredo"))
|
|
continue;
|
|
|
|
var bytesSent = Convert.ToInt64(obj["BytesSentPerSec"] ?? 0);
|
|
var bytesReceived = Convert.ToInt64(obj["BytesReceivedPerSec"] ?? 0);
|
|
var timestamp = DateTime.Now;
|
|
|
|
var adapter = new NetworkAdapter
|
|
{
|
|
Name = name,
|
|
IsOperational = true
|
|
};
|
|
|
|
// Calculate speeds if we have previous data
|
|
var key = $"{name}_sent";
|
|
if (_previousNetworkBytes.ContainsKey(key) && _previousNetworkTime.ContainsKey(key))
|
|
{
|
|
var timeDiff = (timestamp - _previousNetworkTime[key]).TotalSeconds;
|
|
if (timeDiff > 0)
|
|
{
|
|
var bytesDiff = bytesSent - _previousNetworkBytes[key];
|
|
adapter.UploadSpeed = (float)(bytesDiff / timeDiff / (1024 * 1024)); // MB/s
|
|
networkUsage.UploadSpeed += adapter.UploadSpeed;
|
|
}
|
|
}
|
|
|
|
key = $"{name}_received";
|
|
if (_previousNetworkBytes.ContainsKey(key) && _previousNetworkTime.ContainsKey(key))
|
|
{
|
|
var timeDiff = (timestamp - _previousNetworkTime[key]).TotalSeconds;
|
|
if (timeDiff > 0)
|
|
{
|
|
var bytesDiff = bytesReceived - _previousNetworkBytes[key];
|
|
adapter.DownloadSpeed = (float)(bytesDiff / timeDiff / (1024 * 1024)); // MB/s
|
|
networkUsage.DownloadSpeed += adapter.DownloadSpeed;
|
|
}
|
|
}
|
|
|
|
// Store current values for next calculation
|
|
_previousNetworkBytes[$"{name}_sent"] = bytesSent;
|
|
_previousNetworkBytes[$"{name}_received"] = bytesReceived;
|
|
_previousNetworkTime[$"{name}_sent"] = timestamp;
|
|
_previousNetworkTime[$"{name}_received"] = timestamp;
|
|
|
|
networkUsage.BytesSent += (ulong)bytesSent;
|
|
networkUsage.BytesReceived += (ulong)bytesReceived;
|
|
|
|
adapters.Add(adapter);
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not get network performance data");
|
|
}
|
|
|
|
networkUsage.Adapters = adapters;
|
|
return networkUsage;
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting network usage");
|
|
return new NetworkUsage();
|
|
}
|
|
}
|
|
|
|
public async Task<List<ProcessInfo>> GetTopProcessesAsync(int count = 10)
|
|
{
|
|
try
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
var processes = Process.GetProcesses()
|
|
.Where(p => !p.HasExited)
|
|
.Select(p =>
|
|
{
|
|
try
|
|
{
|
|
return new ProcessInfo
|
|
{
|
|
Id = p.Id,
|
|
Name = p.ProcessName,
|
|
MemoryUsage = (ulong)p.WorkingSet64,
|
|
ProcessorTime = p.TotalProcessorTime,
|
|
StartTime = p.StartTime,
|
|
ExecutablePath = p.MainModule?.FileName ?? "",
|
|
CommandLine = GetProcessCommandLine(p.Id)
|
|
};
|
|
}
|
|
catch
|
|
{
|
|
return null; // Skip processes that throw exceptions
|
|
}
|
|
})
|
|
.Where(p => p != null)
|
|
.OrderByDescending(p => p!.MemoryUsage)
|
|
.Take(count)
|
|
.Cast<ProcessInfo>()
|
|
.ToList();
|
|
|
|
return processes;
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting top processes");
|
|
return new List<ProcessInfo>();
|
|
}
|
|
}
|
|
|
|
private async Task<float> GetCpuTemperatureAsync()
|
|
{
|
|
try
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
// Try to get CPU temperature from WMI
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
using var searcher = new ManagementObjectSearcher(@"root\WMI", "SELECT * FROM MSAcpi_ThermalZoneTemperature");
|
|
using var collection = searcher.Get();
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
var temp = Convert.ToDouble(obj["CurrentTemperature"]);
|
|
return (float)((temp - 2732) / 10.0); // Convert from tenths of Kelvin to Celsius
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
return 0f;
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not get CPU temperature");
|
|
return 0f;
|
|
}
|
|
}
|
|
|
|
private async Task<TemperatureInfo> GetTemperatureInfoAsync()
|
|
{
|
|
try
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
var temperatureInfo = new TemperatureInfo
|
|
{
|
|
CPU = GetCpuTemperatureAsync().Result,
|
|
HardDrives = new List<HardDriveTemp>()
|
|
};
|
|
|
|
// Try to get hard drive temperatures
|
|
try
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
using var searcher = new ManagementObjectSearcher(@"root\WMI", "SELECT * FROM MSStorageDriver_ATAPISmartData");
|
|
using var collection = searcher.Get();
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
var instanceName = obj["InstanceName"]?.ToString() ?? "";
|
|
// This would need more sophisticated parsing for actual SMART data
|
|
temperatureInfo.HardDrives.Add(new HardDriveTemp
|
|
{
|
|
Drive = instanceName,
|
|
Temperature = 0f, // Would need SMART data parsing
|
|
Health = "Unknown"
|
|
});
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Could not get hard drive temperatures");
|
|
}
|
|
|
|
return temperatureInfo;
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting temperature information");
|
|
return new TemperatureInfo();
|
|
}
|
|
}
|
|
|
|
private string GetProcessCommandLine(int processId)
|
|
{
|
|
try
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
using var searcher = new ManagementObjectSearcher($"SELECT CommandLine FROM Win32_Process WHERE ProcessId = {processId}");
|
|
using var collection = searcher.Get();
|
|
foreach (ManagementObject obj in collection)
|
|
{
|
|
return obj["CommandLine"]?.ToString() ?? "";
|
|
}
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
return "";
|
|
}
|
|
catch
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
foreach (var counter in _counters.Values)
|
|
{
|
|
counter?.Dispose();
|
|
}
|
|
_counters.Clear();
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
}
|
|
}
|
|
}
|