#include "dnsdist-carbon.hh"
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
#ifndef DISABLE_CARBON
#include "dolog.hh"
const time_t now = time(nullptr);
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& entry : *entries) {
str << namespace_name << "." << hostname << "." << instance_name << "." << entry.d_name << ' ';
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
str << (*val)->load();
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
str << (*adval)->load();
}
- else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
str << **dval;
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
str << (*func)(entry.d_name);
}
str << ' ' << now << "\r\n";
*/
#include "dolog.hh"
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
#include "dnscrypt.hh"
#ifdef HAVE_DNSCRYPT
}
if (packet.size() < static_cast<uint16_t>(sizeof(struct dnsheader))) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
return false;
}
boost::format fmt("%-35s\t%+11s");
g_outputBuffer.clear();
- auto entries = *g_stats.entries.read_lock();
+ auto entries = *dnsdist::metrics::g_stats.entries.read_lock();
sort(entries.begin(), entries.end(),
[](const decltype(entries)::value_type& a, const decltype(entries)::value_type& b) {
return a.d_name < b.d_name;
boost::format flt(" %9.1f");
for (const auto& entry : entries) {
string second;
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
second = std::to_string((*val)->load());
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
second = (flt % (*adval)->load()).str();
}
- else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
second = (flt % (**dval)).str();
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
second = std::to_string((*func)(entry.d_name));
}
setLuaNoSideEffect();
std::unordered_map<string, uint64_t> res;
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
res.reserve(entries->size());
for (const auto& entry : *entries) {
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
res[entry.d_name] = (*val)->load();
}
}
#ifndef DISABLE_SECPOLL
luaCtx.writeFunction("showSecurityStatus", []() {
setLuaNoSideEffect();
- g_outputBuffer = std::to_string(g_stats.securityStatus) + "\n";
+ g_outputBuffer = std::to_string(dnsdist::metrics::g_stats.securityStatus) + "\n";
});
luaCtx.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
#include "dnsdist-snmp.hh"
+#include "dnsdist-metrics.hh"
#include "dolog.hh"
bool g_snmpEnabled{false};
static const oid specialMemoryUsageOID[] = { DNSDIST_STATS_OID, 39 };
static const oid ruleTruncatedOID[] = { DNSDIST_STATS_OID, 40 };
-static std::unordered_map<oid, DNSDistStats::entry_t> s_statsMap;
+static std::unordered_map<oid, dnsdist::metrics::Stats::entry_t> s_statsMap;
/* We are never called for a GETNEXT if it's registered as a
"instance", as it's "magically" handled for us. */
return SNMP_ERR_GENERR;
}
- if (const auto& val = boost::get<pdns::stat_t*>(&it->second)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&it->second)) {
return DNSDistSNMPAgent::setCounter64Value(requests, (*val)->load());
}
return SNMP_ERR_GENERR;
}
- if (const auto& val = boost::get<double*>(&it->second)) {
+ if (const auto& val = std::get_if<double*>(&it->second)) {
std::string str(std::to_string(**val));
snmp_set_var_typed_value(requests->requestvb,
ASN_OCTET_STR,
}
std::string str;
- uint64_t value = (*boost::get<DNSDistStats::statfunction_t>(&it->second))(str);
+ uint64_t value = (*std::get_if<dnsdist::metrics::Stats::statfunction_t>(&it->second))(str);
return DNSDistSNMPAgent::setCounter64Value(requests, value);
}
-static void registerGauge64Stat(const char* name, const oid statOID[], size_t statOIDLength, DNSDistStats::statfunction_t ptr)
+static void registerGauge64Stat(const char* name, const oid statOID[], size_t statOIDLength, dnsdist::metrics::Stats::statfunction_t ptr)
{
if (statOIDLength != OID_LENGTH(queriesOID)) {
errlog("Invalid OID for SNMP Gauge64 statistic %s", name);
{
#ifdef HAVE_NET_SNMP
- registerCounter64Stat("queries", queriesOID, OID_LENGTH(queriesOID), &g_stats.queries);
- registerCounter64Stat("responses", responsesOID, OID_LENGTH(responsesOID), &g_stats.responses);
- registerCounter64Stat("servfailResponses", servfailResponsesOID, OID_LENGTH(servfailResponsesOID), &g_stats.servfailResponses);
- registerCounter64Stat("aclDrops", aclDropsOID, OID_LENGTH(aclDropsOID), &g_stats.aclDrops);
- registerCounter64Stat("ruleDrop", ruleDropOID, OID_LENGTH(ruleDropOID), &g_stats.ruleDrop);
- registerCounter64Stat("ruleNXDomain", ruleNXDomainOID, OID_LENGTH(ruleNXDomainOID), &g_stats.ruleNXDomain);
- registerCounter64Stat("ruleRefused", ruleRefusedOID, OID_LENGTH(ruleRefusedOID), &g_stats.ruleRefused);
- registerCounter64Stat("ruleServFail", ruleServFailOID, OID_LENGTH(ruleServFailOID), &g_stats.ruleServFail);
- registerCounter64Stat("ruleTruncated", ruleTruncatedOID, OID_LENGTH(ruleTruncatedOID), &g_stats.ruleTruncated);
- registerCounter64Stat("selfAnswered", selfAnsweredOID, OID_LENGTH(selfAnsweredOID), &g_stats.selfAnswered);
- registerCounter64Stat("downstreamTimeouts", downstreamTimeoutsOID, OID_LENGTH(downstreamTimeoutsOID), &g_stats.downstreamTimeouts);
- registerCounter64Stat("downstreamSendErrors", downstreamSendErrorsOID, OID_LENGTH(downstreamSendErrorsOID), &g_stats.downstreamSendErrors);
- registerCounter64Stat("truncFail", truncFailOID, OID_LENGTH(truncFailOID), &g_stats.truncFail);
- registerCounter64Stat("noPolicy", noPolicyOID, OID_LENGTH(noPolicyOID), &g_stats.noPolicy);
- registerCounter64Stat("latency0_1", latency0_1OID, OID_LENGTH(latency0_1OID), &g_stats.latency0_1);
- registerCounter64Stat("latency1_10", latency1_10OID, OID_LENGTH(latency1_10OID), &g_stats.latency1_10);
- registerCounter64Stat("latency10_50", latency10_50OID, OID_LENGTH(latency10_50OID), &g_stats.latency10_50);
- registerCounter64Stat("latency50_100", latency50_100OID, OID_LENGTH(latency50_100OID), &g_stats.latency50_100);
- registerCounter64Stat("latency100_1000", latency100_1000OID, OID_LENGTH(latency100_1000OID), &g_stats.latency100_1000);
- registerCounter64Stat("latencySlow", latencySlowOID, OID_LENGTH(latencySlowOID), &g_stats.latencySlow);
- registerCounter64Stat("nonCompliantQueries", nonCompliantQueriesOID, OID_LENGTH(nonCompliantQueriesOID), &g_stats.nonCompliantQueries);
- registerCounter64Stat("nonCompliantResponses", nonCompliantResponsesOID, OID_LENGTH(nonCompliantResponsesOID), &g_stats.nonCompliantResponses);
- registerCounter64Stat("rdQueries", rdQueriesOID, OID_LENGTH(rdQueriesOID), &g_stats.rdQueries);
- registerCounter64Stat("emptyQueries", emptyQueriesOID, OID_LENGTH(emptyQueriesOID), &g_stats.emptyQueries);
- registerCounter64Stat("cacheHits", cacheHitsOID, OID_LENGTH(cacheHitsOID), &g_stats.cacheHits);
- registerCounter64Stat("cacheMisses", cacheMissesOID, OID_LENGTH(cacheMissesOID), &g_stats.cacheMisses);
- registerCounter64Stat("dynBlocked", dynBlockedOID, OID_LENGTH(dynBlockedOID), &g_stats.dynBlocked);
- registerFloatStat("latencyAvg100", latencyAvg100OID, OID_LENGTH(latencyAvg100OID), &g_stats.latencyAvg100);
- registerFloatStat("latencyAvg1000", latencyAvg1000OID, OID_LENGTH(latencyAvg1000OID), &g_stats.latencyAvg1000);
- registerFloatStat("latencyAvg10000", latencyAvg10000OID, OID_LENGTH(latencyAvg10000OID), &g_stats.latencyAvg10000);
- registerFloatStat("latencyAvg1000000", latencyAvg1000000OID, OID_LENGTH(latencyAvg1000000OID), &g_stats.latencyAvg1000000);
+ registerCounter64Stat("queries", queriesOID, OID_LENGTH(queriesOID), &dnsdist::metrics::g_stats.queries);
+ registerCounter64Stat("responses", responsesOID, OID_LENGTH(responsesOID), &dnsdist::metrics::g_stats.responses);
+ registerCounter64Stat("servfailResponses", servfailResponsesOID, OID_LENGTH(servfailResponsesOID), &dnsdist::metrics::g_stats.servfailResponses);
+ registerCounter64Stat("aclDrops", aclDropsOID, OID_LENGTH(aclDropsOID), &dnsdist::metrics::g_stats.aclDrops);
+ registerCounter64Stat("ruleDrop", ruleDropOID, OID_LENGTH(ruleDropOID), &dnsdist::metrics::g_stats.ruleDrop);
+ registerCounter64Stat("ruleNXDomain", ruleNXDomainOID, OID_LENGTH(ruleNXDomainOID), &dnsdist::metrics::g_stats.ruleNXDomain);
+ registerCounter64Stat("ruleRefused", ruleRefusedOID, OID_LENGTH(ruleRefusedOID), &dnsdist::metrics::g_stats.ruleRefused);
+ registerCounter64Stat("ruleServFail", ruleServFailOID, OID_LENGTH(ruleServFailOID), &dnsdist::metrics::g_stats.ruleServFail);
+ registerCounter64Stat("ruleTruncated", ruleTruncatedOID, OID_LENGTH(ruleTruncatedOID), &dnsdist::metrics::g_stats.ruleTruncated);
+ registerCounter64Stat("selfAnswered", selfAnsweredOID, OID_LENGTH(selfAnsweredOID), &dnsdist::metrics::g_stats.selfAnswered);
+ registerCounter64Stat("downstreamTimeouts", downstreamTimeoutsOID, OID_LENGTH(downstreamTimeoutsOID), &dnsdist::metrics::g_stats.downstreamTimeouts);
+ registerCounter64Stat("downstreamSendErrors", downstreamSendErrorsOID, OID_LENGTH(downstreamSendErrorsOID), &dnsdist::metrics::g_stats.downstreamSendErrors);
+ registerCounter64Stat("truncFail", truncFailOID, OID_LENGTH(truncFailOID), &dnsdist::metrics::g_stats.truncFail);
+ registerCounter64Stat("noPolicy", noPolicyOID, OID_LENGTH(noPolicyOID), &dnsdist::metrics::g_stats.noPolicy);
+ registerCounter64Stat("latency0_1", latency0_1OID, OID_LENGTH(latency0_1OID), &dnsdist::metrics::g_stats.latency0_1);
+ registerCounter64Stat("latency1_10", latency1_10OID, OID_LENGTH(latency1_10OID), &dnsdist::metrics::g_stats.latency1_10);
+ registerCounter64Stat("latency10_50", latency10_50OID, OID_LENGTH(latency10_50OID), &dnsdist::metrics::g_stats.latency10_50);
+ registerCounter64Stat("latency50_100", latency50_100OID, OID_LENGTH(latency50_100OID), &dnsdist::metrics::g_stats.latency50_100);
+ registerCounter64Stat("latency100_1000", latency100_1000OID, OID_LENGTH(latency100_1000OID), &dnsdist::metrics::g_stats.latency100_1000);
+ registerCounter64Stat("latencySlow", latencySlowOID, OID_LENGTH(latencySlowOID), &dnsdist::metrics::g_stats.latencySlow);
+ registerCounter64Stat("nonCompliantQueries", nonCompliantQueriesOID, OID_LENGTH(nonCompliantQueriesOID), &dnsdist::metrics::g_stats.nonCompliantQueries);
+ registerCounter64Stat("nonCompliantResponses", nonCompliantResponsesOID, OID_LENGTH(nonCompliantResponsesOID), &dnsdist::metrics::g_stats.nonCompliantResponses);
+ registerCounter64Stat("rdQueries", rdQueriesOID, OID_LENGTH(rdQueriesOID), &dnsdist::metrics::g_stats.rdQueries);
+ registerCounter64Stat("emptyQueries", emptyQueriesOID, OID_LENGTH(emptyQueriesOID), &dnsdist::metrics::g_stats.emptyQueries);
+ registerCounter64Stat("cacheHits", cacheHitsOID, OID_LENGTH(cacheHitsOID), &dnsdist::metrics::g_stats.cacheHits);
+ registerCounter64Stat("cacheMisses", cacheMissesOID, OID_LENGTH(cacheMissesOID), &dnsdist::metrics::g_stats.cacheMisses);
+ registerCounter64Stat("dynBlocked", dynBlockedOID, OID_LENGTH(dynBlockedOID), &dnsdist::metrics::g_stats.dynBlocked);
+ registerFloatStat("latencyAvg100", latencyAvg100OID, OID_LENGTH(latencyAvg100OID), &dnsdist::metrics::g_stats.latencyAvg100);
+ registerFloatStat("latencyAvg1000", latencyAvg1000OID, OID_LENGTH(latencyAvg1000OID), &dnsdist::metrics::g_stats.latencyAvg1000);
+ registerFloatStat("latencyAvg10000", latencyAvg10000OID, OID_LENGTH(latencyAvg10000OID), &dnsdist::metrics::g_stats.latencyAvg10000);
+ registerFloatStat("latencyAvg1000000", latencyAvg1000000OID, OID_LENGTH(latencyAvg1000000OID), &dnsdist::metrics::g_stats.latencyAvg1000000);
registerGauge64Stat("uptime", uptimeOID, OID_LENGTH(uptimeOID), &uptimeOfProcess);
registerGauge64Stat("specialMemoryUsage", specialMemoryUsageOID, OID_LENGTH(specialMemoryUsageOID), &getSpecialMemoryUsage);
registerGauge64Stat("cpuUserMSec", cpuUserMSecOID, OID_LENGTH(cpuUserMSecOID), &getCPUTimeUser);
registerGauge64Stat("cpuSysMSec", cpuSysMSecOID, OID_LENGTH(cpuSysMSecOID), &getCPUTimeSystem);
registerGauge64Stat("fdUsage", fdUsageOID, OID_LENGTH(fdUsageOID), &getOpenFileDescriptors);
registerGauge64Stat("dynBlockedNMGSize", dynBlockedNMGSizeOID, OID_LENGTH(dynBlockedNMGSizeOID), [](const std::string&) { return g_dynblockNMG.getLocal()->size(); });
- registerGauge64Stat("securityStatus", securityStatusOID, OID_LENGTH(securityStatusOID), [](const std::string&) { return g_stats.securityStatus.load(); });
+ registerGauge64Stat("securityStatus", securityStatusOID, OID_LENGTH(securityStatusOID), [](const std::string&) { return dnsdist::metrics::g_stats.securityStatus.load(); });
registerGauge64Stat("realMemoryUsage", realMemoryUsageOID, OID_LENGTH(realMemoryUsageOID), &getRealMemoryUsage);
}
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++state->d_ci.cs->responses;
queueResponse(state, now, std::move(response));
try {
auto ptr = std::make_unique<TCPCrossProtocolResponse>(std::move(response), state, now);
if (!state->d_threadData.crossProtocolResponseSender.send(std::move(ptr))) {
- ++g_stats.tcpCrossProtocolResponsePipeFull;
+ ++dnsdist::metrics::g_stats.tcpCrossProtocolResponsePipeFull;
vinfolog("Unable to pass a cross-protocol response to the TCP worker thread because the pipe is full");
}
}
static void handleQuery(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now)
{
if (state->d_querySize < sizeof(dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
++state->d_ci.cs->nonCompliantQueries;
state->terminateClientConnection();
return;
++state->d_queriesCount;
++state->d_ci.cs->queries;
- ++g_stats.queries;
+ ++dnsdist::metrics::g_stats.queries;
if (state->d_handler.isTLS()) {
auto tlsVersion = state->d_handler.getTLSVersion();
ssize_t remaining = isProxyHeaderComplete(state->d_buffer);
if (remaining == 0) {
vinfolog("Unable to consume proxy protocol header in packet from TCP client %s", state->d_ci.remote.toStringWithPort());
- ++g_stats.proxyProtocolInvalid;
+ ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
break;
}
else if (remaining < 0) {
}
if (!acl->match(remote)) {
- ++g_stats.aclDrops;
+ ++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Dropped TCP connection from %s because of ACL", remote.toStringWithPort());
return;
}
#include "dnsdist.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-healthchecks.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-prometheus.hh"
#include "dnsdist-web.hh"
#include "dolog.hh"
std::ostringstream output;
static const std::set<std::string> metricBlacklist = { "special-memory-usage", "latency-count", "latency-sum" };
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& entry : *entries) {
const auto& metricName = entry.d_name;
output << "# TYPE " << helpName << " " << prometheusTypeName << "\n";
output << prometheusMetricName << " ";
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
output << (*val)->load();
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
output << (*adval)->load();
}
- else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
output << **dval;
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
output << (*func)(entry.d_name);
}
// Latency histogram buckets
output << "# HELP dnsdist_latency Histogram of responses by latency (in milliseconds)\n";
output << "# TYPE dnsdist_latency histogram\n";
- uint64_t latency_amounts = g_stats.latency0_1;
+ uint64_t latency_amounts = dnsdist::metrics::g_stats.latency0_1;
output << "dnsdist_latency_bucket{le=\"1\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency1_10;
+ latency_amounts += dnsdist::metrics::g_stats.latency1_10;
output << "dnsdist_latency_bucket{le=\"10\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency10_50;
+ latency_amounts += dnsdist::metrics::g_stats.latency10_50;
output << "dnsdist_latency_bucket{le=\"50\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency50_100;
+ latency_amounts += dnsdist::metrics::g_stats.latency50_100;
output << "dnsdist_latency_bucket{le=\"100\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latency100_1000;
+ latency_amounts += dnsdist::metrics::g_stats.latency100_1000;
output << "dnsdist_latency_bucket{le=\"1000\"} " << latency_amounts << "\n";
- latency_amounts += g_stats.latencySlow; // Should be the same as latency_count
+ latency_amounts += dnsdist::metrics::g_stats.latencySlow; // Should be the same as latency_count
output << "dnsdist_latency_bucket{le=\"+Inf\"} " << latency_amounts << "\n";
- output << "dnsdist_latency_sum " << g_stats.latencySum << "\n";
- output << "dnsdist_latency_count " << g_stats.latencyCount << "\n";
+ output << "dnsdist_latency_sum " << dnsdist::metrics::g_stats.latencySum << "\n";
+ output << "dnsdist_latency_count " << dnsdist::metrics::g_stats.latencyCount << "\n";
auto states = g_dstates.getLocal();
const string statesbase = "dnsdist_server_";
static void addStatsToJSONObject(Json::object& obj)
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& entry : *entries) {
if (entry.d_name == "special-memory-usage") {
continue; // Too expensive for get-all
}
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
obj.emplace(entry.d_name, (double)(*val)->load());
- } else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&entry.d_value)) {
+ } else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&entry.d_value)) {
obj.emplace(entry.d_name, (*adval)->load());
- } else if (const auto& dval = boost::get<double*>(&entry.d_value)) {
+ } else if (const auto& dval = std::get_if<double*>(&entry.d_value)) {
obj.emplace(entry.d_name, (**dval));
- } else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&entry.d_value)) {
+ } else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&entry.d_value)) {
obj.emplace(entry.d_name, (double)(*func)(entry.d_name));
}
}
Json::array doc;
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
for (const auto& item : *entries) {
if (item.d_name == "special-memory-usage") {
continue; // Too expensive for get-all
}
- if (const auto& val = boost::get<pdns::stat_t*>(&item.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
{ "value", (double)(*val)->load() }
});
}
- else if (const auto& adval = boost::get<pdns::stat_t_trait<double>*>(&item.d_value)) {
+ else if (const auto& adval = std::get_if<pdns::stat_t_trait<double>*>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
{ "value", (*adval)->load() }
});
}
- else if (const auto& dval = boost::get<double*>(&item.d_value)) {
+ else if (const auto& dval = std::get_if<double*>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
{ "value", (**dval) }
});
}
- else if (const auto& func = boost::get<DNSDistStats::statfunction_t>(&item.d_value)) {
+ else if (const auto& func = std::get_if<dnsdist::metrics::Stats::statfunction_t>(&item.d_value)) {
doc.push_back(Json::object {
{ "type", "StatisticItem" },
{ "name", item.d_name },
bool g_verbose;
std::optional<std::ofstream> g_verboseStream{std::nullopt};
-struct DNSDistStats g_stats;
-
uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
uint32_t g_staleCacheEntriesTTL{0};
bool g_syslog{true};
}
catch(...)
{
- ++g_stats.truncFail;
+ ++dnsdist::metrics::g_stats.truncFail;
}
}
if (protocol == dnsdist::Protocol::DoUDP || protocol == dnsdist::Protocol::DNSCryptUDP) {
if (udiff < 1000) {
- ++g_stats.latency0_1;
+ ++dnsdist::metrics::g_stats.latency0_1;
}
else if (udiff < 10000) {
- ++g_stats.latency1_10;
+ ++dnsdist::metrics::g_stats.latency1_10;
}
else if (udiff < 50000) {
- ++g_stats.latency10_50;
+ ++dnsdist::metrics::g_stats.latency10_50;
}
else if (udiff < 100000) {
- ++g_stats.latency50_100;
+ ++dnsdist::metrics::g_stats.latency50_100;
}
else if (udiff < 1000000) {
- ++g_stats.latency100_1000;
+ ++dnsdist::metrics::g_stats.latency100_1000;
}
else {
- ++g_stats.latencySlow;
+ ++dnsdist::metrics::g_stats.latencySlow;
}
- g_stats.latencySum += udiff / 1000;
- ++g_stats.latencyCount;
+ dnsdist::metrics::g_stats.latencySum += udiff / 1000;
+ ++dnsdist::metrics::g_stats.latencyCount;
- doAvg(g_stats.latencyAvg100, udiff, 100);
- doAvg(g_stats.latencyAvg1000, udiff, 1000);
- doAvg(g_stats.latencyAvg10000, udiff, 10000);
- doAvg(g_stats.latencyAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyAvg1000000, udiff, 1000000);
}
else if (protocol == dnsdist::Protocol::DoTCP || protocol == dnsdist::Protocol::DNSCryptTCP) {
- doAvg(g_stats.latencyTCPAvg100, udiff, 100);
- doAvg(g_stats.latencyTCPAvg1000, udiff, 1000);
- doAvg(g_stats.latencyTCPAvg10000, udiff, 10000);
- doAvg(g_stats.latencyTCPAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyTCPAvg1000000, udiff, 1000000);
}
else if (protocol == dnsdist::Protocol::DoT) {
- doAvg(g_stats.latencyDoTAvg100, udiff, 100);
- doAvg(g_stats.latencyDoTAvg1000, udiff, 1000);
- doAvg(g_stats.latencyDoTAvg10000, udiff, 10000);
- doAvg(g_stats.latencyDoTAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoTAvg1000000, udiff, 1000000);
}
else if (protocol == dnsdist::Protocol::DoH) {
- doAvg(g_stats.latencyDoHAvg100, udiff, 100);
- doAvg(g_stats.latencyDoHAvg1000, udiff, 1000);
- doAvg(g_stats.latencyDoHAvg10000, udiff, 10000);
- doAvg(g_stats.latencyDoHAvg1000000, udiff, 1000000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg100, udiff, 100);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg1000, udiff, 1000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg10000, udiff, 10000);
+ doAvg(dnsdist::metrics::g_stats.latencyDoHAvg1000000, udiff, 1000000);
}
}
const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(response.data());
if (dh->qr == 0) {
- ++g_stats.nonCompliantResponses;
+ ++dnsdist::metrics::g_stats.nonCompliantResponses;
if (remote) {
++remote->nonCompliantResponses;
}
return true;
}
else {
- ++g_stats.nonCompliantResponses;
+ ++dnsdist::metrics::g_stats.nonCompliantResponses;
if (remote) {
++remote->nonCompliantResponses;
}
if (remote && response.size() > 0 && static_cast<size_t>(response.size()) > sizeof(dnsheader)) {
infolog("Backend %s sent us a response with id %d that did not parse: %s", remote->d_config.remote.toStringWithPort(), ntohs(dh->id), e.what());
}
- ++g_stats.nonCompliantResponses;
+ ++dnsdist::metrics::g_stats.nonCompliantResponses;
if (remote) {
++remote->nonCompliantResponses;
}
switch (cleartextDH.rcode) {
case RCode::NXDomain:
- ++g_stats.frontendNXDomain;
+ ++dnsdist::metrics::g_stats.frontendNXDomain;
break;
case RCode::ServFail:
if (fromBackend) {
- ++g_stats.servfailResponses;
+ ++dnsdist::metrics::g_stats.servfailResponses;
}
- ++g_stats.frontendServFail;
+ ++dnsdist::metrics::g_stats.frontendServFail;
break;
case RCode::NoError:
- ++g_stats.frontendNoError;
+ ++dnsdist::metrics::g_stats.frontendNoError;
break;
}
}
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
if (ids.cs) {
++ids.cs->responses;
}
return true;
break;
case DNSAction::Action::Drop:
- ++g_stats.ruleDrop;
+ ++dnsdist::metrics::g_stats.ruleDrop;
drop = true;
return true;
break;
dq.getHeader()->ra = dq.getHeader()->rd;
dq.getHeader()->aa = false;
dq.getHeader()->ad = false;
- ++g_stats.ruleTruncated;
+ ++dnsdist::metrics::g_stats.ruleTruncated;
return true;
}
break;
/* the Dynamic Block mechanism supports address and port ranges, so we need to pass the full address and port */
if (auto got = holders.dynNMGBlock->lookup(AddressAndPortRange(dq.ids.origRemote, dq.ids.origRemote.isIPv4() ? 32 : 128, 16))) {
auto updateBlockStats = [&got]() {
- ++g_stats.dynBlocked;
+ ++dnsdist::metrics::g_stats.dynBlocked;
got->second.blocks++;
};
if (auto got = holders.dynSMTBlock->lookup(dq.ids.qname)) {
auto updateBlockStats = [&got]() {
- ++g_stats.dynBlocked;
+ ++dnsdist::metrics::g_stats.dynBlocked;
got->blocks++;
};
/* message was too large for our buffer */
vinfolog("Dropping message too large for our buffer");
++cs.nonCompliantQueries;
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
return false;
}
expectProxyProtocol = expectProxyProtocolFrom(remote);
if (!holders.acl->match(remote) && !expectProxyProtocol) {
vinfolog("Query from %s dropped because of ACL", remote.toStringWithPort());
- ++g_stats.aclDrops;
+ ++dnsdist::metrics::g_stats.aclDrops;
return false;
}
}
++cs.queries;
- ++g_stats.queries;
+ ++dnsdist::metrics::g_stats.queries;
return true;
}
bool checkQueryHeaders(const struct dnsheader* dh, ClientState& cs)
{
if (dh->qr) { // don't respond to responses
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
++cs.nonCompliantQueries;
return false;
}
if (dh->qdcount == 0) {
- ++g_stats.emptyQueries;
+ ++dnsdist::metrics::g_stats.emptyQueries;
if (g_dropEmptyQueries) {
return false;
}
}
if (dh->rd) {
- ++g_stats.rdQueries;
+ ++dnsdist::metrics::g_stats.rdQueries;
}
return true;
}
if (cacheHit) {
- ++g_stats.cacheHits;
+ ++dnsdist::metrics::g_stats.cacheHits;
}
if (dr.isAsynchronous()) {
const auto rcode = dq.getHeader()->rcode;
if (rcode == RCode::NXDomain) {
- ++g_stats.ruleNXDomain;
+ ++dnsdist::metrics::g_stats.ruleNXDomain;
}
else if (rcode == RCode::Refused) {
- ++g_stats.ruleRefused;
+ ++dnsdist::metrics::g_stats.ruleRefused;
}
else if (rcode == RCode::ServFail) {
- ++g_stats.ruleServFail;
+ ++dnsdist::metrics::g_stats.ruleServFail;
}
- ++g_stats.selfAnswered;
+ ++dnsdist::metrics::g_stats.selfAnswered;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
return ProcessQueryResult::SendAnswer;
}
vinfolog("Packet cache miss for query for %s|%s from %s (%s, %d bytes)", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort(), dq.ids.protocol.toString(), dq.getData().size());
- ++g_stats.cacheMisses;
+ ++dnsdist::metrics::g_stats.cacheMisses;
}
if (!selectedBackend) {
- ++g_stats.noPolicy;
+ ++dnsdist::metrics::g_stats.noPolicy;
vinfolog("%s query for %s|%s from %s, no downstream server available", g_servFailOnNoPolicy ? "ServFailed" : "Dropped", dq.ids.qname.toLogString(), QType(dq.ids.qtype).toString(), dq.ids.origRemote.toStringWithPort());
if (g_servFailOnNoPolicy) {
if (!prepareOutgoingResponse(holders, *dq.ids.cs, dq, false)) {
return ProcessQueryResult::Drop;
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
++dq.ids.cs->responses;
// no response-only statistics counter to update.
return ProcessQueryResult::SendAnswer;
dq.ids.du->status_code = 502;
}
}
- ++g_stats.downstreamSendErrors;
+ ++dnsdist::metrics::g_stats.downstreamSendErrors;
++ds->sendErrors;
return false;
}
const ComboAddress& remote = recvData[msgIdx].remote;
if (static_cast<size_t>(got) < sizeof(struct dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
++cs->nonCompliantQueries;
continue;
}
ssize_t got = recvmsg(param.socket, &msgh, 0);
if (got < 0 || static_cast<size_t>(got) < sizeof(struct dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
++param.cs->nonCompliantQueries;
return;
}
using pdns::stat_t;
-struct DNSDistStats
-{
- stat_t responses{0};
- stat_t servfailResponses{0};
- stat_t queries{0};
- stat_t frontendNXDomain{0};
- stat_t frontendServFail{0};
- stat_t frontendNoError{0};
- stat_t nonCompliantQueries{0};
- stat_t nonCompliantResponses{0};
- stat_t rdQueries{0};
- stat_t emptyQueries{0};
- stat_t aclDrops{0};
- stat_t dynBlocked{0};
- stat_t ruleDrop{0};
- stat_t ruleNXDomain{0};
- stat_t ruleRefused{0};
- stat_t ruleServFail{0};
- stat_t ruleTruncated{0};
- stat_t selfAnswered{0};
- stat_t downstreamTimeouts{0};
- stat_t downstreamSendErrors{0};
- stat_t truncFail{0};
- stat_t noPolicy{0};
- stat_t cacheHits{0};
- stat_t cacheMisses{0};
- stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0}, latencySum{0}, latencyCount{0};
- stat_t securityStatus{0};
- stat_t dohQueryPipeFull{0};
- stat_t dohResponsePipeFull{0};
- stat_t outgoingDoHQueryPipeFull{0};
- stat_t proxyProtocolInvalid{0};
- stat_t tcpQueryPipeFull{0};
- stat_t tcpCrossProtocolQueryPipeFull{0};
- stat_t tcpCrossProtocolResponsePipeFull{0};
- double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
- double latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
- double latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
- double latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
- using statfunction_t = std::function<uint64_t(const std::string&)>;
- using entry_t = boost::variant<stat_t*, pdns::stat_t_trait<double>*, double*, statfunction_t>;
- struct EntryPair
- {
- std::string d_name;
- entry_t d_value;
- };
-
- SharedLockGuarded<std::vector<EntryPair>> entries{std::vector<EntryPair>{
- {"responses", &responses},
- {"servfail-responses", &servfailResponses},
- {"queries", &queries},
- {"frontend-nxdomain", &frontendNXDomain},
- {"frontend-servfail", &frontendServFail},
- {"frontend-noerror", &frontendNoError},
- {"acl-drops", &aclDrops},
- {"rule-drop", &ruleDrop},
- {"rule-nxdomain", &ruleNXDomain},
- {"rule-refused", &ruleRefused},
- {"rule-servfail", &ruleServFail},
- {"rule-truncated", &ruleTruncated},
- {"self-answered", &selfAnswered},
- {"downstream-timeouts", &downstreamTimeouts},
- {"downstream-send-errors", &downstreamSendErrors},
- {"trunc-failures", &truncFail},
- {"no-policy", &noPolicy},
- {"latency0-1", &latency0_1},
- {"latency1-10", &latency1_10},
- {"latency10-50", &latency10_50},
- {"latency50-100", &latency50_100},
- {"latency100-1000", &latency100_1000},
- {"latency-slow", &latencySlow},
- {"latency-avg100", &latencyAvg100},
- {"latency-avg1000", &latencyAvg1000},
- {"latency-avg10000", &latencyAvg10000},
- {"latency-avg1000000", &latencyAvg1000000},
- {"latency-tcp-avg100", &latencyTCPAvg100},
- {"latency-tcp-avg1000", &latencyTCPAvg1000},
- {"latency-tcp-avg10000", &latencyTCPAvg10000},
- {"latency-tcp-avg1000000", &latencyTCPAvg1000000},
- {"latency-dot-avg100", &latencyDoTAvg100},
- {"latency-dot-avg1000", &latencyDoTAvg1000},
- {"latency-dot-avg10000", &latencyDoTAvg10000},
- {"latency-dot-avg1000000", &latencyDoTAvg1000000},
- {"latency-doh-avg100", &latencyDoHAvg100},
- {"latency-doh-avg1000", &latencyDoHAvg1000},
- {"latency-doh-avg10000", &latencyDoHAvg10000},
- {"latency-doh-avg1000000", &latencyDoHAvg1000000},
- {"uptime", uptimeOfProcess},
- {"real-memory-usage", getRealMemoryUsage},
- {"special-memory-usage", getSpecialMemoryUsage},
- {"udp-in-errors", std::bind(udpErrorStats, "udp-in-errors")},
- {"udp-noport-errors", std::bind(udpErrorStats, "udp-noport-errors")},
- {"udp-recvbuf-errors", std::bind(udpErrorStats, "udp-recvbuf-errors")},
- {"udp-sndbuf-errors", std::bind(udpErrorStats, "udp-sndbuf-errors")},
- {"udp-in-csum-errors", std::bind(udpErrorStats, "udp-in-csum-errors")},
- {"udp6-in-errors", std::bind(udp6ErrorStats, "udp6-in-errors")},
- {"udp6-recvbuf-errors", std::bind(udp6ErrorStats, "udp6-recvbuf-errors")},
- {"udp6-sndbuf-errors", std::bind(udp6ErrorStats, "udp6-sndbuf-errors")},
- {"udp6-noport-errors", std::bind(udp6ErrorStats, "udp6-noport-errors")},
- {"udp6-in-csum-errors", std::bind(udp6ErrorStats, "udp6-in-csum-errors")},
- {"tcp-listen-overflows", std::bind(tcpErrorStats, "ListenOverflows")},
- {"noncompliant-queries", &nonCompliantQueries},
- {"noncompliant-responses", &nonCompliantResponses},
- {"proxy-protocol-invalid", &proxyProtocolInvalid},
- {"rdqueries", &rdQueries},
- {"empty-queries", &emptyQueries},
- {"cache-hits", &cacheHits},
- {"cache-misses", &cacheMisses},
- {"cpu-iowait", getCPUIOWait},
- {"cpu-steal", getCPUSteal},
- {"cpu-sys-msec", getCPUTimeSystem},
- {"cpu-user-msec", getCPUTimeUser},
- {"fd-usage", getOpenFileDescriptors},
- {"dyn-blocked", &dynBlocked},
- {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }},
- {"security-status", &securityStatus},
- {"doh-query-pipe-full", &dohQueryPipeFull},
- {"doh-response-pipe-full", &dohResponsePipeFull},
- {"outgoing-doh-query-pipe-full", &outgoingDoHQueryPipeFull},
- {"tcp-query-pipe-full", &tcpQueryPipeFull},
- {"tcp-cross-protocol-query-pipe-full", &tcpCrossProtocolQueryPipeFull},
- {"tcp-cross-protocol-response-pipe-full", &tcpCrossProtocolResponsePipeFull},
- // Latency histogram
- {"latency-sum", &latencySum},
- {"latency-count", &latencyCount},
- }};
- struct MutableCounter
- {
- MutableCounter() = default;
- MutableCounter(MutableCounter&& rhs): d_value(rhs.d_value.load())
- {
- }
-
- mutable stat_t d_value{0};
- };
- struct MutableGauge
- {
- MutableGauge() = default;
- MutableGauge(MutableGauge&& rhs): d_value(rhs.d_value.load())
- {
- }
-
- mutable pdns::stat_t_trait<double> d_value{0};
- };
- SharedLockGuarded<std::map<std::string, MutableCounter, std::less<>>> customCounters;
- SharedLockGuarded<std::map<std::string, MutableGauge, std::less<>>> customGauges;
-};
-
-extern struct DNSDistStats g_stats;
-
class BasicQPSLimiter
{
public:
*/
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-nghttp2.hh"
#include "dnsdist-random.hh"
#include "dnsdist-rings.hh"
handleDOHTimeout(std::move(ids.internal.du));
++reuseds;
--outstanding;
- ++g_stats.downstreamTimeouts; // this is an 'actively' discovered timeout
+ ++dnsdist::metrics::g_stats.downstreamTimeouts; // this is an 'actively' discovered timeout
vinfolog("Had a downstream timeout from %s (%s) for query for %s|%s from %s",
d_config.remote.toStringWithPort(), getName(),
ids.internal.qname.toLogString(), QType(ids.internal.qtype).toString(), ids.internal.origRemote.toStringWithPort());
auto oldDU = std::move(it->second.internal.du);
++reuseds;
- ++g_stats.downstreamTimeouts;
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
handleDOHTimeout(std::move(oldDU));
}
else {
to handle it because it's about to be overwritten. */
auto oldDU = std::move(ids.internal.du);
++reuseds;
- ++g_stats.downstreamTimeouts;
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
handleDOHTimeout(std::move(oldDU));
}
else {
if (!inserted) {
/* already used */
++reuseds;
- ++g_stats.downstreamTimeouts;
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
handleDOHTimeout(std::move(state.du));
}
else {
if (!guard) {
/* already used */
++reuseds;
- ++g_stats.downstreamTimeouts;
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
handleDOHTimeout(std::move(state.du));
return;
}
if (ids.isInUse()) {
/* already used */
++reuseds;
- ++g_stats.downstreamTimeouts;
+ ++dnsdist::metrics::g_stats.downstreamTimeouts;
handleDOHTimeout(std::move(state.du));
return;
}
#include "dnsdist.hh"
#include "dnsdist-dynblocks.hh"
+#include "dnsdist-metrics.hh"
GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
updated.erase(entry);
}
g_dynblockNMG.setState(std::move(updated));
- g_stats.dynBlocked += bpfBlocked;
+ dnsdist::metrics::g_stats.dynBlocked += bpfBlocked;
}
}
namespace dnsdist::metrics {
+struct MutableCounter
+{
+ MutableCounter() = default;
+ MutableCounter(MutableCounter&& rhs): d_value(rhs.d_value.load())
+ {
+ }
+
+ mutable stat_t d_value{0};
+};
+
+struct MutableGauge
+{
+ MutableGauge() = default;
+ MutableGauge(MutableGauge&& rhs): d_value(rhs.d_value.load())
+ {
+ }
+
+ mutable pdns::stat_t_trait<double> d_value{0};
+};
+
+static SharedLockGuarded<std::map<std::string, MutableCounter, std::less<>>> s_customCounters;
+static SharedLockGuarded<std::map<std::string, MutableGauge, std::less<>>> s_customGauges;
+
+Stats::Stats(): entries{std::vector<EntryPair>{
+ {"responses", &responses},
+ {"servfail-responses", &servfailResponses},
+ {"queries", &queries},
+ {"frontend-nxdomain", &frontendNXDomain},
+ {"frontend-servfail", &frontendServFail},
+ {"frontend-noerror", &frontendNoError},
+ {"acl-drops", &aclDrops},
+ {"rule-drop", &ruleDrop},
+ {"rule-nxdomain", &ruleNXDomain},
+ {"rule-refused", &ruleRefused},
+ {"rule-servfail", &ruleServFail},
+ {"rule-truncated", &ruleTruncated},
+ {"self-answered", &selfAnswered},
+ {"downstream-timeouts", &downstreamTimeouts},
+ {"downstream-send-errors", &downstreamSendErrors},
+ {"trunc-failures", &truncFail},
+ {"no-policy", &noPolicy},
+ {"latency0-1", &latency0_1},
+ {"latency1-10", &latency1_10},
+ {"latency10-50", &latency10_50},
+ {"latency50-100", &latency50_100},
+ {"latency100-1000", &latency100_1000},
+ {"latency-slow", &latencySlow},
+ {"latency-avg100", &latencyAvg100},
+ {"latency-avg1000", &latencyAvg1000},
+ {"latency-avg10000", &latencyAvg10000},
+ {"latency-avg1000000", &latencyAvg1000000},
+ {"latency-tcp-avg100", &latencyTCPAvg100},
+ {"latency-tcp-avg1000", &latencyTCPAvg1000},
+ {"latency-tcp-avg10000", &latencyTCPAvg10000},
+ {"latency-tcp-avg1000000", &latencyTCPAvg1000000},
+ {"latency-dot-avg100", &latencyDoTAvg100},
+ {"latency-dot-avg1000", &latencyDoTAvg1000},
+ {"latency-dot-avg10000", &latencyDoTAvg10000},
+ {"latency-dot-avg1000000", &latencyDoTAvg1000000},
+ {"latency-doh-avg100", &latencyDoHAvg100},
+ {"latency-doh-avg1000", &latencyDoHAvg1000},
+ {"latency-doh-avg10000", &latencyDoHAvg10000},
+ {"latency-doh-avg1000000", &latencyDoHAvg1000000},
+ {"uptime", uptimeOfProcess},
+ {"real-memory-usage", getRealMemoryUsage},
+ {"special-memory-usage", getSpecialMemoryUsage},
+ {"udp-in-errors", std::bind(udpErrorStats, "udp-in-errors")},
+ {"udp-noport-errors", std::bind(udpErrorStats, "udp-noport-errors")},
+ {"udp-recvbuf-errors", std::bind(udpErrorStats, "udp-recvbuf-errors")},
+ {"udp-sndbuf-errors", std::bind(udpErrorStats, "udp-sndbuf-errors")},
+ {"udp-in-csum-errors", std::bind(udpErrorStats, "udp-in-csum-errors")},
+ {"udp6-in-errors", std::bind(udp6ErrorStats, "udp6-in-errors")},
+ {"udp6-recvbuf-errors", std::bind(udp6ErrorStats, "udp6-recvbuf-errors")},
+ {"udp6-sndbuf-errors", std::bind(udp6ErrorStats, "udp6-sndbuf-errors")},
+ {"udp6-noport-errors", std::bind(udp6ErrorStats, "udp6-noport-errors")},
+ {"udp6-in-csum-errors", std::bind(udp6ErrorStats, "udp6-in-csum-errors")},
+ {"tcp-listen-overflows", std::bind(tcpErrorStats, "ListenOverflows")},
+ {"noncompliant-queries", &nonCompliantQueries},
+ {"noncompliant-responses", &nonCompliantResponses},
+ {"proxy-protocol-invalid", &proxyProtocolInvalid},
+ {"rdqueries", &rdQueries},
+ {"empty-queries", &emptyQueries},
+ {"cache-hits", &cacheHits},
+ {"cache-misses", &cacheMisses},
+ {"cpu-iowait", getCPUIOWait},
+ {"cpu-steal", getCPUSteal},
+ {"cpu-sys-msec", getCPUTimeSystem},
+ {"cpu-user-msec", getCPUTimeUser},
+ {"fd-usage", getOpenFileDescriptors},
+ {"dyn-blocked", &dynBlocked},
+ {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }},
+ {"security-status", &securityStatus},
+ {"doh-query-pipe-full", &dohQueryPipeFull},
+ {"doh-response-pipe-full", &dohResponsePipeFull},
+ {"outgoing-doh-query-pipe-full", &outgoingDoHQueryPipeFull},
+ {"tcp-query-pipe-full", &tcpQueryPipeFull},
+ {"tcp-cross-protocol-query-pipe-full", &tcpCrossProtocolQueryPipeFull},
+ {"tcp-cross-protocol-response-pipe-full", &tcpCrossProtocolResponsePipeFull},
+ // Latency histogram
+ {"latency-sum", &latencySum},
+ {"latency-count", &latencyCount},
+ }}
+{
+}
+
+struct Stats g_stats;
+
std::optional<std::string> declareCustomMetric(const std::string& name, const std::string& type, const std::string& description, std::optional<std::string> customName)
{
if (!std::regex_match(name, std::regex("^[a-z0-9-]+$"))) {
}
if (type == "counter") {
- auto customCounters = g_stats.customCounters.write_lock();
- auto itp = customCounters->insert({name, DNSDistStats::MutableCounter()});
+ auto customCounters = s_customCounters.write_lock();
+ auto itp = customCounters->insert({name, MutableCounter()});
if (itp.second) {
- g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customCounters)[name].d_value});
+ g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customCounters)[name].d_value});
addMetricDefinition(name, "counter", description, customName ? *customName : "");
}
}
else if (type == "gauge") {
- auto customGauges = g_stats.customGauges.write_lock();
- auto itp = customGauges->insert({name, DNSDistStats::MutableGauge()});
+ auto customGauges = s_customGauges.write_lock();
+ auto itp = customGauges->insert({name, MutableGauge()});
if (itp.second) {
- g_stats.entries.write_lock()->emplace_back(DNSDistStats::EntryPair{name, &(*customGauges)[name].d_value});
+ g_stats.entries.write_lock()->emplace_back(Stats::EntryPair{name, &(*customGauges)[name].d_value});
addMetricDefinition(name, "gauge", description, customName ? *customName : "");
}
}
std::variant<uint64_t, Error> incrementCustomCounter(const std::string_view& name, uint64_t step)
{
- auto customCounters = g_stats.customCounters.read_lock();
+ auto customCounters = s_customCounters.read_lock();
auto metric = customCounters->find(name);
if (metric != customCounters->end()) {
if (step) {
std::variant<uint64_t, Error> decrementCustomCounter(const std::string_view& name, uint64_t step)
{
- auto customCounters = g_stats.customCounters.read_lock();
+ auto customCounters = s_customCounters.read_lock();
auto metric = customCounters->find(name);
if (metric != customCounters->end()) {
if (step) {
std::variant<double, Error> setCustomGauge(const std::string_view& name, const double value)
{
- auto customGauges = g_stats.customGauges.read_lock();
+ auto customGauges = s_customGauges.read_lock();
auto metric = customGauges->find(name);
if (metric != customGauges->end()) {
metric->second.d_value = value;
std::variant<double, Error> getCustomMetric(const std::string_view& name)
{
{
- auto customCounters = g_stats.customCounters.read_lock();
+ auto customCounters = s_customCounters.read_lock();
auto counter = customCounters->find(name);
if (counter != customCounters->end()) {
return static_cast<double>(counter->second.d_value.load());
}
}
{
- auto customGauges = g_stats.customGauges.read_lock();
+ auto customGauges = s_customGauges.read_lock();
auto gauge = customGauges->find(name);
if (gauge != customGauges->end()) {
return gauge->second.d_value.load();
}
return std::string("Unable to get metric '") + std::string(name) + "': no such metric";
}
+
}
#include <string_view>
#include <variant>
+#include "lock.hh"
+#include "stat_t.hh"
+
namespace dnsdist::metrics
{
- using Error = std::string;
+using Error = std::string;
+
+[[nodiscard]] std::optional<Error> declareCustomMetric(const std::string& name, const std::string& type, const std::string& description, std::optional<std::string> customName);
+[[nodiscard]] std::variant<uint64_t, Error> incrementCustomCounter(const std::string_view& name, uint64_t step);
+[[nodiscard]] std::variant<uint64_t, Error> decrementCustomCounter(const std::string_view& name, uint64_t step);
+[[nodiscard]] std::variant<double, Error> setCustomGauge(const std::string_view& name, const double value);
+[[nodiscard]] std::variant<double, Error> getCustomMetric(const std::string_view& name);
+
+using pdns::stat_t;
+
+struct Stats
+{
+ Stats();
+
+ stat_t responses{0};
+ stat_t servfailResponses{0};
+ stat_t queries{0};
+ stat_t frontendNXDomain{0};
+ stat_t frontendServFail{0};
+ stat_t frontendNoError{0};
+ stat_t nonCompliantQueries{0};
+ stat_t nonCompliantResponses{0};
+ stat_t rdQueries{0};
+ stat_t emptyQueries{0};
+ stat_t aclDrops{0};
+ stat_t dynBlocked{0};
+ stat_t ruleDrop{0};
+ stat_t ruleNXDomain{0};
+ stat_t ruleRefused{0};
+ stat_t ruleServFail{0};
+ stat_t ruleTruncated{0};
+ stat_t selfAnswered{0};
+ stat_t downstreamTimeouts{0};
+ stat_t downstreamSendErrors{0};
+ stat_t truncFail{0};
+ stat_t noPolicy{0};
+ stat_t cacheHits{0};
+ stat_t cacheMisses{0};
+ stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0}, latencySum{0}, latencyCount{0};
+ stat_t securityStatus{0};
+ stat_t dohQueryPipeFull{0};
+ stat_t dohResponsePipeFull{0};
+ stat_t outgoingDoHQueryPipeFull{0};
+ stat_t proxyProtocolInvalid{0};
+ stat_t tcpQueryPipeFull{0};
+ stat_t tcpCrossProtocolQueryPipeFull{0};
+ stat_t tcpCrossProtocolResponsePipeFull{0};
+ double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
+ double latencyTCPAvg100{0}, latencyTCPAvg1000{0}, latencyTCPAvg10000{0}, latencyTCPAvg1000000{0};
+ double latencyDoTAvg100{0}, latencyDoTAvg1000{0}, latencyDoTAvg10000{0}, latencyDoTAvg1000000{0};
+ double latencyDoHAvg100{0}, latencyDoHAvg1000{0}, latencyDoHAvg10000{0}, latencyDoHAvg1000000{0};
+ using statfunction_t = std::function<uint64_t(const std::string&)>;
+ using entry_t = std::variant<stat_t*, pdns::stat_t_trait<double>*, double*, statfunction_t>;
+ struct EntryPair
+ {
+ std::string d_name;
+ entry_t d_value;
+ };
+
+ SharedLockGuarded<std::vector<EntryPair>> entries;
+};
- [[nodiscard]] std::optional<Error> declareCustomMetric(const std::string& name, const std::string& type, const std::string& description, std::optional<std::string> customName);
- [[nodiscard]] std::variant<uint64_t, Error> incrementCustomCounter(const std::string_view& name, uint64_t step);
- [[nodiscard]] std::variant<uint64_t, Error> decrementCustomCounter(const std::string_view& name, uint64_t step);
- [[nodiscard]] std::variant<double, Error> setCustomGauge(const std::string_view& name, const double value);
- [[nodiscard]] std::variant<double, Error> getCustomMetric(const std::string_view& name);
+extern struct Stats g_stats;
}
uint64_t pos = d_pos++;
if (!d_clientThreads.at(pos % d_numberOfThreads).d_sender.send(std::move(cpq))) {
- ++g_stats.outgoingDoHQueryPipeFull;
+ ++dnsdist::metrics::g_stats.outgoingDoHQueryPipeFull;
return false;
}
*/
#include "dnsdist-proxy-protocol.hh"
+#include "dnsdist-metrics.hh"
#include "dolog.hh"
NetmaskGroup g_proxyProtocolACL;
ssize_t used = parseProxyHeader(query, proxyProto, realRemote, realDestination, tcp, values);
if (used <= 0) {
- ++g_stats.proxyProtocolInvalid;
+ ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
vinfolog("Ignoring invalid proxy protocol (%d, %d) query over %s from %s", query.size(), used, (isTCP ? "TCP" : "UDP"), remote.toStringWithPort());
return false;
}
else if (static_cast<size_t>(used) > g_proxyProtocolMaximumSize) {
vinfolog("Proxy protocol header in %s packet from %s is larger than proxy-protocol-maximum-size (%d), dropping", (isTCP ? "TCP" : "UDP"), remote.toStringWithPort(), used);
- ++g_stats.proxyProtocolInvalid;
+ ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
return false;
}
/* on TCP we have not read the actual query yet */
if (!isTCP && query.size() < sizeof(struct dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
return false;
}
if (proxyProto && g_applyACLToProxiedClients) {
if (!acl.match(realRemote)) {
vinfolog("Query from %s dropped because of ACL", realRemote.toStringWithPort());
- ++g_stats.aclDrops;
+ ++dnsdist::metrics::g_stats.aclDrops;
return false;
}
}
#include "sstuff.hh"
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-random.hh"
#ifndef PACKAGEVERSION
errlog("PowerDNS DNSDist Security Update Mandatory: %s", securityMessage);
}
- g_stats.securityStatus = securityStatus;
+ dnsdist::metrics::g_stats.securityStatus = securityStatus;
g_secPollDone = true;
return;
}
#include "channel.hh"
#include "iputils.hh"
#include "dnsdist.hh"
+#include "dnsdist-metrics.hh"
struct ConnectionInfo
{
++d_queued;
if (!d_tcpclientthreads.at(pos % d_numthreads).d_querySender.send(std::move(conn))) {
--d_queued;
- ++g_stats.tcpQueryPipeFull;
+ ++dnsdist::metrics::g_stats.tcpQueryPipeFull;
return false;
}
uint64_t pos = d_pos++;
if (!d_tcpclientthreads.at(pos % d_numthreads).d_crossProtocolQuerySender.send(std::move(cpq))) {
- ++g_stats.tcpCrossProtocolQueryPipeFull;
+ ++dnsdist::metrics::g_stats.tcpCrossProtocolQueryPipeFull;
return false;
}
#include "dolog.hh"
#include "dnsdist-concurrent-connections.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-metrics.hh"
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-rules.hh"
#include "dnsdist-xpf.hh"
}
try {
if (!du->responseSender->send(std::move(du))) {
- ++g_stats.dohResponsePipeFull;
+ ++dnsdist::metrics::g_stats.dohResponsePipeFull;
vinfolog("Unable to pass a %s to the DoH worker thread because the pipe is full", description);
}
} catch (const std::exception& e) {
handleResponseSent(du->ids, udiff, du->ids.origRemote, du->downstream->d_config.remote, du->response.size(), cleartextDH, backendProtocol, true);
}
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
if (du->ids.cs) {
++du->ids.cs->responses;
}
ClientState& cs = *dsc->cs;
if (du->query.size() < sizeof(dnsheader)) {
- ++g_stats.nonCompliantQueries;
+ ++dnsdist::metrics::g_stats.nonCompliantQueries;
++cs.nonCompliantQueries;
du->status_code = 400;
handleImmediateResponse(std::move(du), "DoH non-compliant query");
}
++cs.queries;
- ++g_stats.queries;
+ ++dnsdist::metrics::g_stats.queries;
du->ids.queryRealTime.start();
{
#else /* USE_SINGLE_ACCEPTOR_THREAD */
try {
if (!dsc->d_querySender.send(std::move(du))) {
- ++g_stats.dohQueryPipeFull;
+ ++dnsdist::metrics::g_stats.dohQueryPipeFull;
vinfolog("Unable to pass a DoH query to the DoH worker thread because the pipe is full");
h2o_send_error_500(req, "Internal Server Error", "Internal Server Error", 0);
}
auto& holders = dsc->holders;
if (!holders.acl->match(conn.d_remote)) {
- ++g_stats.aclDrops;
+ ++dnsdist::metrics::g_stats.aclDrops;
vinfolog("Query from %s (DoH) dropped because of ACL", conn.d_remote.toStringWithPort());
h2o_send_error_403(req, "Forbidden", "dns query not allowed because of ACL", 0);
return 0;
handleResponseSent(du->ids, udiff, dr.ids.origRemote, du->downstream->d_config.remote, du->response.size(), cleartextDH, du->downstream->getProtocol(), true);
- ++g_stats.responses;
+ ++dnsdist::metrics::g_stats.responses;
if (du->ids.cs) {
++du->ids.cs->responses;
}
#include "dnsdist-tcp-downstream.hh"
#include "dnsdist-tcp-upstream.hh"
-struct DNSDistStats g_stats;
GlobalStateHolder<NetmaskGroup> g_ACL;
GlobalStateHolder<vector<DNSDistRuleAction> > g_ruleactions;
GlobalStateHolder<vector<DNSDistResponseRuleAction> > g_respruleactions;