Metrics implementation, WIP
This commit is contained in:
@@ -35,15 +35,26 @@
|
||||
// histogram_family.create({{"endpoint", "/api"}}); // Bound to this thread
|
||||
// histogram.observe(0.25); // ONLY call from creating thread
|
||||
|
||||
#include "arena_allocator.hpp"
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "arena_allocator.hpp"
|
||||
|
||||
namespace metric {
|
||||
|
||||
// Forward declarations
|
||||
template <typename T> struct Family;
|
||||
|
||||
// Callback function type for dynamic metric values
|
||||
// Called during render() to get current metric value
|
||||
// THREAD SAFETY: May be called from arbitrary thread, but serialized by
|
||||
// render() mutex - no need to be thread-safe internally
|
||||
template <typename T> using MetricCallback = std::function<double()>;
|
||||
|
||||
// Counter: Monotonically increasing metric with single-writer semantics
|
||||
// Use for: request counts, error counts, bytes processed, etc.
|
||||
//
|
||||
@@ -115,13 +126,19 @@ template <class T> struct Family {
|
||||
// OK: Multiple calls with same labels return same instance (idempotent)
|
||||
T create(std::vector<std::pair<std::string, std::string>> labels);
|
||||
|
||||
// Register callback-based metric (Counter and Gauge only)
|
||||
// Validates that label set isn't already taken
|
||||
void
|
||||
register_callback(std::vector<std::pair<std::string, std::string>> labels,
|
||||
MetricCallback<T> callback);
|
||||
|
||||
private:
|
||||
Family();
|
||||
friend struct Metric;
|
||||
friend Family<Counter> create_counter(std::string, std::string);
|
||||
friend Family<Gauge> create_gauge(std::string, std::string);
|
||||
friend Family<Histogram> create_histogram(std::string, std::string,
|
||||
std::initializer_list<double>);
|
||||
std::span<const double>);
|
||||
|
||||
struct State;
|
||||
State *p;
|
||||
@@ -131,15 +148,33 @@ private:
|
||||
// IMPORTANT: name and help must point to static memory (string literals)
|
||||
|
||||
// Create counter family (monotonically increasing values)
|
||||
// ERROR: Aborts if family with same name is registered with different help
|
||||
// text.
|
||||
Family<Counter> create_counter(std::string name, std::string help);
|
||||
|
||||
// Create gauge family (can increase/decrease)
|
||||
// ERROR: Aborts if family with same name is registered with different help
|
||||
// text.
|
||||
Family<Gauge> create_gauge(std::string name, std::string help);
|
||||
|
||||
// Create histogram family with custom buckets
|
||||
// Buckets will be sorted, deduplicated, and +Inf will be added automatically
|
||||
// ERROR: Aborts if family with same name is registered with different help text
|
||||
// or buckets.
|
||||
Family<Histogram> create_histogram(std::string name, std::string help,
|
||||
std::initializer_list<double> buckets);
|
||||
std::span<const double> buckets);
|
||||
|
||||
// Helper functions for generating standard histogram buckets
|
||||
// Following Prometheus client library conventions
|
||||
|
||||
// Generate linear buckets: start, start+width, start+2*width, ...,
|
||||
// start+(count-1)*width Example: linear_buckets(0, 10, 5) = {0, 10, 20, 30, 40}
|
||||
std::vector<double> linear_buckets(double start, double width, int count);
|
||||
|
||||
// Generate exponential buckets: start, start*factor, start*factor^2, ...,
|
||||
// start*factor^(count-1) Example: exponential_buckets(1, 2, 5) = {1, 2, 4, 8,
|
||||
// 16}
|
||||
std::vector<double> exponential_buckets(double start, double factor, int count);
|
||||
|
||||
// Render all metrics in Prometheus text format
|
||||
// Returns chunks of Prometheus exposition format (includes # HELP and # TYPE
|
||||
@@ -155,33 +190,7 @@ bool is_valid_metric_name(const std::string &name);
|
||||
bool is_valid_label_key(const std::string &key);
|
||||
bool is_valid_label_value(const std::string &value);
|
||||
|
||||
// Callback function type for dynamic metric values
|
||||
// Called during render() to get current metric value
|
||||
// THREAD SAFETY: May be called from arbitrary thread, but serialized by
|
||||
// render() mutex
|
||||
// - no need to be thread-safe internally
|
||||
template <typename T> using MetricCallback = std::function<double()>;
|
||||
|
||||
// Register callback-based metric to Family
|
||||
// Validates that label set isn't already taken by either:
|
||||
// - A previous register_callback() call (callbacks must be unique)
|
||||
// - A create() call (static and callback metrics cannot coexist for same
|
||||
// labels)
|
||||
//
|
||||
// Similarly, create() will validate that label set isn't already registered as
|
||||
// callback Note: create() can be called multiple times with same labels
|
||||
// (returns same instance)
|
||||
template <>
|
||||
void Family<Counter>::register_callback(
|
||||
std::vector<std::pair<std::string, std::string>> labels,
|
||||
MetricCallback<Counter> callback);
|
||||
|
||||
template <>
|
||||
void Family<Gauge>::register_callback(
|
||||
std::vector<std::pair<std::string, std::string>> labels,
|
||||
MetricCallback<Gauge> callback);
|
||||
|
||||
// Note: Histograms do not support callbacks due to their multi-value nature
|
||||
// (buckets + sum + count). Use static histogram metrics only.
|
||||
|
||||
} // namespace metric
|
||||
} // namespace metric
|
||||
Reference in New Issue
Block a user