]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Dedup Prometheus help and type lines for custom metrics with labels
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 28 Jun 2024 08:45:56 +0000 (10:45 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 28 Jun 2024 08:45:56 +0000 (10:45 +0200)
pdns/dnsdistdist/dnsdist-web.cc
regression-tests.dnsdist/test_Prometheus.py

index 45c9b431e667c400a27893e5f8f1dd2b44be42d1..122ea8147d21c9bcb900fb5bdbcd10cb25add27c 100644 (file)
@@ -484,6 +484,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
   static const std::set<std::string> metricBlacklist = {"special-memory-usage", "latency-count", "latency-sum"};
   {
     auto entries = dnsdist::metrics::g_stats.entries.read_lock();
+    std::unordered_set<std::string> 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<pdns::stat_t*>(&entry.d_value)) {
index cccf04bfb66e338331766bd73cd25a36f3723b5d..f6d334038b0fae8f564d690d133528797d31bb8c 100644 (file)
@@ -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):