const auto& requestor = entry.first;
const auto& counters = entry.second;
- if (d_queryRateRule.warningRateExceeded(counters.queries, now)) {
+ if (d_queryRateRule.warningRateExceeded(g_rings.adjustForSamplingRate(counters.queries), now)) {
handleWarning(blocks, now, requestor, d_queryRateRule, updated);
}
- if (d_queryRateRule.rateExceeded(counters.queries, now)) {
+ if (d_queryRateRule.rateExceeded(g_rings.adjustForSamplingRate(counters.queries), now)) {
addBlock(blocks, now, requestor, d_queryRateRule, updated);
continue;
}
- if (d_respRateRule.warningRateExceeded(counters.respBytes, now)) {
+ if (d_respRateRule.warningRateExceeded(g_rings.adjustForSamplingRate(counters.respBytes), now)) {
handleWarning(blocks, now, requestor, d_respRateRule, updated);
}
- if (d_respRateRule.rateExceeded(counters.respBytes, now)) {
+ if (d_respRateRule.rateExceeded(g_rings.adjustForSamplingRate(counters.respBytes), now)) {
addBlock(blocks, now, requestor, d_respRateRule, updated);
continue;
}
const auto& typeIt = counters.d_qtypeCounts.find(qtype);
if (typeIt != counters.d_qtypeCounts.cend()) {
- if (pair.second.warningRateExceeded(typeIt->second, now)) {
+ if (pair.second.warningRateExceeded(g_rings.adjustForSamplingRate(typeIt->second), now)) {
handleWarning(blocks, now, requestor, pair.second, updated);
}
- if (pair.second.rateExceeded(typeIt->second, now)) {
+ if (pair.second.rateExceeded(g_rings.adjustForSamplingRate(typeIt->second), now)) {
addBlock(blocks, now, requestor, pair.second, updated);
break;
}
const auto& rcodeIt = counters.d_rcodeCounts.find(rcode);
if (rcodeIt != counters.d_rcodeCounts.cend()) {
- if (pair.second.warningRateExceeded(rcodeIt->second, now)) {
+ if (pair.second.warningRateExceeded(g_rings.adjustForSamplingRate(rcodeIt->second), now)) {
handleWarning(blocks, now, requestor, pair.second, updated);
}
- if (pair.second.rateExceeded(rcodeIt->second, now)) {
+ if (pair.second.rateExceeded(g_rings.adjustForSamplingRate(rcodeIt->second), now)) {
addBlock(blocks, now, requestor, pair.second, updated);
break;
}
if (suffixMatchRuleMatches) {
const bool hit = ringEntry.isACacheHit();
- root.submit(ringEntry.name, ((ringEntry.dh.rcode == 0 && ringEntry.usec == std::numeric_limits<unsigned int>::max()) ? -1 : ringEntry.dh.rcode), ringEntry.size, hit, std::nullopt);
+ root.submit(ringEntry.name, ((ringEntry.dh.rcode == 0 && ringEntry.usec == std::numeric_limits<uint32_t>::max()) ? -1 : ringEntry.dh.rcode), ringEntry.size, hit, std::nullopt, g_rings.getSamplingRate());
}
}
}
unsigned int dnsdist_ffi_stat_node_get_children_count(const dnsdist_ffi_stat_node_t* node)
{
- return node->node.children.size();
+ return node->node.size();
}
uint64_t dnsdist_ffi_stat_node_get_children_queries_count(const dnsdist_ffi_stat_node_t* node)
}
const bool hit = entry.isACacheHit();
- root.submit(entry.name, ((entry.dh.rcode == 0 && entry.usec == std::numeric_limits<unsigned int>::max()) ? -1 : entry.dh.rcode), entry.size, hit, std::nullopt);
+ root.submit(entry.name, ((entry.dh.rcode == 0 && entry.usec == std::numeric_limits<uint32_t>::max()) ? -1 : entry.dh.rcode), entry.size, hit, std::nullopt, g_rings.getSamplingRate());
}
}
{
return exceedRespGen(rate, seconds, [rcode](counts_t& counts, const Rings::Response& resp) {
if (resp.dh.rcode == rcode) {
- counts[resp.requestor]++;
+ counts[resp.requestor] += g_rings.adjustForSamplingRate(1U);
}
});
}
static counts_t exceedRespByterate(unsigned int rate, int seconds)
{
return exceedRespGen(rate, seconds, [](counts_t& counts, const Rings::Response& resp) {
- counts[resp.requestor] += resp.size;
+ counts[resp.requestor] += g_rings.adjustForSamplingRate(resp.size);
});
}
setLuaNoSideEffect();
return exceedQueryGen(rate, seconds, [type](counts_t& counts, const Rings::Query& query) {
if (query.qtype == type) {
- counts[query.requestor]++;
+ counts[query.requestor] += g_rings.adjustForSamplingRate(1U);
}
});
});
luaCtx.writeFunction("exceedQRate", [](unsigned int rate, int seconds) {
setLuaNoSideEffect();
return exceedQueryGen(rate, seconds, [](counts_t& counts, const Rings::Query& query) {
- counts[query.requestor]++;
+ counts[query.requestor] += g_rings.adjustForSamplingRate(1U);
});
});
/* StatNode */
luaCtx.registerFunction<unsigned int (StatNode::*)() const>("numChildren",
[](const StatNode& node) -> unsigned int {
- return node.children.size();
+ return node.size();
});
luaCtx.registerMember("fullname", &StatNode::fullname);
luaCtx.registerMember("labelsCount", &StatNode::labelsCount);
auto counter = d_samplingCounter++;
return (counter % d_samplingRate) == 0;
}
+
+uint32_t Rings::adjustForSamplingRate(uint32_t count) const
+{
+ const auto samplingRate = getSamplingRate();
+ if (samplingRate > 0) {
+ return count * samplingRate;
+ }
+ return count;
+}
return d_samplingRate;
}
+ uint32_t adjustForSamplingRate(uint32_t count) const;
+
std::vector<std::unique_ptr<Shard>> d_shards;
pdns::stat_t d_blockingQueryInserts{0};
pdns::stat_t d_blockingResponseInserts{0};
{
// 20% servfails, >100 children, on average less than 2 copies of a query
// >100 different subqueries
- double dups=1.0*childstat.queries/node->children.size();
+ double dups=1.0*childstat.queries/node->size();
if(dups > 2.0)
return;
- if(1.0*childstat.servfails / childstat.queries > 0.2 && node->children.size()>100) {
- cout<<node->fullname<<", servfails: "<<childstat.servfails<<", nxdomains: "<<childstat.nxdomains<<", remotes: "<<childstat.remotes.size()<<", children: "<<node->children.size()<<", childstat.queries: "<<childstat.queries;
+ if(1.0*childstat.servfails / childstat.queries > 0.2 && node->size()>100) {
+ cout<<node->fullname<<", servfails: "<<childstat.servfails<<", nxdomains: "<<childstat.nxdomains<<", remotes: "<<childstat.remotes.size()<<", children: "<<node->size()<<", childstat.queries: "<<childstat.queries;
cout<<", dups2: "<<dups<<endl;
for(const StatNode::Stat::remotes_t::value_type& rem : childstat.remotes) {
cout<<"source: "<<node->fullname<<"\t"<<rem.first.toString()<<"\t"<<rem.second<<endl;
ComboAddress rem = pr.getDest();
rem.sin4.sin_port=0;
- if(doServFailTree)
- root.submit(qname, header.rcode, pr.d_len, false, rem);
+ if (doServFailTree) {
+ root.submit(qname, header.rcode, pr.d_len, false, rem, 0U);
+ }
}
if(!qd.d_qcount || qd.d_qcount == qd.d_answercount) {
newstat += childstat;
}
-void StatNode::submit(const DNSName& domain, int rcode, unsigned int bytes, bool hit, const std::optional<ComboAddress>& remote)
+void StatNode::submit(const DNSName& domain, int rcode, unsigned int bytes, bool hit, const std::optional<ComboAddress>& remote, size_t samplingRate)
{
// cerr<<"FIRST submit called on '"<<domain<<"'"<<endl;
std::vector<string> tmp = domain.getRawLabels();
}
auto last = tmp.end() - 1;
- children[*last].submit(last, tmp.begin(), "", rcode, bytes, remote, 1, hit);
+ children[*last].submit(last, tmp.begin(), "", rcode, bytes, remote, 1, hit, samplingRate);
}
-/* www.powerdns.com. ->
+static uint64_t adjustForSampling(uint32_t count, size_t samplingRate)
+{
+ if (samplingRate > 0) {
+ return count * samplingRate;
+ }
+ return count;
+}
+
+
+/* www.powerdns.com. ->
. <- fullnames
com.
powerdns.com
www.powerdns.com.
*/
-void StatNode::submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, unsigned int bytes, const std::optional<ComboAddress>& remote, unsigned int count, bool hit)
+void StatNode::submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, unsigned int bytes, const std::optional<ComboAddress>& remote, unsigned int count, bool hit, size_t samplingRate)
{
// cerr<<"Submit called for domain='"<<domain<<"': ";
// for(const std::string& n : labels)
labelsCount = count;
}
// cerr<<"Hit the end, set our fullname to '"<<fullname<<"'"<<endl<<endl;
- s.queries++;
- s.bytes += bytes;
+ s.queries += adjustForSampling(1U, samplingRate);
+ s.bytes += adjustForSampling(bytes, samplingRate);
if (rcode < 0) {
- s.drops++;
+ s.drops += adjustForSampling(1U, samplingRate);
}
else if (rcode == RCode::NoError) {
- s.noerrors++;
+ s.noerrors += adjustForSampling(1U, samplingRate);
}
else if (rcode == RCode::ServFail) {
- s.servfails++;
+ s.servfails += adjustForSampling(1U, samplingRate);
}
else if (rcode == RCode::NXDomain) {
- s.nxdomains++;
+ s.nxdomains += adjustForSampling(1U, samplingRate);
}
if (remote) {
}
if (hit) {
- ++s.hits;
+ s.hits += adjustForSampling(1U, samplingRate);
}
}
else {
}
// cerr<<"Not yet end, set our fullname to '"<<fullname<<"', recursing"<<endl;
--end;
- children[*end].submit(end, begin, fullname, rcode, bytes, remote, count+1, hit);
+ children[*end].submit(end, begin, fullname, rcode, bytes, remote, count+1, hit, samplingRate);
}
}
};
using visitor_t = std::function<void(const StatNode*, const Stat& selfstat, const Stat& childstat)>;
- using children_t = std::map<std::string, StatNode, CIStringCompare>;
Stat s;
std::string name;
std::string fullname;
uint8_t labelsCount{0};
- void submit(const DNSName& domain, int rcode, unsigned int bytes, bool hit, const std::optional<ComboAddress>& remote);
+ void submit(const DNSName& domain, int rcode, uint32_t bytes, bool hit, const std::optional<ComboAddress>& remote, size_t samplingRate);
Stat print(unsigned int depth=0, Stat newstat=Stat(), bool silent=false) const;
void visit(const visitor_t& visitor, Stat& newstat, unsigned int depth = 0) const;
bool empty() const
{
return children.empty() && s.remotes.empty();
}
- children_t children;
+ size_t size() const
+ {
+ return children.size();
+ }
private:
- void submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, unsigned int bytes, const std::optional<ComboAddress>& remote, unsigned int count, bool hit);
+ void submit(std::vector<string>::const_iterator end, std::vector<string>::const_iterator begin, const std::string& domain, int rcode, uint32_t bytes, const std::optional<ComboAddress>& remote, unsigned int count, bool hit, size_t samplingRate);
+
+ using children_t = std::map<std::string, StatNode, CIStringCompare>;
+ children_t children;
};