Repo-Init
 
Loading...
Searching...
No Matches
ProcessMetrics.cpp
Go to the documentation of this file.
2
4
5#include <spdlog/spdlog.h>
6
7#include <dirent.h>
8#include <sys/resource.h>
9
10constexpr int SLEEP_INTERVAL_SEC = 1;
11
12size_t ProcessMetrics::countDirectoryEntries(const std::string &path)
13{
14 DIR *dir = nullptr;
15 size_t count = 0;
16 if ((dir = opendir(path.c_str())) != nullptr)
17 {
18 while (readdir(dir) != nullptr) // NOLINT(concurrency-mt-unsafe)
19 {
20 ++count;
21 }
22 closedir(dir);
23 }
24
25 return count;
26}
27
29{
30 struct rusage r_usage{};
31 getrusage(RUSAGE_SELF, &r_usage);
32 return r_usage.ru_maxrss; // NOLINT(cppcoreguidelines-pro-type-union-access)
33}
34
36{
37 struct rusage r_usage{};
38 getrusage(RUSAGE_SELF, &r_usage);
39 return r_usage.ru_majflt; // NOLINT(cppcoreguidelines-pro-type-union-access)
40}
41
43{
44 if (_oldCpuTime == 0)
45 {
46 _oldCpuTime = times(&_oldCpu);
47 if (_oldCpuTime == static_cast<clock_t>(-1))
48 {
49 _oldCpuTime = 0;
50 }
51 return 0.0;
52 }
53
54 struct tms nowCpu{};
55 auto nowCpuTime = times(&nowCpu);
56
57 const double usage = 100.0 * static_cast<double>(nowCpu.tms_utime - _oldCpu.tms_utime) /
58 static_cast<double>(nowCpuTime - _oldCpuTime);
59
60 std::swap(_oldCpu, nowCpu);
61 std::swap(_oldCpuTime, nowCpuTime);
62
63 return usage;
64}
65
66std::pair<size_t, size_t> ProcessMetrics::getDiskIO()
67{
68 std::string buffer;
69 findFromFile("/proc/self/io", "read_bytes", buffer);
70 size_t readBytes = buffer.empty() ? 0 : std::stoull(buffer);
71
72 buffer.clear();
73 findFromFile("/proc/self/io", "write_bytes", buffer);
74 size_t writeBytes = buffer.empty() ? 0 : std::stoull(buffer);
75
76 std::pair<size_t, size_t> result = {readBytes - _oldReadBytes, writeBytes - _oldWriteBytes};
77
78 std::swap(_oldReadBytes, readBytes);
79 std::swap(_oldWriteBytes, writeBytes);
80
81 return result;
82}
83
84size_t ProcessMetrics::getThreadCount() { return countDirectoryEntries("/proc/self/task"); }
85
87
89{
90 _pCurrentTime->SetToCurrentTime();
91 _pMemory->Set(static_cast<double>(getMemoryUsage()));
92 _pPageFaults->Set(static_cast<double>(getPageFaults()));
93 _pCpuUsage->Set(getCpuUsage());
94 auto [diskRead, diskWrite] = getDiskIO();
95 _pDiskRead->Set(static_cast<double>(diskRead));
96 _pDiskWrite->Set(static_cast<double>(diskWrite));
97 _pThreadCount->Set(static_cast<double>(getThreadCount()));
98 _pFileDescriptorCount->Set(static_cast<double>(getFileDescriptorCount()));
99}
100
102{
103 while (!_shouldStop._M_i)
104 {
105 try
106 {
107 update();
108 if (_checkFlag)
109 {
110 _checkFlag->test_and_set();
111 }
112 }
113 catch (const std::exception &e)
114 {
115 spdlog::error("Self monitoring failed: {}", e.what());
116 }
117
118 std::this_thread::sleep_for(std::chrono::seconds(SLEEP_INTERVAL_SEC));
119 }
120}
121
122ProcessMetrics::ProcessMetrics(std::shared_ptr<std::atomic_flag> checkFlag,
123 const std::shared_ptr<prometheus::Registry> &reg)
124 : _checkFlag(std::move(checkFlag))
125{
126 if (reg == nullptr)
127 {
128 throw std::invalid_argument("Registry is nullptr");
129 }
130
131 _pInitTime =
132 &prometheus::BuildGauge().Name("init_time").Help("Initialization time of application").Register(*reg).Add({});
134 &prometheus::BuildGauge().Name("current_time").Help("Current time of application").Register(*reg).Add({});
135 _pMemory =
136 &prometheus::BuildGauge().Name("memory_usage").Help("Memory usage of application").Register(*reg).Add({});
138 &prometheus::BuildGauge().Name("page_faults").Help("Page faults of application").Register(*reg).Add({});
139 _pCpuUsage = &prometheus::BuildGauge().Name("cpu_usage").Help("CPU usage of application").Register(*reg).Add({});
140 _pDiskRead = &prometheus::BuildGauge().Name("disk_read").Help("Disk read of application").Register(*reg).Add({});
141 _pDiskWrite = &prometheus::BuildGauge().Name("disk_write").Help("Disk write of application").Register(*reg).Add({});
143 &prometheus::BuildGauge().Name("thread_count").Help("Thread count of application").Register(*reg).Add({});
144 _pFileDescriptorCount = &prometheus::BuildGauge()
145 .Name("file_descriptor_count")
146 .Help("File descriptor count of application")
147 .Register(*reg)
148 .Add({});
149
150 _pInitTime->SetToCurrentTime();
151
152 _thread = std::make_unique<std::thread>(&ProcessMetrics::threadRunner, this);
153}
154
156{
157 _shouldStop.test_and_set();
158 if (_thread && _thread->joinable())
159 {
160 _thread->join();
161 }
162}
std::vector< std::string > findFromFile(const std::string &filePath, const std::string &pattern, std::string &lastWord)
constexpr int SLEEP_INTERVAL_SEC
prometheus::Gauge * _pMemory
Pointer to the memory usage gauge.
clock_t _oldCpuTime
Variable to store the old CPU time.
ProcessMetrics(std::shared_ptr< std::atomic_flag > checkFlag, const std::shared_ptr< prometheus::Registry > &reg)
prometheus::Gauge * _pInitTime
Pointer to initialization time gauge.
prometheus::Gauge * _pCurrentTime
Pointer to the current time gauge.
size_t _oldWriteBytes
Variable to store the old write bytes.
std::atomic_flag _shouldStop
Flag to stop monitoring.
prometheus::Gauge * _pCpuUsage
Pointer to the CPU usage gauge.
void threadRunner() noexcept
prometheus::Gauge * _pPageFaults
Pointer to the page faults gauge.
prometheus::Gauge * _pFileDescriptorCount
Pointer to the file descriptor count gauge.
std::pair< size_t, size_t > getDiskIO()
prometheus::Gauge * _pDiskRead
Pointer to the disk read gauge.
size_t _oldReadBytes
Variable to store the old read bytes.
prometheus::Gauge * _pThreadCount
Pointer to the thread count gauge.
static size_t countDirectoryEntries(const std::string &path)
static long int getMemoryUsage()
std::shared_ptr< std::atomic_flag > _checkFlag
Runtime check flag.
std::unique_ptr< std::thread > _thread
Thread handler.
static size_t getThreadCount()
static long int getPageFaults()
static size_t getFileDescriptorCount()
prometheus::Gauge * _pDiskWrite
Pointer to the disk write gauge.
Structure to store the old CPU times.