return std::make_shared<NetmaskGroupRule>(nmg);
}
+std::unordered_map<int, vector<boost::variant<string,double>>> getGenResponses(unsigned int top, boost::optional<int> labels, std::function<bool(const Rings::Response&)> pred)
+{
+ setLuaNoSideEffect();
+ map<DNSName, int> counts;
+ unsigned int total=0;
+ {
+ std::lock_guard<std::mutex> lock(g_rings.respMutex);
+ if(!labels) {
+ for(const auto& a : g_rings.respRing) {
+ if(!pred(a))
+ continue;
+ counts[a.name]++;
+ total++;
+ }
+ }
+ else {
+ unsigned int lab = *labels;
+ for(auto a : g_rings.respRing) {
+ if(!pred(a))
+ continue;
+
+ a.name.trimToLabels(lab);
+ counts[a.name]++;
+ total++;
+ }
+
+ }
+ }
+ // cout<<"Looked at "<<total<<" responses, "<<counts.size()<<" different ones"<<endl;
+ vector<pair<int, DNSName>> rcounts;
+ rcounts.reserve(counts.size());
+ for(const auto& c : counts)
+ rcounts.push_back(make_pair(c.second, c.first));
+
+ sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a,
+ const decltype(rcounts)::value_type& b) {
+ return b.first < a.first;
+ });
+
+ std::unordered_map<int, vector<boost::variant<string,double>>> ret;
+ unsigned int count=1, rest=0;
+ for(const auto& rc : rcounts) {
+ if(count==top+1)
+ rest+=rc.first;
+ else
+ ret.insert({count++, {rc.second.toString(), rc.first, 100.0*rc.first/total}});
+ }
+ ret.insert({count, {"Rest", rest, 100.0*rest/total}});
+ return ret;
+}
+
vector<std::function<void(void)>> setupLua(bool client, const std::string& config)
{
g_launchWork= new vector<std::function<void(void)>>();
});
g_lua.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional<int> labels) {
- setLuaNoSideEffect();
- map<DNSName, int> counts;
- unsigned int total=0;
- {
- std::lock_guard<std::mutex> lock(g_rings.respMutex);
- if(!labels) {
- for(const auto& a : g_rings.respRing) {
- if(a.dh.rcode!=kind)
- continue;
- counts[a.name]++;
- total++;
- }
- }
- else {
- unsigned int lab = *labels;
- for(auto a : g_rings.respRing) {
- if(a.dh.rcode!=kind)
- continue;
-
- a.name.trimToLabels(lab);
- counts[a.name]++;
- total++;
- }
-
- }
- }
- // cout<<"Looked at "<<total<<" responses, "<<counts.size()<<" different ones"<<endl;
- vector<pair<int, DNSName>> rcounts;
- rcounts.reserve(counts.size());
- for(const auto& c : counts)
- rcounts.push_back(make_pair(c.second, c.first));
+ return getGenResponses(top, labels, [kind](const Rings::Response& r) { return r.dh.rcode == kind; });
+ });
- sort(rcounts.begin(), rcounts.end(), [](const decltype(rcounts)::value_type& a,
- const decltype(rcounts)::value_type& b) {
- return b.first < a.first;
- });
+ g_lua.executeCode(R"(function topResponses(top, kind, labels) top = top or 10; kind = kind or 0; for k,v in ipairs(getTopResponses(top, kind, labels)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
- std::unordered_map<int, vector<boost::variant<string,double>>> ret;
- unsigned int count=1, rest=0;
- for(const auto& rc : rcounts) {
- if(count==top+1)
- rest+=rc.first;
- else
- ret.insert({count++, {rc.second.toString(), rc.first, 100.0*rc.first/total}});
- }
- ret.insert({count, {"Rest", rest, 100.0*rest/total}});
- return ret;
+ g_lua.writeFunction("getSlowResponses", [](unsigned int top, unsigned int msec, boost::optional<int> labels) {
+ return getGenResponses(top, labels, [msec](const Rings::Response& r) { return r.usec > msec*1000; });
});
- g_lua.executeCode(R"(function topResponses(top, kind, labels) top = top or 10; kind = kind or 0; for k,v in ipairs(getTopResponses(top, kind, labels)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
+
+ g_lua.executeCode(R"(function topSlow(top, msec, labels) top = top or 10; msec = msec or 500; for k,v in ipairs(getSlowResponses(top, msec)) do show(string.format("%4d %-40s %4d %4.1f%%",k,v[1],v[2],v[3])) end end)");
g_lua.writeFunction("showResponseLatency", []() {
g_lua.writeFunction("grepq", [](const std::string& s, boost::optional<unsigned int> limit) {
boost::optional<Netmask> nm;
boost::optional<DNSName> dn;
+ unsigned int msec=0;
try
{
nm = Netmask(s);
}
catch(...) {
- try { dn=DNSName(s); }
- catch(...)
- {
- g_outputBuffer = "Could not parse '"+s+"' as domain name or netmask";
- return;
- }
+ if(boost::ends_with(s,"ms") && sscanf(s.c_str(), "%ums", &msec)) {
+ ;
+ }
+ else {
+ try { dn=DNSName(s); }
+ catch(...)
+ {
+ g_outputBuffer = "Could not parse '"+s+"' as domain name or netmask";
+ return;
+ }
+ }
}
decltype(g_rings.queryRing) qr;
std::multimap<struct timespec, string> out;
- boost::format fmt("%-7.1f %-47s %-5d %-25s %-5s %-4.1f %-2s %-2s %-2s %s\n");
- g_outputBuffer+= (fmt % "Time" % "Client" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str();
+ boost::format fmt("%-7.1f %-47s %-12s %-5d %-25s %-5s %-4.1f %-2s %-2s %-2s %s\n");
+ g_outputBuffer+= (fmt % "Time" % "Client" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str();
for(const auto& c : qr) {
- if((nm && nm->match(c.requestor)) || (dn && c.name.isPartOf(*dn))) {
+ if((nm && nm->match(c.requestor)) || (dn && c.name.isPartOf(*dn)) ) {
QType qt(c.qtype);
- out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % htons(c.dh.id) % c.name.toString() % qt.getName() % "" % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % "Question").str() )) ;
+ out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % "" % htons(c.dh.id) % c.name.toString() % qt.getName() % "" % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % "Question").str() )) ;
if(limit && *limit==++num)
break;
string extra;
for(const auto& c : rr) {
- if((nm && nm->match(c.requestor)) || (dn && c.name.isPartOf(*dn))) {
+ if((nm && nm->match(c.requestor)) || (dn && c.name.isPartOf(*dn)) || (msec && (c.usec/1000 > msec)) ) {
QType qt(c.qtype);
if(!c.dh.rcode)
extra=". " +std::to_string(htons(c.dh.ancount))+ " answers";
else
extra.clear();
- out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % htons(c.dh.id) % c.name.toString() % qt.getName() % (c.usec/1000.0) % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % (RCode::to_s(c.dh.rcode) + extra)).str() )) ;
+ if(c.usec != std::numeric_limits<decltype(c.usec)>::max())
+ out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % c.ds.toStringWithPort() % htons(c.dh.id) % c.name.toString() % qt.getName() % (c.usec/1000.0) % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % (RCode::to_s(c.dh.rcode) + extra)).str() )) ;
+ else
+ out.insert(make_pair(c.when, (fmt % DiffTime(now, c.when) % c.requestor.toStringWithPort() % c.ds.toStringWithPort() % htons(c.dh.id) % c.name.toString() % qt.getName() % "T.O" % (c.dh.tc ? "TC" : "") % (c.dh.rd? "RD" : "") % (c.dh.aa? "AA" : "") % (RCode::to_s(c.dh.rcode) + extra)).str() )) ;
if(limit && *limit==++num)
break;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
std::lock_guard<std::mutex> lock(g_rings.respMutex);
- g_rings.respRing.push_back({ts, ids->origRemote, ids->qname, ids->qtype, (unsigned int)udiff, (unsigned int)got, *dh});
+ g_rings.respRing.push_back({ts, ids->origRemote, ids->qname, ids->qtype, (unsigned int)udiff, (unsigned int)got, *dh, state->remote});
}
if(dh->rcode == RCode::ServFail)
g_stats.servfailResponses++;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
std::lock_guard<std::mutex> lock(g_rings.respMutex);
- g_rings.respRing.push_back({ts, ids.origRemote, ids.qname, ids.qtype, 0, 2000000, 0});
+ struct dnsheader fake;
+ memset(&fake, 0, sizeof(fake));
+ fake.id = ids.origID;
+ g_rings.respRing.push_back({ts, ids.origRemote, ids.qname, ids.qtype, std::numeric_limits<unsigned int>::max(), 0, fake, dss->remote});
}
}
}