MicroLogger/include/metricsLogger.hh

64 lines
1.9 KiB
C++

#pragma once
#include <atomic>
#include <iostream>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <variant>
#include <vector>
namespace vptyp {
static constexpr std::string_view configErrorMsg =
"Bruh, incorrect configuration";
class MetricsLogger {
using map_type =
std::unordered_map<std::string, std::variant<int64_t, double>>;
public:
virtual ~MetricsLogger();
MetricsLogger();
explicit MetricsLogger(std::ostream& out);
MetricsLogger(MetricsLogger&) = delete;
MetricsLogger(MetricsLogger&&) = delete;
MetricsLogger& operator=(MetricsLogger&) = delete;
MetricsLogger& operator=(MetricsLogger&&) = delete;
/// @brief you should make logger configuration before logging
/// After logger will be ready for holding metrics.
/// @return success or not (already configured)
bool configure(const std::vector<std::string>& d);
template <typename Metric>
void add(const std::string& field, Metric metric)
requires(std::is_arithmetic_v<Metric>)
{
refs.fetch_add(1, std::memory_order_release);
map_type* locked = active.load(std::memory_order_acquire);
auto it = locked->find(field);
if (it == locked->end()) {
refs.fetch_sub(1, std::memory_order_release);
throw configErrorMsg; // additional 30ns on bench ?
}
it->second = metric;
refs.fetch_sub(1, std::memory_order_release);
}
bool isConfigured() { return configured == CONFIGURED; }
private:
// helper class for handling worker thread
class Worker;
friend Worker;
enum Configuration { NOT_CONFIGURED, CONFIG_IN_PROGRESS, CONFIGURED };
std::atomic<int> configured{NOT_CONFIGURED};
std::unique_ptr<Worker> worker;
std::unique_ptr<map_type> m1, m2;
std::atomic<map_type*> active;
std::atomic<size_t> refs{0}; // degradation on worker side (waiting for no
// one to be in refs section)
};
} // namespace vptyp