Skip to content

Commit 0329b73

Browse files
committed
metrics-collector fixes
1 parent 3695e63 commit 0329b73

File tree

3 files changed

+132
-67
lines changed

3 files changed

+132
-67
lines changed

src/main.cpp

+68-6
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,90 @@
1-
#include <iostream>
1+
#include "metrics-collector.hpp"
22
#include "file.hpp"
33

4+
#include <iostream>
5+
#include <cstring>
6+
#include <thread>
7+
#include <signal.h>
8+
49
void print_usage(const std::string& program_name) {
5-
std::cerr << "Usage: " << program_name
10+
std::cerr << "Usage: " << program_name << " hash"
611
<< " PATH ALGORITHM" << std::endl
712
<< "Supported algorithms are: "
813
<< "md2, md5, sha, "
914
<< "sha1, sha224, sha256, sha384, sha512, "
1015
<< "mdc2 and ripemd160" << std::endl;
1116
}
1217

13-
int main(int argc, char* argv[]) {
14-
if (argc < 3) {
18+
int hash_main(int argc, char* argv[]) {
19+
if (argc < 4) {
1520
print_usage(argv[0]);
1621
return 1;
1722
}
1823

1924
try {
20-
std::string hash = File::calculate_hash(argv[1], argv[2]);
25+
std::string hash = File::calculate_hash(argv[2], argv[3]);
2126
std::cout << "Digest is: " << hash << std::endl;
2227
} catch (const std::exception& e) {
2328
std::cerr << "Error: " << e.what() << std::endl;
2429
return 1;
2530
}
2631

2732
return 0;
28-
}
33+
}
34+
35+
36+
bool is_running = true;
37+
38+
void signal_handler(int signo) {
39+
std::cerr << "[INFO] Received " << strsignal(signo) << " signal. Stopping" << std::endl;
40+
is_running = false;
41+
}
42+
43+
int metrics_main(int argc, char *argv[]) {
44+
signal(SIGTERM, signal_handler);
45+
signal(SIGINT, signal_handler);
46+
47+
if (argc != 5) {
48+
std::cerr << "usage: worker" << argv[0] << " metrics"
49+
<< " ADDRESS PORT WORKER_NAME" << std::endl;
50+
return 1;
51+
}
52+
53+
MetricsCollector metrics_collector(argv[2], argv[3], argv[4]);
54+
55+
srand(time(NULL));
56+
while (is_running) {
57+
std::this_thread::sleep_for(std::chrono::seconds(rand() % 5 + 1));
58+
std::cerr << "[INFO] Doing task" << std::endl;
59+
metrics_collector.StartTask();
60+
61+
// some "work" that requires memory
62+
void *data = malloc(rand() % (1024 * 1024 * 50)); // 0 - 50 megabytes
63+
for (volatile int i = 0; i < 1000000000 + rand() % 10000000000; i++) {}
64+
free(data);
65+
66+
metrics_collector.StopTask();
67+
std::cerr << "[INFO] Task done" << std::endl;
68+
}
69+
70+
return 0;
71+
}
72+
73+
int main(int argc, char *argv[])
74+
{
75+
static const char usage[] = "Specify hash/metrics";
76+
77+
if (argc < 2) {
78+
std::cerr << usage << std::endl;
79+
return 1;
80+
}
81+
82+
if (strcmp(argv[1], "hash") == 0) {
83+
return hash_main(argc, argv);
84+
} else if (strcmp(argv[1], "metrics") == 0) {
85+
return metrics_main(argc, argv);
86+
}
87+
88+
std::cerr << usage << std::endl;
89+
return 1;
90+
}

src/metrics-collector.cpp

+44-48
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@
44
#include <chrono>
55
#include <unistd.h>
66
#include <fstream>
7+
#include <iostream>
8+
9+
namespace {
10+
double GetMemoryUsed()
11+
{
12+
std::ifstream file("/proc/self/statm");
13+
if (!file.is_open()) {
14+
return 0;
15+
}
16+
17+
long mem_pages = 0;
18+
file >> mem_pages;
19+
file.close();
20+
return mem_pages * (double)getpagesize();
21+
}
22+
}
723

824
MetricsCollector::MetricsCollector(const char *gateway_address, const char *gateway_port, const char *worker_name)
925
: gateway(gateway_address, gateway_port, worker_name),
@@ -31,8 +47,8 @@ MetricsCollector::MetricsCollector(const char *gateway_address, const char *gate
3147
while (true) {
3248
CPUInfo cpu;
3349

34-
file >> cpu_name >> cpu.last_total_user >> cpu.last_total_user_low
35-
>> cpu.last_total_sys >> cpu.last_total_idle
50+
file >> cpu_name >> cpu.time.user >> cpu.time.user_low
51+
>> cpu.time.sys >> cpu.time.idle
3652
>> ign >> ign >> ign >> ign >> ign >> ign;
3753

3854
if (cpu_name.find("cpu") != 0)
@@ -48,30 +64,30 @@ MetricsCollector::MetricsCollector(const char *gateway_address, const char *gate
4864
task_processing_time_gauge = &task_processing_time_family.Add({});
4965

5066
gateway.RegisterCollectable(registry);
51-
52-
is_running = true;
53-
thread = std::thread(&MetricsCollector::mainLoop, this);
54-
67+
thread = std::thread(&MetricsCollector::MainLoop, this);
5568
is_task_running = false;
5669
}
5770

58-
void MetricsCollector::mainLoop()
71+
void MetricsCollector::MainLoop()
5972
{
6073
while (is_running) {
6174
std::this_thread::sleep_for(std::chrono::seconds(1));
6275

63-
getMemoryUsed();
64-
getCPUUsage();
76+
memory_used_gauge->Set(::GetMemoryUsed());
77+
GetCPUUsage();
6578

6679
if (is_task_running) {
67-
struct timespec time;
68-
clock_gettime(CLOCK_MONOTONIC, &time);
69-
task_processing_time_gauge->Set((time.tv_sec - task_start.tv_sec) + (time.tv_nsec - task_start.tv_nsec) * 1e-9);
80+
auto cur_time = std::chrono::high_resolution_clock::now();
81+
task_processing_time_gauge->Set(std::chrono::duration<double>(cur_time - task_start).count());
7082
}
71-
else
83+
else {
7284
task_processing_time_gauge->Set(0);
85+
}
7386

74-
gateway.PushAdd();
87+
int status = gateway.PushAdd();
88+
if (status != 200) {
89+
std::cerr << "[ERROR] Failed to push metrics. Status " << status << std::endl;
90+
}
7591
}
7692
}
7793

@@ -81,73 +97,53 @@ MetricsCollector::~MetricsCollector()
8197
thread.join();
8298
}
8399

84-
void MetricsCollector::getMemoryUsed()
85-
{
86-
std::ifstream file("/proc/self/statm");
87-
if (!file.is_open()) {
88-
memory_used_gauge->Set(0);
89-
return;
90-
}
91-
92-
long mem_pages = 0;
93-
file >> mem_pages;
94-
file.close();
95-
96-
memory_used_gauge->Set(mem_pages * (double)getpagesize());
97-
}
98-
99-
void MetricsCollector::getCPUUsage()
100+
void MetricsCollector::GetCPUUsage()
100101
{
101102
std::ifstream file("/proc/stat");
102-
uint64_t total_user, total_user_low, total_sys, total_idle, total;
103+
CPUInfo::Time cur_time;
103104
double percent;
104105

105106
std::string cpu_name;
106107
int ign;
107108

108109
while (true) {
109-
file >> cpu_name >> total_user >> total_user_low >> total_sys >> total_idle
110+
file >> cpu_name >> cur_time.user >> cur_time.user_low >> cur_time.sys >> cur_time.idle
110111
>> ign >> ign >> ign >> ign >> ign >> ign;
111112

112113
if (cpu_name.find("cpu") != 0)
113114
break;
114115

115116
CPUInfo &cpu = cpu_usage[cpu_name];
116-
if (total_user < cpu.last_total_user || total_user_low < cpu.last_total_user_low ||
117-
total_sys < cpu.last_total_sys || total_idle < cpu.last_total_idle) {
117+
if (cur_time.user < cpu.time.user || cur_time.user_low < cpu.time.user_low ||
118+
cur_time.sys < cpu.time.sys || cur_time.idle < cpu.time.idle) {
118119
// overflow detection
119120
percent = -1.0;
120121
}
121122
else {
122-
total = (total_user - cpu.last_total_user) + (total_user_low - cpu.last_total_user_low) +
123-
(total_sys - cpu.last_total_sys);
123+
uint64_t total = (cur_time.user - cpu.time.user) + (cur_time.user_low - cpu.time.user_low) +
124+
(cur_time.sys - cpu.time.sys);
124125

125126
percent = total;
126-
total += (total_idle - cpu.last_total_idle);
127-
percent /= total;
128-
percent *= 100;
127+
total += (cur_time.idle - cpu.time.idle);
128+
percent = (total == 0) ? -1.0 : (percent / total) * 100.0;
129129
}
130130

131-
cpu.last_total_user = total_user;
132-
cpu.last_total_user_low = total_user_low;
133-
cpu.last_total_sys = total_sys;
134-
cpu.last_total_idle = total_idle;
135-
131+
cpu.time = cur_time;
136132
cpu.gauge->Set(percent);
137133
}
138134

139135
file.close();
140136
}
141137

142-
void MetricsCollector::startTask()
138+
void MetricsCollector::StartTask()
143139
{
144140
is_task_running = true;
145-
clock_gettime(CLOCK_MONOTONIC, &task_start);
141+
task_start = std::chrono::high_resolution_clock::now();
146142
}
147143

148-
void MetricsCollector::stopTask()
144+
void MetricsCollector::StopTask()
149145
{
150146
is_task_running = false;
151147
task_processing_time_gauge->Set(0);
152148
gateway.PushAdd();
153-
}
149+
}

src/metrics-collector.hpp

+20-13
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,43 @@
11
#include <prometheus/gauge.h>
22
#include <prometheus/registry.h>
33
#include <prometheus/gateway.h>
4+
#include <chrono>
45

56
class MetricsCollector {
67
prometheus::Gateway gateway;
78
std::shared_ptr<prometheus::Registry> registry;
89

910
struct CPUInfo {
1011
prometheus::Gauge *gauge;
11-
uint64_t last_total_user;
12-
uint64_t last_total_user_low;
13-
uint64_t last_total_sys;
14-
uint64_t last_total_idle;
12+
13+
struct Time {
14+
uint64_t user;
15+
uint64_t user_low;
16+
uint64_t sys;
17+
uint64_t idle;
18+
};
19+
20+
Time time;
1521
};
1622

17-
prometheus::Gauge *memory_used_gauge;
1823
std::unordered_map<std::string, CPUInfo> cpu_usage;
24+
25+
prometheus::Gauge *memory_used_gauge;
1926
prometheus::Gauge *task_processing_time_gauge;
20-
bool is_running;
27+
28+
std::atomic<bool> is_running {true};
2129
std::thread thread;
2230

2331
bool is_task_running;
24-
struct timespec task_start;
32+
std::chrono::time_point<std::chrono::high_resolution_clock> task_start;
2533

26-
void getMemoryUsed();
27-
void getCPUUsage();
28-
void mainLoop();
34+
void GetCPUUsage();
35+
void MainLoop();
2936

3037
public:
3138
MetricsCollector(const char *gateway_address, const char *gateway_port, const char *worker_name);
3239
~MetricsCollector();
3340

34-
void startTask();
35-
void stopTask();
36-
};
41+
void StartTask();
42+
void StopTask();
43+
};

0 commit comments

Comments
 (0)