DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
SystemMetricsLinux.cpp
Go to the documentation of this file.
1#include "pch.h"
6#include <algorithm>
7#include <vector>
8#include <map>
9
10#if !defined(_WIN32)
11#include <fstream>
12#include <sstream>
13#include <dirent.h>
14#include <unistd.h>
15#include <sys/statvfs.h>
16#include <sys/types.h>
17#include <arpa/inet.h>
18
19namespace DotNetDupe {
20 namespace System {
21 namespace Diagnostics {
22
23 struct SystemMetricsLinuxHelper {
24 static int FindPid(const String& sProcessName) {
26 auto arrMatches = Process::GetProcessesByName(sProcessName);
27 if (arrMatches.GetLength() > 0) return arrMatches[0]->GetId();
28 return -1;
29 }
30
31 static MemoryInfo ReadMem(int iPid) {
33 MemoryInfo info;
34 if (iPid <= 0) return info;
35 std::ifstream f("/proc/" + std::to_string(iPid) + "/status");
36 std::string line; long long rss = 0, vm = 0;
37 while (f.is_open() && std::getline(f, line)) {
38 if (line.rfind("VmRSS:", 0) == 0) std::istringstream(line.substr(6)) >> rss;
39 else if (line.rfind("VmSize:", 0) == 0) std::istringstream(line.substr(7)) >> vm;
40 }
41 info.lPhysicalMemoryBytes = rss * 1024LL; info.lPrivateBytes = vm * 1024LL;
42 return info;
43 }
44
45 static DiskInfo ReadDisk(int iPid) {
47 DiskInfo info;
48 if (iPid <= 0) return info;
49 std::ifstream f("/proc/" + std::to_string(iPid) + "/io");
50 std::string line;
51 while (f.is_open() && std::getline(f, line)) {
52 if (line.rfind("read_bytes:", 0) == 0) std::istringstream(line.substr(11)) >> info.lDiskReadBytes;
53 else if (line.rfind("write_bytes:", 0) == 0) std::istringstream(line.substr(12)) >> info.lDiskWriteBytes;
54 }
55 return info;
56 }
57
58 static NetworkUsageInfo ReadNet(int iPid) {
60 NetworkUsageInfo info;
61 if (iPid <= 0) return info;
62 std::ifstream f("/proc/" + std::to_string(iPid) + "/net/dev");
63 std::string line; long long totalRx = 0, totalTx = 0; int cnt = 0;
64 while (f.is_open() && std::getline(f, line)) {
65 if (++cnt <= 2) continue;
66 auto pos = line.find(':');
67 if (pos != std::string::npos) {
68 std::istringstream iss(line.substr(pos + 1));
69 long long rx = 0, tx = 0, dummy = 0;
70 iss >> rx; for (int i = 0; i < 7; ++i) iss >> dummy; iss >> tx;
71 totalRx += rx; totalTx += tx;
72 }
73 }
74 info.lNetworkReadBytes = totalRx; info.lNetworkWriteBytes = totalTx;
75 return info;
76 }
77
78 static ProcessNetworkConnectionInfo ReadNetInfo(int iPid) {
80 ProcessNetworkConnectionInfo info;
81 if (iPid <= 0) return info;
82 std::ifstream f("/proc/net/tcp");
83 std::string line; int cnt = 0;
84 while (f.is_open() && std::getline(f, line)) {
85 if (cnt++ == 0) continue;
86 std::istringstream iss(line);
87 std::string sl, lAddr, rAddr, st;
88 if (iss >> sl >> lAddr >> rAddr >> st) {
89 auto c1 = lAddr.find(':'), c2 = rAddr.find(':');
90 if (c1 != std::string::npos && c2 != std::string::npos) {
91 int lp = std::stoi(lAddr.substr(c1 + 1), nullptr, 16);
92 int rp = std::stoi(rAddr.substr(c2 + 1), nullptr, 16);
93 NetworkConnectionInfo conn; conn.iLocalPort = lp; conn.iRemotePort = rp;
94 conn.sState = (st == "01") ? "ESTABLISHED" : "LISTEN";
95 info.lstConnections.Add(conn); info.lstOpenPorts.Add(lp);
96 if (st == "01") info.bHasEstablishedInboundConnection = true;
97 }
98 }
99 }
100 return info;
101 }
102
103 static MemoryInfo GetSysMem() {
105 MemoryInfo info;
106 std::ifstream f("/proc/meminfo");
107 std::string line; unsigned long long tot = 0, av = 0;
108 while (f.is_open() && std::getline(f, line)) {
109 if (line.rfind("MemTotal:", 0) == 0) std::istringstream(line.substr(9)) >> tot;
110 else if (line.rfind("MemAvailable:", 0) == 0) std::istringstream(line.substr(13)) >> av;
111 }
112 info.uMemoryTotalBytes = tot * 1024ULL;
113 info.uMemoryUsedBytes = (tot > av) ? (tot - av) * 1024ULL : 0ULL;
114 if (tot > 0) info.dMemoryUsagePercent = (static_cast<double>(info.uMemoryUsedBytes) / static_cast<double>(info.uMemoryTotalBytes)) * 100.0;
115 return info;
116 }
117
118 static double GetSysCpu() {
120 std::ifstream f("/proc/stat");
121 std::string line;
122 if (f.is_open() && std::getline(f, line) && line.rfind("cpu ", 0) == 0) {
123 std::istringstream iss(line.substr(4));
124 long long u, n, s, id, io, ir, so, st;
125 if (iss >> u >> n >> s >> id >> io >> ir >> so >> st) {
126 long long idle = id + io, nonIdle = u + n + s + ir + so + st, total = idle + nonIdle;
127 if (total > 0) return (static_cast<double>(nonIdle) / static_cast<double>(total)) * 100.0;
128 }
129 }
130 return 0.0;
131 }
132
133 static DiskInfo GetSysDisk() {
135 DiskInfo info; struct statvfs vfs;
136 if (statvfs("/", &vfs) == 0) {
137 info.lDiskReadBytes = static_cast<long long>(vfs.f_blocks * vfs.f_frsize);
138 info.lDiskWriteBytes = static_cast<long long>((vfs.f_blocks - vfs.f_bfree) * vfs.f_frsize);
139 }
140 return info;
141 }
142
143 static double GetSysNet() {
145 std::ifstream f("/proc/net/dev");
146 std::string line; long long total = 0; int cnt = 0;
147 while (f.is_open() && std::getline(f, line)) {
148 if (++cnt <= 2) continue;
149 auto pos = line.find(':');
150 if (pos != std::string::npos) {
151 std::istringstream iss(line.substr(pos + 1));
152 long long rx = 0, tx = 0, dummy = 0;
153 iss >> rx; for (int i = 0; i < 7; ++i) iss >> dummy; iss >> tx;
154 total += (rx + tx);
155 }
156 }
157 return static_cast<double>(total);
158 }
159
160 static String ReadCmdLine(int pid) {
162 if (pid <= 0) return String("");
163 std::ifstream f("/proc/" + std::to_string(pid) + "/cmdline", std::ios::binary);
164 std::string cmd; char ch;
165 while (f.is_open() && f.get(ch)) cmd += (ch == '\0') ? ' ' : ch;
166 return String(cmd.c_str());
167 }
168 };
169
170 int SystemMetrics::FindPidByName(const String& sProcessName) { return SystemMetricsLinuxHelper::FindPid(sProcessName); }
171 MemoryInfo SystemMetrics::ReadLinuxProcessMemory(int iPid) { return SystemMetricsLinuxHelper::ReadMem(iPid); }
172 DiskInfo SystemMetrics::ReadLinuxProcessDisk(int iPid) { return SystemMetricsLinuxHelper::ReadDisk(iPid); }
173 NetworkUsageInfo SystemMetrics::ReadLinuxProcessNetwork(int iPid) { return SystemMetricsLinuxHelper::ReadNet(iPid); }
174 ProcessNetworkConnectionInfo SystemMetrics::ReadLinuxProcessNetworkInfo(int iPid) { return SystemMetricsLinuxHelper::ReadNetInfo(iPid); }
175 Collections::Generic::List<int> SystemMetrics::ReadLinuxProcessPorts(int iPid) { return SystemMetricsLinuxHelper::ReadNetInfo(iPid).lstOpenPorts; }
176
177 MemoryInfo SystemMetrics::GetSystemMemoryUsage() { return SystemMetricsLinuxHelper::GetSysMem(); }
178 double SystemMetrics::GetSystemCpuUsage() { return SystemMetricsLinuxHelper::GetSysCpu(); }
179 DiskInfo SystemMetrics::GetSystemDiskUsage() { return SystemMetricsLinuxHelper::GetSysDisk(); }
180 double SystemMetrics::GetSystemNetworkUsage() { return SystemMetricsLinuxHelper::GetSysNet(); }
181
182 String SystemMetrics::GetProcessCommandLine(const String& sProcessName) { return SystemMetricsLinuxHelper::ReadCmdLine(FindPidByName(sProcessName)); }
183 MemoryInfo SystemMetrics::GetProcessMemoryUsage(const String& sProcessName) { return ReadLinuxProcessMemory(FindPidByName(sProcessName)); }
184 DiskInfo SystemMetrics::GetProcessDiskUsage(const String& sProcessName) { return ReadLinuxProcessDisk(FindPidByName(sProcessName)); }
185 NetworkUsageInfo SystemMetrics::GetProcessNetworkUsage(const String& sProcessName) { return ReadLinuxProcessNetwork(FindPidByName(sProcessName)); }
186 Collections::Generic::List<int> SystemMetrics::GetProcessNetworkPort(const String& sProcessName) { return ReadLinuxProcessPorts(FindPidByName(sProcessName)); }
187 Collections::Generic::List<int> SystemMetrics::GetProcessNetworkPort(int iProcessId) { return ReadLinuxProcessPorts(iProcessId); }
188 ProcessNetworkConnectionInfo SystemMetrics::GetProcessNetworkInfo(const String& sProcessName) { return ReadLinuxProcessNetworkInfo(FindPidByName(sProcessName)); }
189 ProcessNetworkConnectionInfo SystemMetrics::GetProcessNetworkInfo(int iProcessId) { return ReadLinuxProcessNetworkInfo(iProcessId); }
190
191 void SystemMetrics::EnrichProcessInfo(ProcessInfo& proc, bool bIncludeNetwork) {
193 if (proc.iProcessId <= 0) throw ArgumentException("Process ID must be greater than zero.");
194 proc.sCommandLine = GetProcessCommandLine(proc.sName);
195 proc.memory = ReadLinuxProcessMemory(proc.iProcessId);
196 proc.disk = ReadLinuxProcessDisk(proc.iProcessId);
197 proc.network = ReadLinuxProcessNetwork(proc.iProcessId);
198 if (bIncludeNetwork) {
199 auto netInfo = ReadLinuxProcessNetworkInfo(proc.iProcessId);
200 proc.lstOpenPorts = netInfo.lstOpenPorts;
201 proc.lstConnections = netInfo.lstConnections;
202 proc.bHasEstablishedConnection = netInfo.bHasEstablishedInboundConnection;
203 }
204 }
205
206 Collections::Generic::List<ServiceInfo> SystemMetrics::GetAllServices() {
207 return Collections::Generic::List<ServiceInfo>();
208 }
209
210 }
211 }
212}
213#endif
Defines the exception thrown when an invalid argument is provided to a method.
Provides access to local and remote processes and enables you to start and stop local system processe...
Utility routines for high-performance UTF-8, UTF-16, and wide-character string conversions.
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
static String GetProcessCommandLine(const String &sProcessName)
Queries the full command line used to launch a process by name.
static void EnrichProcessInfo(ProcessInfo &proc, bool bIncludeNetwork=true)
Enriches an existing ProcessInfo instance with CPU, memory, disk, and network telemetry.
static Collections::Generic::List< int > GetProcessNetworkPort(const String &sProcessName)
Retrieves open listening ports bound by a process by name.
static DiskInfo GetProcessDiskUsage(const String &sProcessName)
Queries disk transfer throughput for a process by name.
static MemoryInfo GetProcessMemoryUsage(const String &sProcessName)
Queries memory allocation details for a process by name.
static Collections::Generic::List< ServiceInfo > GetAllServices()
Enumerates all registered system background services and their current execution status.
static MemoryInfo GetSystemMemoryUsage()
Retrieves total and consumed physical memory metrics for the entire machine.
static double GetSystemCpuUsage()
Computes total system CPU usage percentage across all processors.
static double GetSystemNetworkUsage()
Computes total network traffic throughput across all operational interfaces in Megabits per second.
static NetworkUsageInfo GetProcessNetworkUsage(const String &sProcessName)
Queries network transfer metrics for a process by name.
static ProcessNetworkConnectionInfo GetProcessNetworkInfo(const String &sProcessName)
Queries detailed socket connections for a process by name.
static DiskInfo GetSystemDiskUsage()
Retrieves total disk read and write transfer rates for the system.
Rate or aggregate count of disk read and write operations.
Snapshot of physical and virtual memory utilization for the system or a specific process.
Network throughput counters for bytes transmitted and received.
Comprehensive telemetry snapshot for an operating system process.
Collection of open ports and active connections attributed to a specific process.