diff options
Diffstat (limited to 'dnsdist-web.cc')
-rw-r--r-- | dnsdist-web.cc | 229 |
1 files changed, 175 insertions, 54 deletions
diff --git a/dnsdist-web.cc b/dnsdist-web.cc index 16e1164..066b5c1 100644 --- a/dnsdist-web.cc +++ b/dnsdist-web.cc @@ -34,7 +34,9 @@ #include "dnsdist.hh" #include "dnsdist-dynblocks.hh" #include "dnsdist-healthchecks.hh" +#include "dnsdist-metrics.hh" #include "dnsdist-prometheus.hh" +#include "dnsdist-rings.hh" #include "dnsdist-web.hh" #include "dolog.hh" #include "gettime.hh" @@ -175,6 +177,10 @@ std::map<std::string, MetricDefinition> MetricDefinitionStorage::metrics{ { "latency-doh-avg1000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000 packets received over DoH")}, { "latency-doh-avg10000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 10000 packets received over DoH")}, { "latency-doh-avg1000000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000000 packets received over DoH")}, + { "latency-doq-avg100", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 100 packets received over DoQ")}, + { "latency-doq-avg1000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000 packets received over DoQ")}, + { "latency-doq-avg10000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 10000 packets received over DoQ")}, + { "latency-doq-avg1000000", MetricDefinition(PrometheusMetricType::gauge, "Average response latency, in microseconds, of the last 1000000 packets received over DoQ")}, { "uptime", MetricDefinition(PrometheusMetricType::gauge, "Uptime of the dnsdist process in seconds")}, { "real-memory-usage", MetricDefinition(PrometheusMetricType::gauge, "Current memory usage in bytes")}, { "noncompliant-queries", MetricDefinition(PrometheusMetricType::counter, "Number of queries dropped as non-compliant")}, @@ -212,9 +218,9 @@ std::map<std::string, MetricDefinition> MetricDefinitionStorage::metrics{ }; #endif /* DISABLE_PROMETHEUS */ -bool addMetricDefinition(const std::string& name, const std::string& type, const std::string& description, const std::string& customName) { +bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition& def) { #ifndef DISABLE_PROMETHEUS - return MetricDefinitionStorage::addMetricDefinition(name, type, description, customName); + return MetricDefinitionStorage::addMetricDefinition(def); #else return true; #endif /* DISABLE_PROMETHEUS */ @@ -224,7 +230,7 @@ bool addMetricDefinition(const std::string& name, const std::string& type, const static bool apiWriteConfigFile(const string& filebasename, const string& content) { if (!g_apiReadWrite) { - errlog("Not writing content to %s since the API is read-only", filebasename); + warnlog("Not writing content to %s since the API is read-only", filebasename); return false; } @@ -247,15 +253,14 @@ static bool apiWriteConfigFile(const string& filebasename, const string& content static void apiSaveACL(const NetmaskGroup& nmg) { - vector<string> vec; - nmg.toStringVector(&vec); + auto aclEntries = nmg.toStringVector(); string acl; - for(const auto& s : vec) { + for (const auto& entry : aclEntries) { if (!acl.empty()) { acl += ", "; } - acl += "\"" + s + "\""; + acl += "\"" + entry + "\""; } string content = "setACL({" + acl + "})"; @@ -468,7 +473,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) 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; @@ -504,16 +509,16 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) 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); } @@ -524,20 +529,20 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) // 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_"; @@ -592,6 +597,18 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) output << "# TYPE " << statesbase << "tlsresumptions " << "counter" << "\n"; output << "# HELP " << statesbase << "tcplatency " << "Server's latency when answering TCP questions in milliseconds" << "\n"; output << "# TYPE " << statesbase << "tcplatency " << "gauge" << "\n"; + output << "# HELP " << statesbase << "healthcheckfailures " << "Number of health check attempts that failed (total)" << "\n"; + output << "# TYPE " << statesbase << "healthcheckfailures " << "counter" << "\n"; + output << "# HELP " << statesbase << "healthcheckfailuresparsing " << "Number of health check attempts where the response could not be parsed" << "\n"; + output << "# TYPE " << statesbase << "healthcheckfailuresparsing " << "counter" << "\n"; + output << "# HELP " << statesbase << "healthcheckfailurestimeout " << "Number of health check attempts where the response did not arrive in time" << "\n"; + output << "# TYPE " << statesbase << "healthcheckfailurestimeout " << "counter" << "\n"; + output << "# HELP " << statesbase << "healthcheckfailuresnetwork " << "Number of health check attempts that experienced a network issue" << "\n"; + output << "# TYPE " << statesbase << "healthcheckfailuresnetwork " << "counter" << "\n"; + output << "# HELP " << statesbase << "healthcheckfailuresmismatch " << "Number of health check attempts where the response did not match the query" << "\n"; + output << "# TYPE " << statesbase << "healthcheckfailuresmismatch " << "counter" << "\n"; + output << "# HELP " << statesbase << "healthcheckfailuresinvalid " << "Number of health check attempts where the DNS response was invalid" << "\n"; + output << "# TYPE " << statesbase << "healthcheckfailuresinvalid " << "counter" << "\n"; for (const auto& state : *states) { string serverName; @@ -635,6 +652,12 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) output << statesbase << "tcpavgqueriesperconn" << label << " " << state->tcpAvgQueriesPerConnection << "\n"; output << statesbase << "tcpavgconnduration" << label << " " << state->tcpAvgConnectionDuration << "\n"; output << statesbase << "tlsresumptions" << label << " " << state->tlsResumptions << "\n"; + output << statesbase << "healthcheckfailures" << label << " " << state->d_healthCheckMetrics.d_failures << "\n"; + output << statesbase << "healthcheckfailuresparsing" << label << " " << state->d_healthCheckMetrics.d_parseErrors << "\n"; + output << statesbase << "healthcheckfailurestimeout" << label << " " << state->d_healthCheckMetrics.d_timeOuts << "\n"; + output << statesbase << "healthcheckfailuresnetwork" << label << " " << state->d_healthCheckMetrics.d_networkErrors << "\n"; + output << statesbase << "healthcheckfailuresmismatch" << label << " " << state->d_healthCheckMetrics.d_mismatchErrors << "\n"; + output << statesbase << "healthcheckfailuresinvalid" << label << " " << state->d_healthCheckMetrics.d_invalidResponseErrors << "\n"; } const string frontsbase = "dnsdist_frontend_"; @@ -650,8 +673,8 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) output << "# TYPE " << frontsbase << "tcpdiedsendingresponse " << "counter" << "\n"; output << "# HELP " << frontsbase << "tcpgaveup " << "Amount of TCP connections terminated after too many attempts to get a connection to the backend" << "\n"; output << "# TYPE " << frontsbase << "tcpgaveup " << "counter" << "\n"; - output << "# HELP " << frontsbase << "tcpclientimeouts " << "Amount of TCP connections terminated by a timeout while reading from the client" << "\n"; - output << "# TYPE " << frontsbase << "tcpclientimeouts " << "counter" << "\n"; + output << "# HELP " << frontsbase << "tcpclienttimeouts " << "Amount of TCP connections terminated by a timeout while reading from the client" << "\n"; + output << "# TYPE " << frontsbase << "tcpclienttimeouts " << "counter" << "\n"; output << "# HELP " << frontsbase << "tcpdownstreamtimeouts " << "Amount of TCP connections terminated by a timeout while reading from the backend" << "\n"; output << "# TYPE " << frontsbase << "tcpdownstreamtimeouts " << "counter" << "\n"; output << "# HELP " << frontsbase << "tcpcurrentconnections " << "Amount of current incoming TCP connections from clients" << "\n"; @@ -672,7 +695,6 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) output << "# TYPE " << frontsbase << "tlsunknownticketkeys " << "counter" << "\n"; output << "# HELP " << frontsbase << "tlsinactiveticketkeys " << "Amount of TLS sessions resumed from an inactive key" << "\n"; output << "# TYPE " << frontsbase << "tlsinactiveticketkeys " << "counter" << "\n"; - output << "# HELP " << frontsbase << "tlshandshakefailures " << "Amount of TLS handshake failures" << "\n"; output << "# TYPE " << frontsbase << "tlshandshakefailures " << "counter" << "\n"; @@ -700,7 +722,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) output << frontsbase << "tcpdiedreadingquery" << label << front->tcpDiedReadingQuery.load() << "\n"; output << frontsbase << "tcpdiedsendingresponse" << label << front->tcpDiedSendingResponse.load() << "\n"; output << frontsbase << "tcpgaveup" << label << front->tcpGaveUp.load() << "\n"; - output << frontsbase << "tcpclientimeouts" << label << front->tcpClientTimeouts.load() << "\n"; + output << frontsbase << "tcpclienttimeouts" << label << front->tcpClientTimeouts.load() << "\n"; output << frontsbase << "tcpdownstreamtimeouts" << label << front->tcpDownstreamTimeouts.load() << "\n"; output << frontsbase << "tcpcurrentconnections" << label << front->tcpCurrentConnections.load() << "\n"; output << frontsbase << "tcpmaxconcurrentconnections" << label << front->tcpMaxConcurrentConnections.load() << "\n"; @@ -723,7 +745,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) errorCounters = &front->tlsFrontend->d_tlsCounters; } else if (front->dohFrontend != nullptr) { - errorCounters = &front->dohFrontend->d_tlsCounters; + errorCounters = &front->dohFrontend->d_tlsContext.d_tlsCounters; } if (errorCounters != nullptr) { @@ -761,7 +783,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) #ifdef HAVE_DNS_OVER_HTTPS std::map<std::string,uint64_t> dohFrontendDuplicates; for(const auto& doh : g_dohlocals) { - const string frontName = doh->d_local.toStringWithPort(); + const string frontName = doh->d_tlsContext.d_addr.toStringWithPort(); uint64_t threadNumber = 0; auto dupPair = frontendDuplicates.emplace(frontName, 1); if (!dupPair.second) { @@ -895,18 +917,18 @@ using namespace json11; 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)); } } @@ -1084,6 +1106,12 @@ static void addServerToJSON(Json::array& servers, int id, const std::shared_ptr< {"tcpAvgConnectionDuration", (double)a->tcpAvgConnectionDuration}, {"tlsResumptions", (double)a->tlsResumptions}, {"tcpLatency", (double)(a->latencyUsecTCP/1000.0)}, + {"healthCheckFailures", (double)(a->d_healthCheckMetrics.d_failures)}, + {"healthCheckFailuresParsing", (double)(a->d_healthCheckMetrics.d_parseErrors)}, + {"healthCheckFailuresTimeout", (double)(a->d_healthCheckMetrics.d_timeOuts)}, + {"healthCheckFailuresNetwork", (double)(a->d_healthCheckMetrics.d_networkErrors)}, + {"healthCheckFailuresMismatch", (double)(a->d_healthCheckMetrics.d_mismatchErrors)}, + {"healthCheckFailuresInvalid", (double)(a->d_healthCheckMetrics.d_invalidResponseErrors)}, {"dropRate", (double)a->dropRate} }; @@ -1151,7 +1179,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) errorCounters = &front->tlsFrontend->d_tlsCounters; } else if (front->dohFrontend != nullptr) { - errorCounters = &front->dohFrontend->d_tlsCounters; + errorCounters = &front->dohFrontend->d_tlsContext.d_tlsCounters; } if (errorCounters != nullptr) { frontend["tlsHandshakeFailuresDHKeyTooSmall"] = (double)errorCounters->d_dhKeyTooSmall; @@ -1174,7 +1202,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) for (const auto& doh : g_dohlocals) { dohs.emplace_back(Json::object{ { "id", num++ }, - { "address", doh->d_local.toStringWithPort() }, + { "address", doh->d_tlsContext.d_addr.toStringWithPort() }, { "http-connects", (double) doh->d_httpconnects }, { "http1-queries", (double) doh->d_http1Stats.d_nbQueries }, { "http2-queries", (double) doh->d_http2Stats.d_nbQueries }, @@ -1239,6 +1267,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) {"id", num++}, {"creationOrder", (double)a.d_creationOrder}, {"uuid", boost::uuids::to_string(a.d_id)}, + {"name", a.d_name}, {"matches", (double)a.d_rule->d_matches}, {"rule", a.d_rule->toString()}, {"action", a.d_action->toString()}, @@ -1254,14 +1283,13 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) string acl; { - vector<string> vec; - g_ACL.getLocal()->toStringVector(&vec); + auto aclEntries = g_ACL.getLocal()->toStringVector(); - for (const auto& s : vec) { + for (const auto& entry : aclEntries) { if (!acl.empty()) { acl += ", "; } - acl += s; + acl += entry; } } @@ -1362,34 +1390,34 @@ static void handleStatsOnly(const YaHTTP::Request& req, YaHTTP::Response& resp) 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 }, @@ -1496,18 +1524,12 @@ static void handleAllowFrom(const YaHTTP::Request& req, YaHTTP::Response& resp) } } if (resp.status == 200) { - Json::array acl; - vector<string> vec; - g_ACL.getLocal()->toStringVector(&vec); - - for(const auto& s : vec) { - acl.push_back(s); - } + auto aclEntries = g_ACL.getLocal()->toStringVector(); Json::object obj{ { "type", "ConfigSetting" }, { "name", "allow-from" }, - { "value", acl } + { "value", aclEntries } }; Json my_json = obj; resp.body = my_json.dump(); @@ -1600,13 +1622,111 @@ static void handleCacheManagement(const YaHTTP::Request& req, YaHTTP::Response& } #endif /* DISABLE_WEB_CACHE_MANAGEMENT */ +template<typename T> static void addRingEntryToList(const struct timespec& now, Json::array& list, const T& entry) +{ + constexpr bool response = std::is_same_v<T, Rings::Response>; + Json::object tmp{ + { "age", static_cast<double>(DiffTime(entry.when, now)) }, + { "id", ntohs(entry.dh.id) }, + { "name", entry.name.toString() }, + { "requestor", entry.requestor.toStringWithPort() }, + { "size", static_cast<int>(entry.size) }, + { "qtype", entry.qtype }, + { "protocol", entry.protocol.toString() }, + { "rd", static_cast<bool>(entry.dh.rd) }, + }; + if constexpr (!response) { +#if defined(DNSDIST_RINGS_WITH_MACADDRESS) + tmp.emplace("mac", entry.hasmac ? std::string(reinterpret_cast<const char*>(entry.macaddress.data()), entry.macaddress.size()) : std::string()); +#endif + } + else { + tmp.emplace("latency", static_cast<double>(entry.usec)); + tmp.emplace("rcode", static_cast<uint8_t>(entry.dh.rcode)); + tmp.emplace("tc", static_cast<bool>(entry.dh.tc)); + tmp.emplace("aa", static_cast<bool>(entry.dh.aa)); + tmp.emplace("answers", ntohs(entry.dh.ancount)); + auto server = entry.ds.toStringWithPort(); + tmp.emplace("backend", server != "0.0.0.0:0" ? std::move(server) : "Cache"); + } + list.push_back(std::move(tmp)); +} + +static void handleRings(const YaHTTP::Request& req, YaHTTP::Response& resp) +{ + handleCORS(req, resp); + + std::optional<size_t> maxNumberOfQueries{std::nullopt}; + std::optional<size_t> maxNumberOfResponses{std::nullopt}; + + const auto maxQueries = req.getvars.find("maxQueries"); + if (maxQueries != req.getvars.end()) { + try { + maxNumberOfQueries = pdns::checked_stoi<size_t>(maxQueries->second); + } + catch (const std::exception& exp) { + vinfolog("Error parsing the 'maxQueries' value from rings HTTP GET query: %s", exp.what()); + } + } + + const auto maxResponses = req.getvars.find("maxResponses"); + if (maxResponses != req.getvars.end()) { + try { + maxNumberOfResponses = pdns::checked_stoi<size_t>(maxResponses->second); + } + catch (const std::exception& exp) { + vinfolog("Error parsing the 'maxResponses' value from rings HTTP GET query: %s", exp.what()); + } + } + + resp.status = 200; + + Json::object doc; + size_t numberOfQueries = 0; + size_t numberOfResponses = 0; + Json::array queries; + Json::array responses; + struct timespec now + { + }; + gettime(&now); + + for (const auto& shard : g_rings.d_shards) { + if (!maxNumberOfQueries || numberOfQueries < *maxNumberOfQueries) { + auto queryRing = shard->queryRing.lock(); + for (const auto& entry : *queryRing) { + addRingEntryToList(now, queries, entry); + numberOfQueries++; + if (maxNumberOfQueries && numberOfQueries >= *maxNumberOfQueries) { + break; + } + } + } + if (!maxNumberOfResponses || numberOfResponses < *maxNumberOfResponses) { + auto responseRing = shard->respRing.lock(); + for (const auto& entry : *responseRing) { + addRingEntryToList(now, responses, entry); + numberOfResponses++; + if (maxNumberOfResponses && numberOfResponses >= *maxNumberOfResponses) { + break; + } + } + } + } + doc.emplace("queries", std::move(queries)); + doc.emplace("responses", std::move(responses)); + Json my_json = doc; + resp.body = my_json.dump(); + resp.headers["Content-Type"] = "application/json"; +} + static std::unordered_map<std::string, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)>> s_webHandlers; void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler); void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler) { - s_webHandlers[endpoint] = handler; + s_webHandlers[endpoint] = std::move(handler); } void clearWebHandlers() @@ -1664,6 +1784,7 @@ void registerBuiltInWebHandlers() registerWebHandler("/api/v1/servers/localhost", handleStats); registerWebHandler("/api/v1/servers/localhost/pool", handlePoolStats); registerWebHandler("/api/v1/servers/localhost/statistics", handleStatsOnly); + registerWebHandler("/api/v1/servers/localhost/rings", handleRings); #ifndef DISABLE_WEB_CONFIG registerWebHandler("/api/v1/servers/localhost/config", handleConfigDump); registerWebHandler("/api/v1/servers/localhost/config/allow-from", handleAllowFrom); @@ -1759,10 +1880,10 @@ static void connectionThread(WebClientConnection&& conn) vinfolog("Webserver thread died with parse error exception while processing a request from %s: %s", conn.getClient().toStringWithPort(), e.what()); } catch (const std::exception& e) { - errlog("Webserver thread died with exception while processing a request from %s: %s", conn.getClient().toStringWithPort(), e.what()); + vinfolog("Webserver thread died with exception while processing a request from %s: %s", conn.getClient().toStringWithPort(), e.what()); } catch (...) { - errlog("Webserver thread died with exception while processing a request from %s", conn.getClient().toStringWithPort()); + vinfolog("Webserver thread died with exception while processing a request from %s", conn.getClient().toStringWithPort()); } } @@ -1845,7 +1966,7 @@ void dnsdistWebserverThread(int sock, const ComboAddress& local) t.detach(); } catch (const std::exception& e) { - errlog("Had an error accepting new webserver connection: %s", e.what()); + vinfolog("Had an error accepting new webserver connection: %s", e.what()); } } } |