]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add Rcode response statistics on API
authorThomas du Boÿs <thomas.du-boys@corp.ovh.com>
Fri, 11 Jan 2019 10:02:15 +0000 (11:02 +0100)
committerThomas du Boÿs <thomas.du-boys@corp.ovh.com>
Mon, 28 Jan 2019 09:53:02 +0000 (10:53 +0100)
- Add new statistic variable about rcode responses
- Add metrics about RCode on statistics API entrypoint
- Update regression tests

pdns/responsestats-auth.cc
pdns/responsestats.cc
pdns/responsestats.hh
pdns/ws-api.cc
regression-tests.api/test_Servers.py

index 2112dce2a6cc58a996f7c6cc2aaf98a483de18df..61b4c6b0087f43990b45f14690ec7e67da161365 100644 (file)
@@ -52,5 +52,5 @@ void ResponseStats::submitResponse(DNSPacket &p, bool udpOrTCP) {
     }
   }
 
-  submitResponse(p.qtype.getCode(), buf.length(), udpOrTCP);
+  submitResponse(p.qtype.getCode(), buf.length(), p.d.rcode, udpOrTCP);
 }
index 64ec3abe457410568d1d6fb3206ddac500a8b231..93b2fca51102ea7c6662331e16d813ee9d1cfe78 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "dnsparser.hh"
 
-ResponseStats::ResponseStats() :   d_qtypecounters(new std::atomic<unsigned long>[65536])
+ResponseStats::ResponseStats() :   d_qtypecounters(new std::atomic<unsigned long>[65536]), d_rcodecounters(new std::atomic<unsigned long>[256])
 {
   d_sizecounters.push_back(make_pair(20,0));
   d_sizecounters.push_back(make_pair(40,0));
@@ -21,6 +21,8 @@ ResponseStats::ResponseStats() :   d_qtypecounters(new std::atomic<unsigned long
   d_sizecounters.push_back(make_pair(std::numeric_limits<uint16_t>::max(),0));
   for(unsigned int n =0 ; n < 65535; ++n)
     d_qtypecounters[n] = 0;
+  for(unsigned int n =0 ; n < 256; ++n)
+    d_rcodecounters[n] = 0;
 }
 
 ResponseStats g_rs;
@@ -28,9 +30,15 @@ ResponseStats g_rs;
 static bool pcomp(const pair<uint16_t, uint64_t>&a , const pair<uint16_t, uint64_t>&b)
 {
   return a.first < b.first;
-} 
+}
+
+void ResponseStats::submitResponse(uint16_t qtype,uint16_t respsize, uint8_t rcode, bool udpOrTCP)
+{
+    d_rcodecounters[rcode]++;
+    submitResponse(qtype, respsize, udpOrTCP);
+}
 
-void ResponseStats::submitResponse(uint16_t qtype, uint16_t respsize, bool udpOrTCP) 
+void ResponseStats::submitResponse(uint16_t qtype,uint16_t respsize, bool udpOrTCP)
 {
   d_qtypecounters[qtype]++;
   pair<uint16_t, uint64_t> s(respsize, 0);
@@ -63,6 +71,18 @@ map<uint16_t, uint64_t> ResponseStats::getSizeResponseCounts()
   return ret;
 }
 
+map<uint8_t, uint64_t> ResponseStats::getRCodeResponseCounts()
+{
+  map<uint8_t, uint64_t> ret;
+  uint64_t count;
+  for(unsigned int i = 0 ; i < 256 ; ++i) {
+    count= d_rcodecounters[i];
+    if(count)
+      ret[i]=count;
+  }
+  return ret;
+}
+
 string ResponseStats::getQTypeReport()
 {
   typedef map<uint16_t, uint64_t> qtypenums_t;
@@ -74,4 +94,3 @@ string ResponseStats::getQTypeReport()
   }
   return os.str();
 }
