Skip to content

Commit 651092f

Browse files
committed
fix(core): Ignore labels with empty value
The Data Mpdel spec states: > A label with an empty label value is considered > equivalent to a label that does not exist.
1 parent bac0722 commit 651092f

File tree

3 files changed

+84
-9
lines changed

3 files changed

+84
-9
lines changed

core/include/prometheus/family.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable {
8888
/// metric.
8989
/// \throw std::runtime_exception on invalid metric or label names.
9090
Family(const std::string& name, const std::string& help,
91-
const Labels& constant_labels);
91+
Labels constant_labels);
9292

9393
/// \brief Add a new dimensional data.
9494
///
@@ -108,7 +108,7 @@ class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable {
108108
/// labels already exists - the already existing dimensional data.
109109
/// \throw std::runtime_exception on invalid label names.
110110
template <typename... Args>
111-
T& Add(const Labels& labels, Args&&... args) {
111+
T& Add(Labels labels, Args&&... args) {
112112
return Add(labels, std::make_unique<T>(args...));
113113
}
114114

@@ -121,7 +121,7 @@ class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable {
121121
/// \brief Returns true if the dimensional data with the given labels exist
122122
///
123123
/// \param labels A set of key-value pairs (= labels) of the dimensional data.
124-
bool Has(const Labels& labels) const;
124+
bool Has(Labels labels) const;
125125

126126
/// \brief Returns the name for this family.
127127
///
@@ -149,7 +149,7 @@ class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable {
149149
mutable std::mutex mutex_;
150150

151151
ClientMetric CollectMetric(const Labels& labels, T* metric) const;
152-
T& Add(const Labels& labels, std::unique_ptr<T> object);
152+
T& Add(Labels labels, std::unique_ptr<T> object);
153153
};
154154

155155
} // namespace prometheus

core/src/family.cc

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,42 @@
1414
#include "prometheus/summary.h"
1515

1616
namespace prometheus {
17+
namespace {
18+
19+
template <class Key, class T, class Compare, class Alloc, class Pred>
20+
void erase_if(std::map<Key, T, Compare, Alloc>& c, Pred pred) {
21+
for (auto i = c.begin(), last = c.end(); i != last;)
22+
if (pred(*i)) {
23+
i = c.erase(i);
24+
} else {
25+
++i;
26+
}
27+
}
28+
29+
auto empty_label_value = [](const Labels::value_type& label) {
30+
return label.second.empty();
31+
};
32+
33+
// A label with an empty label value is considered equivalent to a label that
34+
// does not exist.
35+
void filter_labels(Labels& labels) {
36+
// with C++20 use std::erase_if
37+
erase_if(labels, empty_label_value);
38+
}
39+
40+
Labels filter_and_return_labels(Labels labels) {
41+
filter_labels(labels);
42+
return labels;
43+
}
44+
45+
} // namespace
1746

1847
template <typename T>
1948
Family<T>::Family(const std::string& name, const std::string& help,
20-
const Labels& constant_labels)
21-
: name_(name), help_(help), constant_labels_(constant_labels) {
49+
Labels constant_labels)
50+
: name_(name),
51+
help_(help),
52+
constant_labels_(filter_and_return_labels(std::move(constant_labels))) {
2253
if (!CheckMetricName(name_)) {
2354
throw std::invalid_argument("Invalid metric name");
2455
}
@@ -31,7 +62,9 @@ Family<T>::Family(const std::string& name, const std::string& help,
3162
}
3263

3364
template <typename T>
34-
T& Family<T>::Add(const Labels& labels, std::unique_ptr<T> object) {
65+
T& Family<T>::Add(Labels labels, std::unique_ptr<T> object) {
66+
filter_labels(labels);
67+
3568
std::lock_guard<std::mutex> lock{mutex_};
3669

3770
auto insert_result =
@@ -70,9 +103,12 @@ void Family<T>::Remove(T* metric) {
70103
}
71104

72105
template <typename T>
73-
bool Family<T>::Has(const Labels& labels) const {
106+
bool Family<T>::Has(Labels labels) const {
107+
filter_labels(labels);
108+
74109
std::lock_guard<std::mutex> lock{mutex_};
75-
return metrics_.count(labels) != 0u;
110+
auto count = metrics_.count(labels);
111+
return count != 0u;
76112
}
77113

78114
template <typename T>

core/tests/family_test.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,44 @@ TEST(FamilyTest, reject_summary_with_quantile_label) {
139139
EXPECT_ANY_THROW(family.Add(labels, quantiles));
140140
}
141141

142+
TEST(FamilyTest, ignore_constant_labels_with_empty_value) {
143+
auto labels = Labels{{"foo", "bar"}, {"label", ""}};
144+
auto expected_labels = Labels{{"foo", "bar"}};
145+
146+
Family<Counter> family{"total_requests", "All Requests", labels};
147+
EXPECT_EQ(expected_labels, family.GetConstantLabels());
148+
}
149+
150+
TEST(FamilyTest, ignore_labels_with_empty_value_on_add) {
151+
auto labels = Labels{{"foo", "bar"}, {"label", ""}};
152+
auto expected_labels = Labels{{"foo", "bar"}};
153+
154+
Family<Counter> family{"total_requests", "All Requests", {}};
155+
family.Add(labels);
156+
157+
EXPECT_TRUE(family.Has(expected_labels));
158+
}
159+
160+
TEST(FamilyTest, ignore_labels_with_empty_value_for_has) {
161+
auto labels = Labels{{"foo", "bar"}};
162+
auto accepted_labels = Labels{{"foo", "bar"}, {"label", ""}};
163+
164+
Family<Counter> family{"total_requests", "All Requests", {}};
165+
family.Add(labels);
166+
167+
EXPECT_TRUE(family.Has(accepted_labels));
168+
}
169+
170+
TEST(FamilyTest, ignore_labels_with_empty_value_and_merge) {
171+
auto labelsA = Labels{{"foo", "bar"}};
172+
auto labelsB = Labels{{"foo", "bar"}, {"label", ""}};
173+
174+
Family<Counter> family{"total_requests", "All Requests", {}};
175+
auto& a = family.Add(labelsA);
176+
auto& b = family.Add(labelsB);
177+
178+
EXPECT_EQ(&a, &b);
179+
}
180+
142181
} // namespace
143182
} // namespace prometheus

0 commit comments

Comments
 (0)