diff --git a/src/Task.Monitor.Cli.Utils/PInvokeErrorHelpers.cs b/src/Task.Monitor.Cli.Utils/PInvokeErrorHelpers.cs new file mode 100644 index 0000000..acb6590 --- /dev/null +++ b/src/Task.Monitor.Cli.Utils/PInvokeErrorHelpers.cs @@ -0,0 +1,44 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Task.Monitor.Cli.Utils; + +public static class PInvokeErrorHelpers +{ + public static void AssertOnLastError(string message) + { +#if DEBUG + int error = Marshal.GetLastPInvokeError(); + Debug.Assert(error == 0, GetFormattedErrorMessage(message)); +#endif + } + + public static void TraceOnLastError(string message) => + Trace.WriteLine(GetFormattedErrorMessage(message)); + + public static void TraceOnceOnLastError(string key) => + TraceEx.WriteLineOnce(key, GetFormattedErrorMessage()); + + public static void TraceOnceOnLastError(string key, string message) => + TraceEx.WriteLineOnce(key, GetFormattedErrorMessage(message)); + + public static void TraceOnPInvokeError(string message, uint error) => + Trace.WriteLine($"PINVOKE ERROR ({error}): {message}"); + + public static void TraceOnceOnPInvokeError(string key, string message, uint error) => + TraceEx.WriteLineOnce(key, $"PINVOKE ERROR ({error}): {message}"); + + private static string GetFormattedErrorMessage() => GetFormattedErrorMessage(string.Empty); + + private static string GetFormattedErrorMessage(string message) + { + int error = Marshal.GetLastPInvokeError(); + string errorMessage = $"PINVOKE ERROR ({error}): {Marshal.GetPInvokeErrorMessage(error)}"; + + if (string.IsNullOrEmpty(message)) { + errorMessage += $" {message}"; + } + + return errorMessage; + } +} diff --git a/src/Task.Monitor.Cli.Utils/TraceEx.cs b/src/Task.Monitor.Cli.Utils/TraceEx.cs new file mode 100644 index 0000000..65eb2a9 --- /dev/null +++ b/src/Task.Monitor.Cli.Utils/TraceEx.cs @@ -0,0 +1,29 @@ +using System.Collections.Concurrent; +using System.Diagnostics; + +namespace Task.Monitor.Cli.Utils; + +public static class TraceEx +{ + private static readonly ConcurrentDictionary lastSeen = new(); + private static TimeSpan suppressionWindow = TimeSpan.FromMinutes(10); + + public static void WriteLineOnce(string key, string message) + { + DateTime now = DateTime.UtcNow; + lastSeen.AddOrUpdate( + key, + addValueFactory: k => { + Trace.WriteLine($"Key: {key}: {message}"); + return now; + }, + updateValueFactory: (k, lastLoggedTime) => { + if (now - lastLoggedTime >= suppressionWindow) { + Trace.WriteLine($"Key: {key}: {message}"); + return now; + } + return lastLoggedTime; + } + ); + } +} diff --git a/src/Task.Monitor.System/PInvokeErrorHelpers.cs b/src/Task.Monitor.System/PInvokeErrorHelpers.cs deleted file mode 100644 index e7fdebb..0000000 --- a/src/Task.Monitor.System/PInvokeErrorHelpers.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Task.Monitor.System; - -public static class PInvokeErrorHelpers -{ - public static void AssertOnLastError(string methodName) - { -#if DEBUG - int error = Marshal.GetLastPInvokeError(); - Debug.Assert(error == 0, $"Failed with {GetFormattedErrorMesage()}"); -#endif - } - - public static string GetFormattedErrorMesage() - { - int error = Marshal.GetLastPInvokeError(); - string message = Marshal.GetPInvokeErrorMessage(error); - return $"PInvoke error ({error}): {message}"; - } -} diff --git a/src/Task.Monitor.System/Process/GpuService.Windows.cs b/src/Task.Monitor.System/Process/GpuService.Windows.cs index 98736f9..8b49a98 100644 --- a/src/Task.Monitor.System/Process/GpuService.Windows.cs +++ b/src/Task.Monitor.System/Process/GpuService.Windows.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.Runtime.InteropServices; +using Task.Monitor.Cli.Utils; using Task.Monitor.Interop.Win32; namespace Task.Monitor.System.Process; @@ -16,29 +17,60 @@ public static partial class GpuService private static Dictionary GetProcessStatsInternal() { - if (Pdh.PdhOpenQuery(null, IntPtr.Zero, out IntPtr hQuery) != Pdh.ERROR_SUCCESS) { - Trace.WriteLine($"Failed PdhOpenQuery in {nameof(GpuService)}."); + uint pdhResult = 0; + + if ((pdhResult = Pdh.PdhOpenQuery( + null, + IntPtr.Zero, + out IntPtr hQuery)) != Pdh.ERROR_SUCCESS) { + + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + nameof(Pdh.PdhOpenQuery), + $"Failed {nameof(GetProcessStatsInternal)}", + pdhResult); + return new Dictionary(cumulativeEngineValues); } - Pdh.PdhAddEnglishCounter( - hQuery, - GpuEngineCounterPath, - IntPtr.Zero, - out IntPtr hCounter); - - Pdh.PdhCollectQueryData(hQuery); + if ((pdhResult = Pdh.PdhAddEnglishCounter( + hQuery, + GpuEngineCounterPath, + IntPtr.Zero, + out IntPtr hCounter)) != Pdh.ERROR_SUCCESS) { + + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + GpuEngineCounterPath, + $"Failed {nameof(Pdh.PdhAddEnglishCounter)}", + pdhResult); + + Pdh.PdhCloseQuery(hQuery); + return new Dictionary(cumulativeEngineValues); + } + + if ((pdhResult = Pdh.PdhCollectQueryData(hQuery)) != Pdh.ERROR_SUCCESS) { + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + nameof(Pdh.PdhCollectQueryData), + $"Failed {nameof(GetProcessStatsInternal)}", + pdhResult); + + Pdh.PdhCloseQuery(hQuery); + return new Dictionary(cumulativeEngineValues); + } uint bufferSize = 0; uint itemCount = 0; - Pdh.PdhGetRawCounterArray( + _ = Pdh.PdhGetRawCounterArray( hCounter, ref bufferSize, ref itemCount, IntPtr.Zero); if (bufferSize <= 0) { + TraceEx.WriteLineOnce( + $"{nameof(Pdh.PdhGetRawCounterArray)} {hCounter}", + $"{nameof(Pdh.PdhGetRawCounterArray)} failed to calculate {nameof(bufferSize)} "); + Pdh.PdhCloseQuery(hQuery); return new Dictionary(cumulativeEngineValues); } @@ -88,6 +120,12 @@ private static Dictionary GetProcessStatsInternal() cumulativeEngineValues[pid] = cumulativeEngineValues.GetValueOrDefault(pid, 0) + maxDelta; } } + else { + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + $"{nameof(Pdh.PdhGetRawCounterArray)} {hCounter}", + $"{nameof(Pdh.PdhGetRawCounterArray)} failed to allocate {nameof(buffer)}", + pdhResult); + } Marshal.FreeHGlobal(buffer); Pdh.PdhCloseQuery(hQuery); diff --git a/src/Task.Monitor.System/Process/ModuleService.cs b/src/Task.Monitor.System/Process/ModuleService.cs index 1a5bf62..1147f5d 100644 --- a/src/Task.Monitor.System/Process/ModuleService.cs +++ b/src/Task.Monitor.System/Process/ModuleService.cs @@ -8,7 +8,6 @@ public virtual List GetModules(int pid) { if (!ProcessUtils.TryGetProcessByPid(pid, out SysDiag::Process? process) || process == null) { - SysDiag::Trace.WriteLine($"Failed TryGetProcessByPid for Pid {pid} in {nameof(ModuleService)}."); return []; } diff --git a/src/Task.Monitor.System/Process/ProcessService.Windows.cs b/src/Task.Monitor.System/Process/ProcessService.Windows.cs index 4141398..94e4252 100644 --- a/src/Task.Monitor.System/Process/ProcessService.Windows.cs +++ b/src/Task.Monitor.System/Process/ProcessService.Windows.cs @@ -25,6 +25,10 @@ public sealed partial class ProcessService entry.th32ProcessID); if (hProcess == IntPtr.Zero) { + PInvokeErrorHelpers.TraceOnceOnLastError( + $"{nameof(Kernel32.OpenProcess)}_{entry.th32ProcessID}", + $"Failed to open process for pid {entry.th32ProcessID}"); + return null; } @@ -103,6 +107,7 @@ private static string GetProcessCommandLine(int pid, in string defaultValue) IntPtr hSnapshot = Kernel32.CreateToolhelp32Snapshot(Kernel32.TH32CS_SNAPPROCESS, 0); if (hSnapshot == IntPtr.Zero) { + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.CreateToolhelp32Snapshot)); return null; } @@ -111,6 +116,7 @@ private static string GetProcessCommandLine(int pid, in string defaultValue) }; if (!Kernel32.Process32FirstW(hSnapshot, ref entry)) { + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.Process32FirstW)); return null; } @@ -141,6 +147,7 @@ private IEnumerable GetProcessInfosInternal() IntPtr hSnapshot = Kernel32.CreateToolhelp32Snapshot(Kernel32.TH32CS_SNAPPROCESS, 0); if (hSnapshot == IntPtr.Zero) { + PInvokeErrorHelpers.TraceOnLastError(nameof(Kernel32.CreateToolhelp32Snapshot)); yield break; } @@ -149,6 +156,7 @@ private IEnumerable GetProcessInfosInternal() }; if (!Kernel32.Process32FirstW(hSnapshot, ref entry)) { + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.Process32FirstW)); yield break; } @@ -176,7 +184,7 @@ private static void GetProcessIoOperations( writeBytes = 0; if (!WinNt.GetProcessIoCounters(hProcess, out WinNt.IO_COUNTERS counters)) { - PInvokeErrorHelpers.AssertOnLastError(nameof(WinNt.GetProcessIoCounters)); + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(WinNt.GetProcessIoCounters)); return; } @@ -186,14 +194,14 @@ private static void GetProcessIoOperations( private void GetProcessMemCounters(IntPtr hProcess, ref PsApi.PROCESS_MEMORY_COUNTERS counters) { - counters.cb = (uint)Marshal.SizeOf(); + counters.cb = (uint)Marshal.SizeOf(); if (!PsApi.GetProcessMemoryInfo( hProcess, ref counters, counters.cb)) { - PInvokeErrorHelpers.AssertOnLastError(nameof(PsApi.GetProcessMemoryInfo)); + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(PsApi.GetProcessMemoryInfo)); } } @@ -211,6 +219,7 @@ private void GetProcessorTimes( out MinWinBase.FILETIME kernel, out MinWinBase.FILETIME user)) { + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.GetProcessTimes)); return; } @@ -229,6 +238,7 @@ private string GetProcessPath(IntPtr hProcess, uint flags = Kernel32.PROCESS_NAM sb, ref size)) { + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(Kernel32.QueryFullProcessImageNameW)); return string.Empty; } @@ -287,14 +297,17 @@ private static string GetProcessUserName(SafeProcessHandle processHandle) private static SecurityIdentifier? GetProcessSecurityIdentifier(SafeProcessHandle processHandle) { - if (ProcessThreadsApi.OpenProcessToken( + if (!ProcessThreadsApi.OpenProcessToken( processHandle, 0x8u, out SafeProcessHandle tokenHandle)) { - if (GetProcessTokenSid(tokenHandle, out SecurityIdentifier sid)) { - return sid; - } + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(ProcessThreadsApi.OpenProcessToken)); + return null; + } + + if (GetProcessTokenSid(tokenHandle, out SecurityIdentifier sid)) { + return sid; } return null; @@ -328,6 +341,9 @@ private static unsafe bool GetProcessTokenSid(SafeProcessHandle processHandle, o sid = new SecurityIdentifier(new IntPtr(sidPtr)); } } + else { + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(GetProcessTokenSid)); + } return result; } diff --git a/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs b/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs index 4cc5ae8..735e839 100644 --- a/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs +++ b/src/Task.Monitor.System/Process/ServiceUtils.Windows.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using System.ServiceProcess; using Microsoft.Win32; +using Task.Monitor.Cli.Utils; using Task.Monitor.Interop.Win32; namespace Task.Monitor.System.Process; @@ -22,7 +23,7 @@ private static void BuildServiceMap() IntPtr hSCM = WinService.OpenSCManager(null!, null!, WinService.SC_MANAGER_CONNECT); if (hSCM == IntPtr.Zero) { - Trace.WriteLine($"Failed to open SCM Manager: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(WinService.SC_MANAGER_CONNECT)); return; } @@ -37,6 +38,7 @@ private static void BuildServiceMap() WinService.SERVICE_QUERY_STATUS); if (hService == IntPtr.Zero) { + PInvokeErrorHelpers.TraceOnceOnLastError($"{nameof(WinService.OpenService)} {service.ServiceName}"); continue; } @@ -70,8 +72,13 @@ public static bool GetService(int pid, out ServiceInfo? service) public static string? GetServiceImagePath(string serviceName) { const string RegPath = @"SYSTEM\CurrentControlSet\Services\"; - - using RegistryKey? key = Registry.LocalMachine.OpenSubKey(RegPath + serviceName); + string subKey = $"{RegPath}{serviceName}"; + using RegistryKey? key = Registry.LocalMachine.OpenSubKey(subKey); + + if (key == null) { + TraceEx.WriteLineOnce(subKey, "Failed to open registry key"); + } + return key?.GetValue("ImagePath")?.ToString() ?? null; } @@ -87,7 +94,7 @@ private static int GetServiceProcessId(IntPtr hService) (uint)Marshal.SizeOf(), out _)) { - Trace.WriteLine($"GetServiceProcessId QueryServiceStatusEx: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnceOnLastError($"{nameof(WinService.QueryServiceStatusEx)} {hService}"); return 0; } @@ -112,7 +119,10 @@ internal static ServiceInfo[] GetServices() IntPtr hSCM = WinService.OpenSCManager(null!, null!, WinService.SC_MANAGER_ENUMERATE_SERVICE); if (hSCM == IntPtr.Zero) { - Trace.WriteLine($"Failed to open SCM Manager: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnceOnLastError( + nameof(WinService.OpenSCManager), + $"Failed GetServices {nameof(WinService.SC_MANAGER_ENUMERATE_SERVICE)}"); + return services; } @@ -135,7 +145,10 @@ internal static ServiceInfo[] GetServices() null!); if (bytesNeeded == 0) { - Trace.WriteLine($"EnumServicesStatusEx bytesNeeded returned 0: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnceOnLastError( + nameof(WinService.EnumServicesStatusEx), + $"{nameof(WinService.EnumServicesStatusEx)} {nameof(bytesNeeded)} returned 0"); + WinService.CloseServiceHandle(hSCM); return services; } @@ -156,7 +169,9 @@ internal static ServiceInfo[] GetServices() null!); if (!result) { - Trace.WriteLine($"Failed to EnumServicesStatusEx: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnceOnLastError( + nameof(WinService.EnumServicesStatusEx), + $"{nameof(WinService.EnumServicesStatusEx)} failed to allocate {nameof(buffer)}"); if (buffer != IntPtr.Zero) { Marshal.FreeHGlobal(buffer); diff --git a/src/Task.Monitor.System/SystemInfo.Windows.cs b/src/Task.Monitor.System/SystemInfo.Windows.cs index 090bd6f..4c31e1d 100644 --- a/src/Task.Monitor.System/SystemInfo.Windows.cs +++ b/src/Task.Monitor.System/SystemInfo.Windows.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Principal; +using Task.Monitor.Cli.Utils; using Task.Monitor.Interop.Win32; #if __WIN32__ @@ -31,9 +32,9 @@ private static bool GetCpuInfoInternal(ref SystemStatistics systemStatistics) systemStatistics.CpuName = string.Empty; using RegistryKey? key = Registry.LocalMachine.OpenSubKey(RegPath); - Debug.Assert(key != null, $"Failed OpenSubKey() {RegPath}"); if (key == null) { + TraceEx.WriteLineOnce(RegPath, "Failed GetCpuInfoInternal OpenSubKey"); return false; } @@ -41,6 +42,7 @@ private static bool GetCpuInfoInternal(ref SystemStatistics systemStatistics) object? processorName = key.GetValue(RegKeyProcessorName); if (processorName == null) { + TraceEx.WriteLineOnce(RegKeyProcessorName, "Failed GetCpuInfoInternal GetValue"); return false; } @@ -50,10 +52,12 @@ private static bool GetCpuInfoInternal(ref SystemStatistics systemStatistics) object? frequency = key.GetValue(RegKeyFrequencyMhz); if (frequency == null) { + TraceEx.WriteLineOnce(RegKeyFrequencyMhz, "Failed GetCpuInfoInternal GetValue"); return false; } if (!int.TryParse(frequency.ToString() ?? "0", out int frequencyInt32)) { + TraceEx.WriteLineOnce($"FRQ{frequency}", $"Failed GetCpuInfoInternal TryParse frequency"); return false; } @@ -71,7 +75,9 @@ private static unsafe bool GetCpuTimesInternal(ref SystemTimes systemTimes) &lpIdleFileTime, &lpKernelFileTime, &lpUserFileTime)) { + PInvokeErrorHelpers.AssertOnLastError(nameof(ProcessThreadsApi.GetSystemTimes)); + PInvokeErrorHelpers.TraceOnceOnLastError(nameof(ProcessThreadsApi.GetSystemTimes)); return false; } @@ -118,6 +124,7 @@ private static bool GetGpuMemoryInternalTotal(ref SystemStatistics systemStatist using RegistryKey? key = Registry.LocalMachine.OpenSubKey(RegPath); if (key == null) { + TraceEx.WriteLineOnce(RegPath, $"Failed GetGpuMemoryInternalTotal OpenSubKey"); return false; } @@ -128,10 +135,13 @@ private static bool GetGpuMemoryInternalTotal(ref SystemStatistics systemStatist continue; } + TraceEx.WriteLineOnce($"{RegPath} {subKeyName}", $"Enumerating Gpu adapter {subKeyName}"); + using RegistryKey? subKey = key.OpenSubKey(subKeyName); object? memorySize = subKey?.GetValue(RegKeyMemorySize); if (memorySize == null) { + TraceEx.WriteLineOnce(RegKeyMemorySize, "Failed GetGpuMemoryInternalTotal GetValue"); continue; } @@ -157,22 +167,47 @@ private static bool GetGpuMemoryInternalUsed(ref SystemStatistics systemStatisti IntPtr hQuery; IntPtr hCounter; + uint pdhResult = 0; - if (Pdh.PdhOpenQuery( + if ((pdhResult = Pdh.PdhOpenQuery( null, IntPtr.Zero, - out hQuery) != Pdh.ERROR_SUCCESS) { + out hQuery)) != Pdh.ERROR_SUCCESS) { + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + nameof(Pdh.PdhOpenQuery), + $"Failed {nameof(GetGpuMemoryInternalUsed)}", + pdhResult); + + Pdh.PdhCloseQuery(hQuery); + return false; + } + + if ((pdhResult = Pdh.PdhAddEnglishCounter( + hQuery, + AdapterMemoryCounterPath, + IntPtr.Zero, + out hCounter)) != Pdh.ERROR_SUCCESS) { + + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + AdapterMemoryCounterPath, + $"Failed {nameof(Pdh.PdhAddEnglishCounter)}", + pdhResult); + + Pdh.PdhCloseQuery(hQuery); return false; } - Pdh.PdhAddEnglishCounter( - hQuery, - AdapterMemoryCounterPath, - IntPtr.Zero, - out hCounter); + if ((pdhResult = Pdh.PdhCollectQueryData(hQuery)) != Pdh.ERROR_SUCCESS) { + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + nameof(Pdh.PdhCollectQueryData), + $"Failed {nameof(GetGpuMemoryInternalUsed)}", + pdhResult); + + Pdh.PdhCloseQuery(hQuery); + return false; + } - Pdh.PdhCollectQueryData(hQuery); long usedDedicatedMemory = SumRawCounterArray(hCounter); systemStatistics.AvailableGpuMemory = systemStatistics.TotalGpuMemory - usedDedicatedMemory; @@ -193,28 +228,56 @@ private static bool GetNetworkStatsInternal(ref NetworkStatistics networkStatist IntPtr hQuery; IntPtr hCounterReceived; IntPtr hCounterSent; - - if (Pdh.PdhOpenQuery( + uint pdhResult = 0; + + if ((pdhResult = Pdh.PdhOpenQuery( null, IntPtr.Zero, - out hQuery) != Pdh.ERROR_SUCCESS) { + out hQuery)) != Pdh.ERROR_SUCCESS) { + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + nameof(Pdh.PdhOpenQuery), + $"Failed {nameof(GetNetworkStatsInternal)}", + pdhResult); + return false; } - Pdh.PdhAddEnglishCounter( - hQuery, - BytesReceivedPath, - IntPtr.Zero, - out hCounterReceived); - - Pdh.PdhAddEnglishCounter( - hQuery, - BytesSentPath, - IntPtr.Zero, - out hCounterSent); + if ((pdhResult = Pdh.PdhAddEnglishCounter( + hQuery, + BytesReceivedPath, + IntPtr.Zero, + out hCounterReceived)) != Pdh.ERROR_SUCCESS) { + + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + BytesReceivedPath, + $"Failed {nameof(Pdh.PdhAddEnglishCounter)}", + pdhResult); - Pdh.PdhCollectQueryData(hQuery); + Pdh.PdhCloseQuery(hQuery); + return false; + } + + if ((pdhResult = Pdh.PdhAddEnglishCounter( + hQuery, + BytesSentPath, + IntPtr.Zero, + out hCounterSent)) != Pdh.ERROR_SUCCESS) { + + PInvokeErrorHelpers.TraceOnPInvokeError(nameof(Pdh.PdhAddEnglishCounter), pdhResult); + Pdh.PdhCloseQuery(hQuery); + return false; + } + + if ((pdhResult = Pdh.PdhCollectQueryData(hQuery)) != Pdh.ERROR_SUCCESS) { + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + nameof(Pdh.PdhCollectQueryData), + $"Failed {nameof(GetNetworkStatsInternal)}", + pdhResult); + + Pdh.PdhCloseQuery(hQuery); + return false; + } long totalReceived = SumRawCounterArray(hCounterReceived); long totalSent = SumRawCounterArray(hCounterSent); @@ -272,6 +335,10 @@ private static unsafe bool GetSystemMemoryInternal(ref SystemStatistics systemSt if (!SysInfoApi.GlobalMemoryStatusEx(&memoryStatus)) { PInvokeErrorHelpers.AssertOnLastError(nameof(SysInfoApi.GlobalMemoryStatusEx)); + PInvokeErrorHelpers.TraceOnceOnLastError( + nameof(SysInfoApi.GlobalMemoryStatusEx), + $"Failed {nameof(GetSystemMemoryInternal)}"); + return false; } @@ -296,25 +363,36 @@ private static long SumRawCounterArray(IntPtr hCounter) { uint bufferSize = 0; uint itemCount = 0; - - Pdh.PdhGetRawCounterArray( - hCounter, - ref bufferSize, - ref itemCount, + uint pdhResult = 0; + + _ = Pdh.PdhGetRawCounterArray( + hCounter, + ref bufferSize, + ref itemCount, IntPtr.Zero); if (bufferSize <= 0) { + TraceEx.WriteLineOnce( + $"{nameof(Pdh.PdhGetRawCounterArray)} {hCounter}", + $"{nameof(Pdh.PdhGetRawCounterArray)} failed to calculate {nameof(bufferSize)} "); + return -1; } IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize); - if (Pdh.PdhGetRawCounterArray( - hCounter, - ref bufferSize, - ref itemCount, - buffer) != Pdh.ERROR_SUCCESS) { + if ((pdhResult = Pdh.PdhGetRawCounterArray( + hCounter, + ref bufferSize, + ref itemCount, + buffer)) != Pdh.ERROR_SUCCESS) { + + PInvokeErrorHelpers.TraceOnceOnPInvokeError( + $"{nameof(Pdh.PdhGetRawCounterArray)} {hCounter}", + $"{nameof(Pdh.PdhGetRawCounterArray)} failed to allocate {nameof(buffer)}", + pdhResult); + Marshal.FreeHGlobal(buffer); return 0; } diff --git a/src/Task.Monitor.System/SystemTerminal.Windows.cs b/src/Task.Monitor.System/SystemTerminal.Windows.cs index 96f4b31..7a71957 100644 --- a/src/Task.Monitor.System/SystemTerminal.Windows.cs +++ b/src/Task.Monitor.System/SystemTerminal.Windows.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.Runtime.InteropServices; +using Task.Monitor.Cli.Utils; using Task.Monitor.Interop.Win32; namespace Task.Monitor.System; @@ -31,13 +32,13 @@ private void EnableAnsiTerminalCodesInternal() if (consoleHandle == IntPtr.Zero || consoleHandle == new IntPtr(-1)) { PInvokeErrorHelpers.AssertOnLastError(nameof(ProcessEnv.GetStdHandle)); - Trace.WriteLine($"EnableAnsiTerminalCodesInternal GetStdHandle: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnLastError(nameof(ProcessEnv.GetStdHandle)); return; } if (!ConsoleApi.GetConsoleMode(consoleHandle, out uint originalMode)) { PInvokeErrorHelpers.AssertOnLastError(nameof(ConsoleApi.GetConsoleMode)); - Trace.WriteLine($"EnableAnsiTerminalCodesInternal GetConsoleMode: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnLastError(nameof(ConsoleApi.GetConsoleMode)); return; } @@ -45,7 +46,7 @@ private void EnableAnsiTerminalCodesInternal() if (!ConsoleApi.SetConsoleMode(consoleHandle, newMode)) { PInvokeErrorHelpers.AssertOnLastError(nameof(ConsoleApi.SetConsoleMode)); - Trace.WriteLine($"EnableAnsiTerminalCodesInternal SetConsoleMode: {PInvokeErrorHelpers.GetFormattedErrorMesage()}"); + PInvokeErrorHelpers.TraceOnLastError(nameof(ConsoleApi.SetConsoleMode)); } } #endif diff --git a/src/taskmon/TaskMonApp.cs b/src/taskmon/TaskMonApp.cs index 542c573..a569208 100644 --- a/src/taskmon/TaskMonApp.cs +++ b/src/taskmon/TaskMonApp.cs @@ -19,7 +19,7 @@ private void InitialiseProcess() FormattedTextWriterTraceListener.Initialise( logPath, maxBytes: 2 * 1024 * 1024, - maxFiles: 32, + maxFiles: 16, Constants.AppName); } }