1+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2+ /*
3+ * Copyright 2022-Present Couchbase, Inc.
4+ *
5+ * Use of this software is governed by the Business Source License included
6+ * in the file licenses/BSL-Couchbase.txt. As of the Change Date specified
7+ * in that file, in accordance with the Business Source License, use of this
8+ * software will be governed by the Apache License, Version 2.0, included in
9+ * the file licenses/APL2.txt.
10+ */
11+ #pragma once
12+
13+ #include < string>
14+ #include < string_view>
15+ #include < unordered_map>
16+
17+ #include " units.h"
18+
19+ namespace cb ::stats {
20+
21+ /* *
22+ * Small wrapper to track whether a key from stats.def.h needs to be formatted.
23+ *
24+ * This is used to distinguish:
25+ *
26+ * STAT(foo_bar, "foo_bar",...)
27+ * -> StatDef("foo_bar", ...)
28+ * from
29+ * STAT(foo_bar, FMT("{scope}:foo_bar"),...)
30+ * -> StatDef( CBStatsKey("{scope}:foo_bar", NeedsFormattingTag{}), ...)
31+ */
32+ class CBStatsKey {
33+ public:
34+ // default constructor required for stats.def.h if cbstats name is not given
35+ CBStatsKey () = default ;
36+
37+ CBStatsKey (std::string_view key) : key(key) {
38+ }
39+
40+ struct NeedsFormattingTag {};
41+
42+ CBStatsKey (std::string_view key, NeedsFormattingTag)
43+ : key(key), needsFormatting(true ) {
44+ }
45+
46+ operator std::string_view () const {
47+ return key;
48+ }
49+
50+ bool empty () const {
51+ return key.empty ();
52+ }
53+
54+ const std::string_view key;
55+ const bool needsFormatting = false ;
56+ };
57+
58+ /* *
59+ * Type representing the key under which a stat should be reported.
60+ *
61+ * StatCollector implementations which support labelled stats with
62+ * shared names may use the metricFamilyKey and labels, if present -
63+ * for example PrometheusStatCollector.
64+ *
65+ * Implementations which do not support labels should use the cbstatsKey.
66+ * These keys should be unique per-bucket.
67+ *
68+ * For example, "cmd_get" and "cmd_set". CBStats must report them under
69+ * unique names, but Prometheus could report them under the same metric
70+ * name (e.g., "cmd") but with a label to distinguish them.
71+ * This is not a necessity, but is a nice-to-have to make Prometheus
72+ * querying more expressive.
73+ *
74+ * This type should mainly be constructed from the definitions in
75+ * stats.def.h, but can also be created directly as a fallback until
76+ * all stats have been transitioned to stats.def.h.
77+ */
78+ struct StatDef {
79+ using Labels = std::unordered_map<const char *, std::string_view>;
80+ /* *
81+ * Construct from char* to minimize code change while migrating to
82+ * the StatCollector interface.
83+ *
84+ * Ideally stats would specify a StatKey to lookup a StatDef,
85+ * but until all stats have been added to stats.def.h, this
86+ * allows convenient construction of a basic StatDef.
87+ *
88+ * StatDefs created in this manner will _not_ be formatted. Code which
89+ * is unaware of StatCollectors may generate stat keys which are not
90+ * safe to provide to fmt::format (e.g., may happen to contain invalid
91+ * replacement specifiers).
92+ */
93+ StatDef (const char * uniqueKey) : StatDef(std::string_view(uniqueKey)) {
94+ }
95+
96+ StatDef (std::string_view uniqueKey) : cbstatsKey(CBStatsKey(uniqueKey)) {
97+ }
98+
99+ /* *
100+ * Construct a stat definition for use by CBStats and Prometheus.
101+ *
102+ * Constructs a stat specification including the information needed to
103+ * expose a stat through either CBStats or Prometheus.
104+ *
105+ * @param cbstatsKey name of stat which is unique within a bucket. Used by
106+ * CBStats.
107+ * @param unit the quantity this stat represents (bytes, seconds etc.) and
108+ * the scale prefix (kilo, micro etc.). Used by PrometheusStatCollector to
109+ * normalise stats into their base units, and suffix them correctly.
110+ * @param metricFamilyKey name which may be shared by multiple stats with
111+ * distinguishing labels. Used to group stats.
112+ * @param labels key/value pairs used by Prometheus to filter/aggregate
113+ * stats
114+ */
115+ StatDef (CBStatsKey cbstatsKey,
116+ cb::stats::Unit unit = cb::stats::units::none,
117+ std::string_view metricFamilyKey = " " ,
118+ Labels&& labels = {});
119+
120+ /* *
121+ * Tag struct used to explicitly identify stats which should not be exposed
122+ * to Prometheus.
123+ */
124+ struct CBStatsOnlyTag {};
125+
126+ /* *
127+ * Tag struct used to explicitly identify stats which should not be exposed
128+ * for cbstats.
129+ */
130+ struct PrometheusOnlyTag {};
131+
132+ /* *
133+ * Construct a CBStats-only stat definition.
134+ *
135+ * Constructs a stat specification including the information needed to
136+ * expose a stat only through CBStats. The stat will _not_ be exposed over
137+ * Prometheus.
138+ *
139+ * @param cbstatsKey name of stat which is unique within a bucket.
140+ */
141+ StatDef (CBStatsKey cbstatsKey, CBStatsOnlyTag);
142+
143+ /* *
144+ * Construct a Prometheus-only stat definition.
145+ *
146+ * Constructs a stat specification including the information needed to
147+ * expose a stat only for Prometheus. The stat will _not_ be exposed over
148+ * cbstats.
149+ *
150+ * @param metricFamilyKey name of stat which is unique within a bucket.
151+ */
152+ StatDef (std::string_view metricFamilyKey,
153+ cb::stats::Unit unit,
154+ Labels&& labels,
155+ PrometheusOnlyTag);
156+
157+ bool isCBStat () const {
158+ return !cbstatsKey.empty ();
159+ }
160+
161+ bool isPrometheusStat () const {
162+ return !metricFamily.empty ();
163+ }
164+
165+ bool needsFormatting () const {
166+ return cbstatsKey.needsFormatting ;
167+ }
168+
169+ // Key which should be unique per bucket, possibly after being formatted
170+ // with values from `labels`. Used by CBStats.
171+ const CBStatsKey cbstatsKey;
172+ // The unit this stat represents, e.g., microseconds.
173+ // Used to scale to base units and name the stat correctly for Prometheus,
174+ const cb::stats::Unit unit = cb::stats::units::none;
175+ // Metric name used by Prometheus. Used to "group"
176+ // stats in combination with distinguishing labels.
177+ std::string metricFamily;
178+ // Labels for this metric. Labels set here will
179+ // override defaults labels set in the StatCollector
180+ const Labels labels;
181+ };
182+
183+ } // namespace cb::stats
0 commit comments