prom 0.1.0
Client-independent C++23 Prometheus/OpenMetrics metric abstraction
Loading...
Searching...
No Matches
scope.hpp
Go to the documentation of this file.
1#pragma once
2
28
29#include <prom/metric_base.hpp>
30#include <prom/registry.hpp>
31
32#include <cstdint>
33#include <memory>
34#include <mutex>
35#include <string>
36#include <string_view>
37#include <unordered_map>
38#include <utility>
39#include <vector>
40
41namespace prom {
42
46 std::string prefix{};
51 comms::DisplayInfo display{};
52};
53
57class Scope : public ScopeState, public std::enable_shared_from_this<Scope> {
58public:
59 explicit Scope(ScopeConfig config = {})
60 : deco_(std::move(config.prefix),
61 std::move(config.const_labels),
62 std::move(config.display),
63 detail::global_decoration()) {}
64
65 // --- metric factories (names get the prefix; labels/display get merged) --
66
67 [[nodiscard]] Counter counter(const CounterSpec& spec) {
68 return make<Counter>(MetricType::Counter,
69 spec.name,
70 spec.help,
71 spec.labels,
72 spec.unit,
73 spec.display,
74 {},
75 {},
76 {});
77 }
78 [[nodiscard]] Gauge gauge(const GaugeSpec& spec) {
79 return make<Gauge>(MetricType::Gauge,
80 spec.name,
81 spec.help,
82 spec.labels,
83 spec.unit,
84 spec.display,
85 {},
86 {},
87 {});
88 }
89 [[nodiscard]] Histogram histogram(const HistogramSpec& spec) {
90 std::vector<double> buckets = spec.buckets;
91 if (buckets.empty()) {
93 }
94 return make<Histogram>(MetricType::Histogram,
95 spec.name,
96 spec.help,
97 spec.labels,
98 spec.unit,
99 spec.display,
100 std::move(buckets),
101 {},
102 {});
103 }
104 [[nodiscard]] Summary summary(const SummarySpec& spec) {
105 std::vector<double> quantiles = spec.quantiles;
106 if (quantiles.empty()) {
108 }
109 return make<Summary>(MetricType::Summary,
110 spec.name,
111 spec.help,
112 spec.labels,
113 spec.unit,
114 spec.display,
115 {},
116 std::move(quantiles),
117 {});
118 }
119 [[nodiscard]] Untyped untyped(const UntypedSpec& spec) {
120 return make<Untyped>(MetricType::Untyped,
121 spec.name,
122 spec.help,
123 spec.labels,
124 spec.unit,
125 spec.display,
126 {},
127 {},
128 {});
129 }
130 [[nodiscard]] Info info(const InfoSpec& spec) {
131 return make<Info>(
132 MetricType::Info, spec.name, spec.help, spec.labels, Unit{}, spec.display, {}, {}, {});
133 }
134 [[nodiscard]] StateSet stateset(const StateSetSpec& spec) {
135 return make<StateSet>(MetricType::StateSet,
136 spec.name,
137 spec.help,
138 spec.labels,
139 Unit{},
140 spec.display,
141 {},
142 {},
143 spec.states);
144 }
145
146 // --- live configuration (mutations reconfigure existing scoped metrics) --
147
148 [[nodiscard]] std::string prefix() const {
149 return deco_.prefix();
150 }
151 void set_prefix(std::string prefix) {
152 deco_.set_prefix(std::move(prefix));
153 }
154
155 [[nodiscard]] Labels const_labels() const {
156 return deco_.const_labels();
157 }
159 deco_.set_const_labels(std::move(labels));
160 }
161 void add_const_label(std::string name, std::string value) {
162 deco_.add_const_label(std::move(name), std::move(value));
163 }
164
165 [[nodiscard]] comms::DisplayInfo display() const {
166 return deco_.display();
167 }
168 void set_display(comms::DisplayInfo display) {
169 deco_.set_display(std::move(display));
170 }
171
173 [[nodiscard]] ScopeConfig config() const {
174 return ScopeConfig{deco_.prefix(), deco_.const_labels(), deco_.display()};
175 }
178 deco_.configure(
179 std::move(config.prefix), std::move(config.const_labels), std::move(config.display));
180 }
181
182 // --- ScopeState (consumed by scoped metrics on each use) ----------------
183
184 [[nodiscard]] std::uint64_t version() const noexcept override {
185 return deco_.version();
186 }
187 [[nodiscard]] std::string full_name(const std::string_view base) const override {
188 return deco_.full_name(base);
189 }
190 [[nodiscard]] Labels effective_labels(const Labels& own) const override {
191 return deco_.effective_labels(own);
192 }
193 [[nodiscard]] comms::DisplayInfo
194 effective_display(const comms::DisplayInfo& own) const override {
195 return deco_.effective_display(own);
196 }
197 [[nodiscard]] bool decorates() const noexcept override {
198 return deco_.decorates();
199 }
200
201 // --- enumeration --------------------------------------------------------
202
207 [[nodiscard]] std::vector<MetricInfo> metrics() const {
208 // Collect live cores under the lock, then describe() *after* releasing
209 // it, keeping the lock hold short.
210 std::vector<std::shared_ptr<MetricCore>> live;
211 {
212 const std::scoped_lock lock(mutex_);
213 for (auto it = metrics_.begin(); it != metrics_.end();) {
214 if (auto core = it->lock()) {
215 live.push_back(std::move(core));
216 ++it;
217 } else {
218 it = metrics_.erase(it);
219 }
220 }
221 }
222 std::vector<MetricInfo> out;
223 out.reserve(live.size());
224 for (const auto& core : live) {
225 out.push_back(describe(*core));
226 }
227 return out;
228 }
229
230private:
231 template <class Metric>
232 [[nodiscard]] Metric make(const MetricType type,
233 const std::string_view name,
234 const std::string_view help,
235 const Labels& labels,
236 const Unit& unit,
237 const comms::DisplayInfo& display,
238 std::vector<double> buckets,
239 std::vector<double> quantiles,
240 std::vector<std::string> states) {
241 auto core = std::make_shared<MetricCore>();
242 core->type = type;
243 core->scope = shared_from_this(); // keeps this Scope alive
244 core->source = detail::global_adapter_cell(); // scopes follow the global adapter
245 core->base_name = std::string(name);
246 core->help = std::string(help);
247 core->base_labels = labels;
248 core->base_display = display;
249 core->buckets = std::move(buckets);
250 core->quantiles = std::move(quantiles);
251 core->states = std::move(states);
252 if (!unit.empty()) {
253 core->has_unit = true;
254 core->unit_from_dimval = unit.from_dimval;
255 core->unit_name = std::string(unit.name);
256 core->unit_kind = std::string(unit.kind);
257 core->unit_symbol = std::string(unit.symbol);
258 }
259 {
260 const std::scoped_lock lock(mutex_);
261 metrics_.push_back(core);
262 }
263 // name / const_labels / display stay empty here: bind() fills them from
264 // the live scope config on first use and on every reconfiguration.
265 return Metric{std::move(core)};
266 }
267
268 // The live prefix / labels / display this scope applies; shared engine with
269 // a decorating Registry. Carries its own mutex and version.
270 detail::DecorationState deco_;
271 // Guards `metrics_` only (the decoration locks itself).
272 mutable std::mutex mutex_;
273 // Metrics created through this scope, tracked at creation for enumeration.
274 mutable std::vector<std::weak_ptr<MetricCore>> metrics_;
275};
276
277namespace detail {
278
279inline std::mutex& scope_map_mutex() {
280 static std::mutex mutex;
281 return mutex;
282}
283
284inline std::unordered_map<std::string, std::shared_ptr<Scope>>& scope_map() {
285 static std::unordered_map<std::string, std::shared_ptr<Scope>> map;
286 return map;
287}
288
289} // namespace detail
290
294[[nodiscard]] inline std::shared_ptr<Scope> scope(const std::string_view name, ScopeConfig config) {
295 const std::scoped_lock lock(detail::scope_map_mutex());
296 auto& map = detail::scope_map();
297 const auto key = std::string(name);
298 if (const auto it = map.find(key); it != map.end()) {
299 return it->second;
300 }
301 auto created = std::make_shared<Scope>(std::move(config));
302 map.emplace(key, created);
303 return created;
304}
305
308[[nodiscard]] inline std::shared_ptr<Scope> scope(const std::string_view name) {
309 {
310 const std::scoped_lock lock(detail::scope_map_mutex());
311 auto& map = detail::scope_map();
312 if (const auto it = map.find(std::string(name)); it != map.end()) {
313 return it->second;
314 }
315 }
316 ScopeConfig config;
317 config.prefix = std::string(name) + "_";
318 return scope(name, std::move(config));
319}
320
322[[nodiscard]] inline std::shared_ptr<Scope> find_scope(const std::string_view name) {
323 const std::scoped_lock lock(detail::scope_map_mutex());
324 auto& map = detail::scope_map();
325 const auto it = map.find(std::string(name));
326 return it != map.end() ? it->second : nullptr;
327}
328
330[[nodiscard]] inline std::vector<std::shared_ptr<Scope>> scopes() {
331 const std::scoped_lock lock(detail::scope_map_mutex());
332 const auto& map = detail::scope_map();
333 std::vector<std::shared_ptr<Scope>> out;
334 out.reserve(map.size());
335 for (const auto& scope : map | std::views::values) {
336 out.push_back(scope);
337 }
338 return out;
339}
340
342[[nodiscard]] inline std::vector<std::string> scope_names() {
343 const std::scoped_lock lock(detail::scope_map_mutex());
344 const auto& map = detail::scope_map();
345 std::vector<std::string> out;
346 out.reserve(map.size());
347 for (const auto& name : map | std::views::keys) {
348 out.push_back(name);
349 }
350 return out;
351}
352
353// Registry::scope is declared in <prom/registry.hpp> and defined here so the
354// registry header need not see the full Scope definition.
355inline std::shared_ptr<Scope> Registry::scope(const std::string_view name) {
356 return ::prom::scope(name);
357}
358inline std::shared_ptr<Scope> Registry::scope(const std::string_view name, ScopeConfig config) {
359 return ::prom::scope(name, std::move(config));
360}
361
362} // namespace prom
::prometheus::Histogram::BucketBoundaries buckets
Definition adapter.cpp:65
std::string name
Metric name (state-set label key).
Definition adapter.cpp:68
::prometheus::Summary::Quantiles quantiles
Definition adapter.cpp:66
prom::MetricType type
Definition adapter.cpp:53
A counter.
Definition counter.hpp:28
A gauge.
Definition gauge.hpp:24
A histogram.
Definition histogram.hpp:32
An info metric: a single sample whose labels carry the payload (build version, commit,...
Definition info.hpp:25
An immutable-by-convention set of labels, kept sorted by name with duplicates collapsed last-wins.
Definition labels.hpp:55
RegistryConfig config() const
A snapshot of the whole decoration.
Definition registry.hpp:199
static std::shared_ptr< Scope > scope(std::string_view name)
Get-or-create the process-wide, named Scope (a per-library metrics instance with a shared prefix / de...
Definition scope.hpp:355
Read-only view a scoped metric uses to re-resolve its name, constant labels, and display metadata aga...
Definition metric_base.hpp:51
A named, reconfigurable metrics instance for one library.
Definition scope.hpp:57
ScopeConfig config() const
A snapshot of the whole configuration.
Definition scope.hpp:173
void set_prefix(std::string prefix)
Definition scope.hpp:151
Summary summary(const SummarySpec &spec)
Definition scope.hpp:104
Histogram histogram(const HistogramSpec &spec)
Definition scope.hpp:89
void add_const_label(std::string name, std::string value)
Definition scope.hpp:161
comms::DisplayInfo effective_display(const comms::DisplayInfo &own) const override
The effective display metadata for a metric's own display.
Definition scope.hpp:194
Labels const_labels() const
Definition scope.hpp:155
std::string full_name(const std::string_view base) const override
The effective metric name for a base (un-prefixed) name.
Definition scope.hpp:187
std::string prefix() const
Definition scope.hpp:148
std::vector< MetricInfo > metrics() const
Snapshots describing every (still-alive) metric created through this scope, including declared-but-un...
Definition scope.hpp:207
Scope(ScopeConfig config={})
Definition scope.hpp:59
bool decorates() const noexcept override
Whether this decoration actually changes anything (a non-empty prefix, constant labels,...
Definition scope.hpp:197
Counter counter(const CounterSpec &spec)
Definition scope.hpp:67
Gauge gauge(const GaugeSpec &spec)
Definition scope.hpp:78
StateSet stateset(const StateSetSpec &spec)
Definition scope.hpp:134
Labels effective_labels(const Labels &own) const override
The effective constant labels for a metric's own labels.
Definition scope.hpp:190
std::uint64_t version() const noexcept override
Monotonic counter, bumped on every configuration change.
Definition scope.hpp:184
Info info(const InfoSpec &spec)
Definition scope.hpp:130
void set_const_labels(Labels labels)
Definition scope.hpp:158
Untyped untyped(const UntypedSpec &spec)
Definition scope.hpp:119
void set_display(comms::DisplayInfo display)
Definition scope.hpp:168
void configure(ScopeConfig config)
Replace the whole configuration at once.
Definition scope.hpp:177
comms::DisplayInfo display() const
Definition scope.hpp:165
A state set: each declared state is a boolean, exposed as one series per state with value 0 or 1.
Definition stateset.hpp:27
A summary. Like a histogram but tracks quantiles instead of fixed buckets.
Definition summary.hpp:29
An untyped metric: just a settable value.
Definition untyped.hpp:24
comms::DisplayInfo display() const
Definition metric_base.hpp:194
Labels effective_labels(const Labels &own) const override
The effective constant labels for a metric's own labels.
Definition metric_base.hpp:138
Labels const_labels() const
Definition metric_base.hpp:176
std::uint64_t version() const noexcept override
Monotonic counter, bumped on every configuration change.
Definition metric_base.hpp:126
bool decorates() const noexcept override
Whether this decoration actually changes anything (a non-empty prefix, constant labels,...
Definition metric_base.hpp:155
void set_prefix(std::string prefix)
Definition metric_base.hpp:169
void set_const_labels(Labels labels)
Definition metric_base.hpp:180
comms::DisplayInfo effective_display(const comms::DisplayInfo &own) const override
The effective display metadata for a metric's own display.
Definition metric_base.hpp:147
void set_display(comms::DisplayInfo display)
Definition metric_base.hpp:198
void add_const_label(std::string name, std::string value)
Definition metric_base.hpp:187
void configure(std::string prefix, Labels const_labels, comms::DisplayInfo display)
Replace prefix, constant labels, and display in one shot (single version bump).
Definition metric_base.hpp:208
std::string prefix() const
Definition metric_base.hpp:165
std::string full_name(const std::string_view base) const override
The effective metric name for a base (un-prefixed) name.
Definition metric_base.hpp:130
MetricCore (the shared per-series state) and the CRTP MetricBase that gives every metric type value s...
Definition adapter.hpp:24
MetricType
The OpenMetrics / Prometheus metric kinds prom understands.
Definition unit.hpp:15
@ Summary
Quantile summary of observations.
@ Info
Static key/value metadata (exposed as *_info).
@ Untyped
A bare value with no semantic constraints.
@ Counter
Monotonically increasing cumulative value.
@ Gauge
Value that can go up and down.
@ StateSet
A set of mutually-related boolean states.
@ Histogram
Bucketed distribution of observations.
std::shared_ptr< Scope > scope(const std::string_view name, ScopeConfig config)
Get-or-create the process-wide scope named name, using config only if it does not yet exist (a later ...
Definition scope.hpp:294
constexpr std::array< double, 3 > default_summary_quantiles
Default quantiles applied when a summary spec leaves quantiles empty.
Definition summary.hpp:16
MetricInfo describe(const MetricCore &core)
Build a MetricInfo from a core, applying scope decoration for a scoped metric's effective name and co...
Definition registry.hpp:83
std::vector< std::shared_ptr< Scope > > scopes()
Every process-wide scope created so far (unordered).
Definition scope.hpp:330
std::vector< std::string > scope_names()
The names of every process-wide scope created so far (unordered).
Definition scope.hpp:342
constexpr std::array< double, 11 > default_histogram_buckets
The default bucket bounds applied when a histogram spec leaves buckets empty — the canonical Promethe...
Definition histogram.hpp:17
std::shared_ptr< Scope > find_scope(const std::string_view name)
Return the scope named name, or nullptr if none has been created.
Definition scope.hpp:322
Registry — the front door for creating registered metrics.
Declarative description of a counter, for Registry::counter / Counter::Counter.
Definition counter.hpp:17
std::string_view help
Definition counter.hpp:19
Labels labels
Definition counter.hpp:20
std::string_view name
Definition counter.hpp:18
comms::DisplayInfo display
Definition counter.hpp:22
Unit unit
Definition counter.hpp:21
Declarative description of a gauge.
Definition gauge.hpp:14
comms::DisplayInfo display
Definition gauge.hpp:19
Unit unit
Definition gauge.hpp:18
std::string_view name
Definition gauge.hpp:15
Labels labels
Definition gauge.hpp:17
std::string_view help
Definition gauge.hpp:16
Declarative description of a histogram.
Definition histogram.hpp:21
std::string_view help
Definition histogram.hpp:23
std::string_view name
Definition histogram.hpp:22
Labels labels
Definition histogram.hpp:24
std::vector< double > buckets
Upper bounds; default set used when empty.
Definition histogram.hpp:27
Unit unit
Definition histogram.hpp:25
comms::DisplayInfo display
Definition histogram.hpp:26
Declarative description of an info metric.
Definition info.hpp:16
comms::DisplayInfo display
Definition info.hpp:20
std::string_view help
Definition info.hpp:18
Labels labels
Constant labels carried alongside the info set.
Definition info.hpp:19
std::string_view name
Definition info.hpp:17
The configuration a Scope applies to every metric created through it.
Definition scope.hpp:44
comms::DisplayInfo display
Default display metadata; per-metric display fields override these.
Definition scope.hpp:51
Labels const_labels
Merged into every metric's constant labels; a metric's own labels win on a name collision.
Definition scope.hpp:49
std::string prefix
Prepended to every metric name (e.g. "foo_").
Definition scope.hpp:46
Declarative description of a state set.
Definition stateset.hpp:17
std::vector< std::string > states
Definition stateset.hpp:22
std::string_view name
Definition stateset.hpp:18
comms::DisplayInfo display
Definition stateset.hpp:21
std::string_view help
Definition stateset.hpp:19
Labels labels
Definition stateset.hpp:20
Declarative description of a summary.
Definition summary.hpp:19
Unit unit
Definition summary.hpp:23
std::string_view name
Definition summary.hpp:20
std::string_view help
Definition summary.hpp:21
std::vector< double > quantiles
Target quantiles; default set used when empty.
Definition summary.hpp:25
comms::DisplayInfo display
Definition summary.hpp:24
Labels labels
Definition summary.hpp:22
OpenMetrics unit suffix plus optional dimensional metadata.
Definition unit.hpp:53
std::string_view kind
Dimensional compatibility group (e.g. "time").
Definition unit.hpp:55
bool from_dimval
True when inferred from a dimval value.
Definition unit.hpp:57
std::string_view name
Human-readable unit name (e.g. "seconds").
Definition unit.hpp:54
constexpr bool empty() const noexcept
A unit carries no information when it has neither a name nor a kind.
Definition unit.hpp:60
std::string_view symbol
Display symbol (e.g. "s").
Definition unit.hpp:56
Declarative description of an untyped metric.
Definition untyped.hpp:14
Unit unit
Definition untyped.hpp:18
Labels labels
Definition untyped.hpp:17
std::string_view help
Definition untyped.hpp:16
std::string_view name
Definition untyped.hpp:15
comms::DisplayInfo display
Definition untyped.hpp:19