-
index c82cf05c1412cc4dfcada08cf2ccd03fc087595a..884d49d0f20934029ca8673cd9fb7013546b3e71 100644 (file)
@@ -30,12 +30,15 @@ public:
 
   void submitResponse(DNSPacket &p, bool udpOrTCP);
   void submitResponse(uint16_t qtype, uint16_t respsize, bool udpOrTCP);
+  void submitResponse(uint16_t qtype, uint16_t respsize, uint8_t rcode, bool udpOrTCP);
   map<uint16_t, uint64_t> getQTypeResponseCounts();
   map<uint16_t, uint64_t> getSizeResponseCounts();
+  map<uint8_t, uint64_t> getRCodeResponseCounts();
   string getQTypeReport();
 
 private:
   boost::scoped_array<std::atomic<unsigned long>> d_qtypecounters;
+  boost::scoped_array<std::atomic<unsigned long>> d_rcodecounters;
   typedef vector<pair<uint16_t, uint64_t> > sizecounters_t;
   sizecounters_t d_sizecounters;
 };
index 54776cd1e3b89bf0691ed2bfa9954d79c2272ec8..6106d25f3329d76107fc6134f991ee1347be0e22 100644 (file)
@@ -165,6 +165,7 @@ void apiServerStatistics(HttpRequest* req, HttpResponse* resp) {
 
   auto resp_qtype_stats = g_rs.getQTypeResponseCounts();
   auto resp_size_stats = g_rs.getSizeResponseCounts();
+  auto resp_rcode_stats = g_rs.getRCodeResponseCounts();
 
   Json::array doc;
   for(const auto& item : general_stats) {
@@ -188,7 +189,7 @@ void apiServerStatistics(HttpRequest* req, HttpResponse* resp) {
 
     doc.push_back(Json::object {
       { "type", "MapStatisticItem" },
-      { "name", "queries-by-qtype" },
+      { "name", "response-by-qtype" },
       { "value", values },
     });
   }
@@ -212,6 +213,24 @@ void apiServerStatistics(HttpRequest* req, HttpResponse* resp) {
     });
   }
 
+  {
+    Json::array values;
+    for(const auto& item : resp_rcode_stats) {
+      if (item.second == 0)
+        continue;
+      values.push_back(Json::object {
+        { "name", RCode::to_s(item.first) },
+        { "value", std::to_string(item.second) },
+      });
+    }
+
+    doc.push_back(Json::object {
+      { "type", "MapStatisticItem" },
+      { "name", "response-by-rcode" },
+      { "value", values },
+    });
+  }
+
 #ifndef RECURSOR
   for(const auto& ringName : S.listRings()) {
     Json::array values;
index 400a6e47fd49cb87ee040b7e8b416e741afb1351..80835f999ed644c77096861e1aed81cefb2e7af2 100644 (file)
@@ -43,14 +43,17 @@ class Servers(ApiTestCase):
         self.assertIn('uptime', [e['name'] for e in data])
         if is_auth():
             print(data)
-            qtype_stats, respsize_stats, queries_stats = None, None, None
+            qtype_stats, respsize_stats, queries_stats, rcode_stats = None, None, None, None
             for elem in data:
-                if elem['type'] == 'MapStatisticItem' and elem['name'] == 'queries-by-qtype':
+                if elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-by-qtype':
                     qtype_stats = elem['value']
                 elif elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-sizes':
                     respsize_stats = elem['value']
                 elif elem['type'] == 'RingStatisticItem' and elem['name'] == 'queries':
                     queries_stats = elem['value']
+                elif elem['type'] == 'MapStatisticItem' and elem['name'] == 'response-by-rcode':
+                    rcode_stats = elem['value']
             self.assertIn('A', [e['name'] for e in qtype_stats])
             self.assertIn('60', [e['name'] for e in respsize_stats])
             self.assertIn('example.com/A', [e['name'] for e in queries_stats])
+            self.assertIn('No Error', [e['name'] for e in rcode_stats])