diff options
| author | vvminashkin <[email protected]> | 2026-03-02 12:13:39 +0300 |
|---|---|---|
| committer | vvminashkin <[email protected]> | 2026-03-02 13:04:29 +0300 |
| commit | b065a51848d90f8131a4861ebd6ec4f4e79f548f (patch) | |
| tree | 908bccce181c50611bf891daded56c1fbbd35b39 /library/cpp/monlib/encode | |
| parent | 49c8ec452cfb6220fc817bbb4d4667e440060ce0 (diff) | |
[cpp/monlib] add ability to mangle name in prometheus decoder
commit_hash:ef6584bf0941f50d0833dacd3b5d14cfc1cd30a8
Diffstat (limited to 'library/cpp/monlib/encode')
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" |
