'/servers/{server_id}/statistics':
get:
summary: 'Query statistics.'
- description: 'Query PowerDNS internal statistics. Returns a list of StatisticItem elements.'
+ description: 'Query PowerDNS internal statistics. Returns a list of BaseStatisticItem derived elements.'
operationId: getStats
tags:
- stats
type: array
items:
$ref: '#/definitions/StatisticItem'
+ $ref: '#/definitions/MapStatisticItem'
+ $ref: '#/definitions/RingStatisticItem'
'/servers/{server_id}/search-log':
get:
type: string
description: 'The value of setting name'
- StatisticItem:
- title: StatisticItem
+ BaseStatisticItem:
+ title: BaseStatisticItem
properties:
name:
- type: string
- description: 'set to “StatisticItem”'
- type:
type: string
description: 'The name of this item (e.g. ‘uptime’)'
- value:
- type: string
- description: 'The value of item'
+
+ StatisticItem:
+ title: StatisticItem
+ allOf:
+ $ref: "#/definitions/BaseStatisticItem"
+ properties:
+ type:
+ enum: [StatisticItem]
+ description: 'set to "StatisticItem"'
+ value:
+ type: string
+ description: 'The value of item'
+
+ MapStatisticItem:
+ title: MapStatisticItem
+ allOf:
+ $ref: "#/definitions/BaseStatisticItem"
+ properties:
+ type:
+ enum: [MapStatisticItem]
+ description: 'set to "MapStatisticItem"'
+ value:
+ type: array
+ description: 'named statistic values'
+ items:
+ type: array
+ properties:
+ name:
+ type: string
+ description: 'item name'
+ value:
+ type: string
+ description: 'item value'
+
+ RingStatisticItem:
+ title: RingStatisticItem
+ allOf:
+ $ref: "#/definitions/BaseStatisticItem"
+ properties:
+ type:
+ enum: [RingStatisticItem]
+ description: 'set to "RingStatisticItem"'
+ size:
+ type: integer
+ description: 'for RingStatisticItem objects, the size of the ring'
+ value:
+ type: array
+ description: 'named ring statistic values'
+ items:
+ type: array
+ properties:
+ name:
+ type: string
+ description: 'item name'
+ value:
+ type: string
+ description: 'item value'
SearchResultZone:
title: SearchResultZone
#include "json.hh"
#include "version.hh"
#include "arguments.hh"
+#include "dnsparser.hh"
+#include "responsestats.hh"
+#include "statbag.hh"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <iomanip>
-extern string s_programname;
using json11::Json;
+extern string s_programname;
+extern ResponseStats g_rs;
+#ifndef RECURSOR
+extern StatBag S;
+#endif
+
#ifndef HAVE_STRCASESTR
/*
if(req->method != "GET")
throw HttpMethodNotAllowedException();
- map<string,string> items;
- productServerStatisticsFetch(items);
+ typedef map<string, string> stat_items_t;
+ stat_items_t general_stats;
+ productServerStatisticsFetch(general_stats);
+
+ auto resp_qtype_stats = g_rs.getQTypeResponseCounts();
+ auto resp_size_stats = g_rs.getSizeResponseCounts();
Json::array doc;
- typedef map<string, string> items_t;
- for(const items_t::value_type& item : items) {
+ for(const auto& item : general_stats) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.first },
});
}
+ {
+ Json::array values;
+ for(const auto& item : resp_qtype_stats) {
+ if (item.second == 0)
+ continue;
+ values.push_back(Json::object {
+ { "name", DNSRecordContent::NumberToType(item.first) },
+ { "value", std::to_string(item.second) },
+ });
+ }
+
+ doc.push_back(Json::object {
+ { "type", "MapStatisticItem" },
+ { "name", "queries-by-qtype" },
+ { "value", values },
+ });
+ }
+
+ {
+ Json::array values;
+ for(const auto& item : resp_size_stats) {
+ if (item.second == 0)
+ continue;
+
+ values.push_back(Json::object {
+ { "name", std::to_string(item.first) },
+ { "value", std::to_string(item.second) },
+ });
+ }
+
+ doc.push_back(Json::object {
+ { "type", "MapStatisticItem" },
+ { "name", "response-sizes" },
+ { "value", values },
+ });
+ }
+
+#ifndef RECURSOR
+ for(const auto& ringName : S.listRings()) {
+ Json::array values;
+ const auto& ring = S.getRing(ringName);
+ for(const auto& item : ring) {
+ if (item.second == 0)
+ continue;
+
+ values.push_back(Json::object {
+ { "name", item.first },
+ { "value", std::to_string(item.second) },
+ });
+ }
+
+ doc.push_back(Json::object {
+ { "type", "RingStatisticItem" },
+ { "name", ringName },
+ { "size", std::to_string(S.getRingSize(ringName)) },
+ { "value", values },
+ });
+ }
+#endif
+
resp->setBody(doc);
}
"--api-key="+APIKEY
]
+run_check_call(["make", "-C", "../pdns", "sdig"])
+
if daemon == 'authoritative':
# Prepare sqlite DB with some zones.
serverproc.wait()
sys.exit(2)
+print "Query for example.com/A to create statistic data..."
+run_check_call(["../pdns/sdig", "127.0.0.1", str(DNSPORT), "example.com", "A"])
+
print "Running tests..."
returncode = 0
test_env = {}
def test_read_statistics(self):
r = self.session.get(self.url("/api/v1/servers/localhost/statistics"))
self.assert_success_json(r)
- data = dict([(r['name'], r['value']) for r in r.json()])
- self.assertIn('uptime', data)
+ data = r.json()
+ self.assertIn('uptime', [e['name'] for e in data])
+ if is_auth():
+ print data
+ qtype_stats, respsize_stats, queries_stats = None, None, None
+ for elem in data:
+ if elem['type'] == 'MapStatisticItem' and elem['name'] == 'queries-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']
+ 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])