-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMetricsCollector.cpp
More file actions
123 lines (104 loc) · 3.25 KB
/
Copy pathMetricsCollector.cpp
File metadata and controls
123 lines (104 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <mutex>
#include <thread>
#include <atomic>
#include <memory>
#include <variant>
#include <queue>
#include <condition_variable>
// Типы значений метрик
using MetricValue = std::variant<int, double, std::string>;
// Класс для хранения метрики
class Metric {
public:
Metric(const std::string& name, const MetricValue& value)
: name(name), value(value) {}
std::string getName() const { return name; }
MetricValue getValue() const { return value; }
private:
std::string name;
MetricValue value;
};
// Класс для записи метрик в файл
class MetricWriter {
public:
MetricWriter(const std::string& filename) : filename(filename), running(true) {
writerThread = std::thread(&MetricWriter::writeThreadFunc, this);
}
~MetricWriter() {
running = false;
cv.notify_one();
if (writerThread.joinable()) {
writerThread.join();
}
flush();
}
void addMetric(const Metric& metric) {
std::lock_guard<std::mutex> lock(queueMutex);
metricsQueue.push(metric);
cv.notify_one();
}
void flush() {
std::ofstream file(filename, std::ios::app);
if (!file.is_open()) {
throw std::runtime_error("Cannot open metrics file: " + filename);
}
std::queue<Metric> tempQueue;
{
std::lock_guard<std::mutex> lock(queueMutex);
tempQueue.swap(metricsQueue);
}
while (!tempQueue.empty()) {
const auto& metric = tempQueue.front();
auto now = std::chrono::system_clock::now();
auto now_time = std::chrono::system_clock::to_time_t(now);
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) % 1000;
file << std::put_time(std::localtime(&now_time), "%Y-%m-%d %H:%M:%S");
file << "." << std::setfill('0') << std::setw(3) << now_ms.count();
file << " \"" << metric.getName() << "\" ";
std::visit([&file](auto&& arg) {
file << arg;
}, metric.getValue());
file << std::endl;
tempQueue.pop();
}
}
private:
void writeThreadFunc() {
while (running) {
std::unique_lock<std::mutex> lock(queueMutex);
cv.wait_for(lock, std::chrono::seconds(1), [this]() {
return !running || !metricsQueue.empty();
});
if (!metricsQueue.empty()) {
lock.unlock();
flush();
}
}
}
std::string filename;
std::queue<Metric> metricsQueue;
std::mutex queueMutex;
std::condition_variable cv;
std::atomic<bool> running;
std::thread writerThread;
};
// Класс для сбора метрик
class MetricsCollector {
public:
MetricsCollector(const std::string& filename) : writer(filename) {}
template<typename T>
void addMetric(const std::string& name, const T& value) {
writer.addMetric(Metric(name, value));
}
private:
MetricWriter writer;
};