More scaffolding
This commit is contained in:
110
src/metric.cpp
110
src/metric.cpp
@@ -1,9 +1,15 @@
|
||||
#include "metric.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace metric {
|
||||
struct MetricKey {
|
||||
std::string_view name;
|
||||
@@ -33,9 +39,24 @@ template <> struct hash<metric::MetricKey> {
|
||||
|
||||
namespace metric {
|
||||
|
||||
struct Counter::State {};
|
||||
struct Gauge::State {};
|
||||
struct Histogram::State {};
|
||||
using AtomicWord = std::atomic<uint64_t>;
|
||||
|
||||
struct Counter::State {
|
||||
AtomicWord value;
|
||||
};
|
||||
|
||||
struct Gauge::State {
|
||||
std::mutex mutex;
|
||||
double value;
|
||||
};
|
||||
|
||||
struct Histogram::State {
|
||||
std::vector<double> thresholds;
|
||||
std::vector<AtomicWord> counts;
|
||||
AtomicWord sum;
|
||||
AtomicWord observations;
|
||||
};
|
||||
|
||||
struct Metric {
|
||||
|
||||
static std::mutex mutex;
|
||||
@@ -47,6 +68,8 @@ struct Metric {
|
||||
|
||||
static std::unordered_map<std::thread::id, PerThreadState> perThreadState;
|
||||
|
||||
static std::unordered_map<MetricKey, Gauge::State> gauges;
|
||||
|
||||
struct ThreadInit {
|
||||
ThreadInit() {
|
||||
std::unique_lock<std::mutex> _{mutex};
|
||||
@@ -58,23 +81,88 @@ struct Metric {
|
||||
}
|
||||
};
|
||||
static thread_local ThreadInit thread_init;
|
||||
|
||||
static Counter
|
||||
create_counter(std::string_view name,
|
||||
std::vector<std::pair<std::string, std::string>> labels) {
|
||||
std::unique_lock<std::mutex> _{mutex};
|
||||
Counter result;
|
||||
result.p = &perThreadState[std::this_thread::get_id()]
|
||||
.counters[MetricKey{name, labels}];
|
||||
return result;
|
||||
}
|
||||
|
||||
static Gauge
|
||||
create_gauge(std::string_view name,
|
||||
std::vector<std::pair<std::string, std::string>> labels) {
|
||||
std::unique_lock<std::mutex> _{mutex};
|
||||
Gauge result;
|
||||
result.p = &gauges[MetricKey{name, labels}];
|
||||
return result;
|
||||
}
|
||||
|
||||
static Histogram
|
||||
create_histogram(std::string_view name,
|
||||
std::vector<std::pair<std::string, std::string>> labels) {
|
||||
std::unique_lock<std::mutex> _{mutex};
|
||||
Histogram result;
|
||||
result.p = &perThreadState[std::this_thread::get_id()]
|
||||
.histograms[MetricKey{name, labels}];
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
void Counter::inc(double x) {}
|
||||
void Gauge::inc(double x) {}
|
||||
void Gauge::dec(double x) {}
|
||||
void Gauge::set(double x) {}
|
||||
void Histogram::observe(double x) {}
|
||||
template <class U, class V> U reinterpret(V v) {
|
||||
static_assert(sizeof(U) == sizeof(V));
|
||||
static_assert(std::is_arithmetic_v<U>);
|
||||
static_assert(std::is_arithmetic_v<V>);
|
||||
U u;
|
||||
memcpy(&u, &v, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
void Counter::inc(double x) {
|
||||
assert(x >= 0);
|
||||
p->value.fetch_add(x, std::memory_order_relaxed);
|
||||
}
|
||||
void Gauge::inc(double x) {
|
||||
std::unique_lock<std::mutex> _{p->mutex};
|
||||
p->value += x;
|
||||
}
|
||||
void Gauge::dec(double x) {
|
||||
std::unique_lock<std::mutex> _{p->mutex};
|
||||
p->value -= x;
|
||||
}
|
||||
void Gauge::set(double x) {
|
||||
std::unique_lock<std::mutex> _{p->mutex};
|
||||
p->value = x;
|
||||
}
|
||||
void Histogram::observe(double x) {
|
||||
assert(p->thresholds.size() == p->counts.size());
|
||||
for (size_t i = 0; i < p->thresholds.size(); ++i) {
|
||||
p->counts[i].fetch_add(x <= p->thresholds[i], std::memory_order_relaxed);
|
||||
}
|
||||
auto sum = reinterpret<double>(p->sum.load(std::memory_order_relaxed));
|
||||
sum += x;
|
||||
p->sum.store(reinterpret<decltype(p->sum.load())>(sum));
|
||||
p->observations.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
template <>
|
||||
Counter Family<Counter>::create(
|
||||
std::initializer_list<std::pair<std::string_view, std::string_view>>) {}
|
||||
std::vector<std::pair<std::string, std::string>> labels) {
|
||||
return Metric::create_counter(name, labels);
|
||||
}
|
||||
template <>
|
||||
Gauge Family<Gauge>::create(
|
||||
std::initializer_list<std::pair<std::string_view, std::string_view>>) {}
|
||||
std::vector<std::pair<std::string, std::string>> labels) {
|
||||
return Metric::create_gauge(name, labels);
|
||||
}
|
||||
template <>
|
||||
Histogram Family<Histogram>::create(
|
||||
std::initializer_list<std::pair<std::string_view, std::string_view>>) {}
|
||||
std::vector<std::pair<std::string, std::string>> labels) {
|
||||
return Metric::create_histogram(name, labels);
|
||||
}
|
||||
|
||||
Family<Counter> create_counter(std::string_view name, std::string_view help) {}
|
||||
Family<Gauge> create_gauge(std::string_view name, std::string_view help) {}
|
||||
|
||||
@@ -45,8 +45,7 @@ private:
|
||||
template <class T> struct Family {
|
||||
static_assert(std::is_same_v<T, Counter> || std::is_same_v<T, Gauge> ||
|
||||
std::is_same_v<T, Histogram>);
|
||||
T create(
|
||||
std::initializer_list<std::pair<std::string_view, std::string_view>>);
|
||||
T create(std::vector<std::pair<std::string, std::string>>);
|
||||
|
||||
private:
|
||||
friend struct Metric;
|
||||
|
||||
Reference in New Issue
Block a user