summaryrefslogtreecommitdiffstats
path: root/library/cpp/monlib/encode
diff options
context:
space:
mode:
authorvvminashkin <[email protected]>2026-03-02 12:13:39 +0300
committervvminashkin <[email protected]>2026-03-02 13:04:29 +0300
commitb065a51848d90f8131a4861ebd6ec4f4e79f548f (patch)
tree908bccce181c50611bf891daded56c1fbbd35b39 /library/cpp/monlib/encode
parent49c8ec452cfb6220fc817bbb4d4667e440060ce0 (diff)
[cpp/monlib] add ability to mangle name in prometheus decoder
commit_hash:ef6584bf0941f50d0833dacd3b5d14cfc1cd30a8
Diffstat (limited to 'library/cpp/monlib/encode')
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus.h8
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp23
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp57
3 files changed, 83 insertions, 5 deletions
diff --git a/library/cpp/monlib/encode/prometheus/prometheus.h b/library/cpp/monlib/encode/prometheus/prometheus.h
index c6982996990..6467836a6a6 100644
--- a/library/cpp/monlib/encode/prometheus/prometheus.h
+++ b/library/cpp/monlib/encode/prometheus/prometheus.h
@@ -1,5 +1,7 @@
#pragma once
+#include <functional>
+
#include <library/cpp/monlib/encode/encoder.h>
#include <library/cpp/monlib/encode/format.h>
@@ -18,6 +20,12 @@ namespace NMonitoring {
struct TPrometheusDecodeSettings {
EPrometheusDecodeMode Mode{EPrometheusDecodeMode::DEFAULT};
+ /*
+ * Mangles the label that is equal to metricNameLabel. The
+ * new name must be not equal to any already present in the
+ * metric sample.
+ */
+ std::function<TString(TStringBuf)> NameMangler{};
};
IMetricEncoderPtr EncoderPrometheus(IOutputStream* out, TStringBuf metricNameLabel = "sensor");
diff --git a/library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp b/library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp
index 5ccc854cab2..c74fc9f4a82 100644
--- a/library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp
+++ b/library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp
@@ -525,14 +525,27 @@ namespace NMonitoring {
}
void ConsumeLabels(TStringBuf name, const TLabelsMap& labels) {
- Y_PARSER_ENSURE(labels.count(MetricNameLabel_) == 0,
- "label name '" << MetricNameLabel_ <<
- "' is reserved, but is used with metric: " << name << LabelsToStr(labels));
+ auto it = labels.find(MetricNameLabel_);
+ if(it != labels.end() && !Settings_.NameMangler) {
+ Y_PARSER_ENSURE(false,
+ "label name '" << MetricNameLabel_ <<
+ "' is reserved, but is used with metric: " << name << LabelsToStr(labels));
+ }
+ const bool labelClashPresent = it != labels.end();
Consumer_->OnLabelsBegin();
Consumer_->OnLabel(MetricNameLabel_, TString(name)); // TODO: remove this string allocation
- for (const auto& it: labels) {
- Consumer_->OnLabel(it.first, it.second);
+ for (const auto& [k, v]: labels) {
+ if(labelClashPresent && k == MetricNameLabel_) {
+ auto newKey = Settings_.NameMangler(k);
+ Y_PARSER_ENSURE(!labels.contains(newKey),
+ "after mangling label name: " << MetricNameLabel_ <<
+ " the resulting label is: " << newKey <<
+ "but it is already used in: " << LabelsToStr(labels));
+ Consumer_->OnLabel(newKey, v);
+ continue;
+ }
+ Consumer_->OnLabel(k, v);
}
Consumer_->OnLabelsEnd();
}
diff --git a/library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp b/library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp
index 4dbb4b574bb..f6b3eb01667 100644
--- a/library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp
+++ b/library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp
@@ -105,6 +105,63 @@ Y_UNIT_TEST_SUITE(TPrometheusDecoderTest) {
}
}
+ Y_UNIT_TEST(NameAlreadyPresent) {
+ constexpr auto inputMetrics =
+ "# A normal comment.\n"
+ "#\n"
+ "# TYPE name counter\n"
+ "name{sensor=\"some_name\",labelname=\"val1\",basename=\"basevalue\"} NaN\n"
+ "name{labelname=\"val2\",basename=\"basevalue\"} Nan\n"
+ "name {labelname=\"val3\",basename=\"basevalue\"} 2.3 1234567890\n"
+ "# HELP name two-line\\n doc str\\\\ing\n";
+
+ try {
+ auto samples = Decode(inputMetrics);
+ } catch(...) {
+ return;
+ }
+ UNIT_ASSERT(false);
+ }
+
+ Y_UNIT_TEST(NameAlreadyPresentButMangled) {
+ constexpr auto inputMetrics =
+ "# A normal comment.\n"
+ "#\n"
+ "# TYPE name counter\n"
+ "name{sensor=\"some_name\",labelname=\"val1\",basename=\"basevalue\"} NaN\n"
+ "name{labelname=\"val2\",basename=\"basevalue\"} Nan\n"
+ "name {labelname=\"val3\",basename=\"basevalue\"} 2.3 1234567890\n"
+ "# HELP name two-line\\n doc str\\\\ing\n";
+
+ try {
+ auto samples = Decode(inputMetrics, TPrometheusDecodeSettings{.NameMangler = [](auto s) -> TString {
+ return TStringBuilder{}<<"mm_" << s;
+ }});
+ } catch(...) {
+ UNIT_ASSERT(false);
+ }
+ }
+
+ Y_UNIT_TEST(MangledNameClash) {
+ constexpr auto inputMetrics =
+ "# A normal comment.\n"
+ "#\n"
+ "# TYPE name counter\n"
+ "name{mm_sensor=\"other\",sensor=\"some_name\",labelname=\"val1\",basename=\"basevalue\"} NaN\n"
+ "name{labelname=\"val2\",basename=\"basevalue\"} Nan\n"
+ "name {labelname=\"val3\",basename=\"basevalue\"} 2.3 1234567890\n"
+ "# HELP name two-line\\n doc str\\\\ing\n";
+
+ try {
+ auto samples = Decode(inputMetrics, TPrometheusDecodeSettings{.NameMangler = [](auto s) -> TString {
+ return TStringBuilder{}<<"mm_" << s;
+ }});
+ } catch(...) {
+ return;
+ }
+ UNIT_ASSERT(false);
+ }
+
Y_UNIT_TEST(Counter) {
constexpr auto inputMetrics =
"# A normal comment.\n"