From: Remi Gacogne Date: Fri, 28 Jun 2024 08:45:56 +0000 (+0200) Subject: dnsdist: Dedup Prometheus help and type lines for custom metrics with labels X-Git-Tag: rec-5.2.0-alpha1~209^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4781d5b094850dbda246366474c3ae70cc018380;p=thirdparty%2Fpdns.git dnsdist: Dedup Prometheus help and type lines for custom metrics with labels --- diff --git a/pdns/dnsdistdist/dnsdist-web.cc b/pdns/dnsdistdist/dnsdist-web.cc index 45c9b431e6..122ea8147d 100644 --- a/pdns/dnsdistdist/dnsdist-web.cc +++ b/pdns/dnsdistdist/dnsdist-web.cc @@ -484,6 +484,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) static const std::set metricBlacklist = {"special-memory-usage", "latency-count", "latency-sum"}; { auto entries = dnsdist::metrics::g_stats.entries.read_lock(); + std::unordered_set helpAndTypeSent; for (const auto& entry : *entries) { const auto& metricName = entry.d_name; @@ -515,8 +516,11 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) // for these we have the help and types encoded in the sources // but we need to be careful about labels in custom metrics std::string helpName = prometheusMetricName.substr(0, prometheusMetricName.find('{')); - output << "# HELP " << helpName << " " << metricDetails.description << "\n"; - output << "# TYPE " << helpName << " " << prometheusTypeName << "\n"; + if (!helpAndTypeSent.count(helpName)) { + helpAndTypeSent.insert(helpName); + output << "# HELP " << helpName << " " << metricDetails.description << "\n"; + output << "# TYPE " << helpName << " " << prometheusTypeName << "\n"; + } output << prometheusMetricName << " "; if (const auto& val = std::get_if(&entry.d_value)) { diff --git a/regression-tests.dnsdist/test_Prometheus.py b/regression-tests.dnsdist/test_Prometheus.py index cccf04bfb6..f6d334038b 100644 --- a/regression-tests.dnsdist/test_Prometheus.py +++ b/regression-tests.dnsdist/test_Prometheus.py @@ -28,6 +28,10 @@ class TestPrometheus(DNSDistTest): declareMetric('custom-metric2', 'gauge', 'Custom gauge') -- and custom names declareMetric('custom-metric3', 'counter', 'Custom counter', 'custom_prometheus_name') + + -- test prometheus labels in custom metrics + declareMetric('custom-metric-foo-x-bar-y-xyz', 'counter', 'Custom counter with labels', 'custom_metric_foo{x="bar",y="xyz"}') + declareMetric('custom-metric-foo-x-baz-y-abc', 'counter', 'Custom counter with labels', 'custom_metric_foo{x="baz",y="abc"}') """ def checkPrometheusContentBasic(self, content): @@ -42,7 +46,7 @@ class TestPrometheus(DNSDistTest): elif not line.startswith('#'): tokens = line.split(' ') self.assertEqual(len(tokens), 2) - if not line.startswith('dnsdist_') and not line.startswith('custom_prometheus_name'): + if not line.startswith('dnsdist_') and not line.startswith('custom_'): raise AssertionError('Expecting prometheus metric to be prefixed by \'dnsdist_\', got: "%s"' % (line)) def checkMetric(self, content, name, expectedType, expectedValue):