From 1c5786b190f7d81f5043315cb64654bf5f7a5b5d Mon Sep 17 00:00:00 2001 From: Pere Diaz Bou Date: Fri, 22 Apr 2022 13:09:12 +0200 Subject: [PATCH] exporter: cleanups - DaemonMetricCollector singleton with static variable - some iterator references - DaemonMetricCollector chagne timer to steady_timer with chrono - AdminClientSocket handle error when send_request. - update_sockests now clears the list of sockets before adding new ones. - use string_body instead of dynamic_body in http::response Signed-off-by: Pere Diaz Bou --- src/ceph_exporter.cc | 5 -- src/exporter/DaemonMetricCollector.cc | 85 ++++++++++++++------------- src/exporter/DaemonMetricCollector.h | 2 +- src/exporter/http_server.cc | 35 ++++++----- 4 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/ceph_exporter.cc b/src/ceph_exporter.cc index 67af60f5b508a..3122a9ca45a76 100644 --- a/src/ceph_exporter.cc +++ b/src/ceph_exporter.cc @@ -7,11 +7,6 @@ #include - -// FIXME: lets save collector instance here for now. -DaemonMetricCollector collector; - - int main(int argc, char** argv) { boost::thread server_thread(http_server_thread_entrypoint); DaemonMetricCollector &collector = collector_instance(); diff --git a/src/exporter/DaemonMetricCollector.cc b/src/exporter/DaemonMetricCollector.cc index 51d3fe7c52e19..d97e405f8ef2b 100644 --- a/src/exporter/DaemonMetricCollector.cc +++ b/src/exporter/DaemonMetricCollector.cc @@ -14,14 +14,14 @@ using json_object = boost::json::object; using json_value = boost::json::value; using json_array = boost::json::array; -const char *DaemonMetricCollector::SOCKETDIR = "/var/run/ceph/"; +const char *DaemonMetricCollector::SOCKETDIR = "/tmp/ceph-asok.u6a3XT"; -void DaemonMetricCollector::request_loop(boost::asio::deadline_timer &timer) { +void DaemonMetricCollector::request_loop(boost::asio::steady_timer &timer) { timer.async_wait([&](const boost::system::error_code &e) { std::cerr << e << std::endl; update_sockets(); dump_asok_metrics(); - timer.expires_from_now(boost::posix_time::seconds(stats_period)); + timer.expires_from_now(std::chrono::seconds(stats_period)); request_loop(timer); }); } @@ -30,8 +30,9 @@ void DaemonMetricCollector::main() { // TODO: let's do 5 for now and expose this to change in the future stats_period = 5; boost::asio::io_service io; - boost::asio::deadline_timer timer(io, - boost::posix_time::seconds(stats_period)); + // boost::asio::deadline_timer timer(io, + // boost::posix_time::seconds(stats_period)); + boost::asio::steady_timer timer{io, std::chrono::seconds(stats_period)}; request_loop(timer); io.run(); } @@ -70,36 +71,37 @@ bool is_hyphen(char ch) { return ch == '-'; } void DaemonMetricCollector::dump_asok_metrics() { std::stringstream ss; - for (auto client : clients) { - AdminSocketClient &sock_client = client.second; - std::string daemon_name = client.first; + for (auto &[daemon_name, sock_client] : clients) { std::string perf_dump_response = asok_request(sock_client, "perf dump"); - if (perf_dump_response.size() > 0) { - json_object dump = boost::json::parse(perf_dump_response).as_object(); - std::string perf_schema_response = - asok_request(sock_client, "perf schema"); - json_object schema = boost::json::parse(perf_schema_response).as_object(); - for (auto perf : schema) { - std::string perf_group = perf.key().to_string(); - json_object perf_group_object = perf.value().as_object(); - for (auto perf_counter : perf_group_object) { - std::string perf_name = perf_counter.key().to_string(); - json_object perf_info = perf_counter.value().as_object(); - if (perf_info["priority"].as_int64() < - PerfCountersBuilder::PRIO_USEFUL) { - continue; - } - std::string name = "ceph_" + perf_group + "_" + perf_name; - std::replace_if(name.begin(), name.end(), is_hyphen, '_'); - - // FIXME: test this, based on mgr_module perfpath_to_path_labels - auto labels_and_name = get_labels_and_metric_name(daemon_name, name); - std::string labels = labels_and_name.first; - name = labels_and_name.second; - - json_value perf_values = dump[perf_group].as_object()[perf_name]; - dump_asok_metric(ss, perf_info, perf_values, name, labels); + if (perf_dump_response.size() == 0) { + continue; + } + std::string perf_schema_response = asok_request(sock_client, "perf schema"); + if (perf_schema_response.size() == 0) { + continue; + } + json_object dump = boost::json::parse(perf_dump_response).as_object(); + json_object schema = boost::json::parse(perf_schema_response).as_object(); + for (auto &perf : schema) { + std::string perf_group = perf.key().to_string(); + json_object perf_group_object = perf.value().as_object(); + for (auto &perf_counter : perf_group_object) { + std::string perf_name = perf_counter.key().to_string(); + json_object perf_info = perf_counter.value().as_object(); + if (perf_info["priority"].as_int64() < + PerfCountersBuilder::PRIO_USEFUL) { + continue; } + std::string name = "ceph_" + perf_group + "_" + perf_name; + std::replace_if(name.begin(), name.end(), is_hyphen, '_'); + + // FIXME: test this, based on mgr_module perfpath_to_path_labels + auto labels_and_name = get_labels_and_metric_name(daemon_name, name); + std::string labels = labels_and_name.first; + name = labels_and_name.second; + + json_value perf_values = dump[perf_group].as_object()[perf_name]; + dump_asok_metric(ss, perf_info, perf_values, name, labels); } } } @@ -110,7 +112,10 @@ std::string DaemonMetricCollector::asok_request(AdminSocketClient &asok, std::string command) { std::string request("{\"prefix\": \"" + command + "\"}"); std::string response; - asok.do_request(request, &response); + std::string err = asok.do_request(request, &response); + if (err.length() > 0) { + return ""; + } return response; } @@ -175,11 +180,11 @@ void DaemonMetricCollector::dump_asok_metric(std::stringstream &ss, } } void DaemonMetricCollector::update_sockets() { + clients.clear(); for (const auto &entry : - std::filesystem::recursive_directory_iterator(SOCKETDIR)) { + std::filesystem::directory_iterator(SOCKETDIR)) { if (entry.path().extension() == ".asok") { std::string daemon_socket_name = entry.path().filename().string(); - // remove .asok std::string daemon_name = daemon_socket_name.substr(0, daemon_socket_name.size() - 5); if (clients.find(daemon_name) == clients.end() && @@ -191,11 +196,7 @@ void DaemonMetricCollector::update_sockets() { } } -DaemonMetricCollector *_collector_instance = nullptr; - DaemonMetricCollector &collector_instance() { - if (_collector_instance == nullptr) { - _collector_instance = new DaemonMetricCollector(); - } - return *_collector_instance; + static DaemonMetricCollector instance; + return instance; } diff --git a/src/exporter/DaemonMetricCollector.h b/src/exporter/DaemonMetricCollector.h index 3bd445fc1cbfc..735b9ac086fc3 100644 --- a/src/exporter/DaemonMetricCollector.h +++ b/src/exporter/DaemonMetricCollector.h @@ -23,7 +23,7 @@ private: std::string metrics; int stats_period; // time to wait before sending requests again void update_sockets(); - void request_loop(boost::asio::deadline_timer &timer); + void request_loop(boost::asio::steady_timer &timer); void dump_asok_metrics(); void dump_asok_metric(std::stringstream &ss, boost::json::object perf_info, diff --git a/src/exporter/http_server.cc b/src/exporter/http_server.cc index 074dd787665c8..3fdfbb53c14f1 100644 --- a/src/exporter/http_server.cc +++ b/src/exporter/http_server.cc @@ -34,7 +34,7 @@ private: tcp::socket socket_; beast::flat_buffer buffer_{8192}; http::request request_; - http::response response_; + http::response response_; net::steady_timer deadline_{socket_.get_executor(), std::chrono::seconds(60)}; @@ -64,11 +64,11 @@ private: default: // We return responses indicating an error if // we do not recognize the request method. - response_.result(http::status::bad_request); + response_.result(http::status::method_not_allowed); response_.set(http::field::content_type, "text/plain"); - beast::ostream(response_.body()) - << "Invalid request-method '" << std::string(request_.method_string()) - << "'"; + std::string body("Invalid request-method '" + + std::string(request_.method_string()) + "'"); + response_.body() = body; break; } @@ -79,24 +79,23 @@ private: void create_response() { if (request_.target() == "/") { response_.set(http::field::content_type, "text/html; charset=utf-8"); - beast::ostream(response_.body()) - << "\n" - << "Ceph Exporter\n" - << "\n" - << "

Ceph Exporter

\n" - - << "

Metrics

" - << "\n" - << "\n"; + std::string body("\n" + "Ceph Exporter\n" + "\n" + "

Ceph Exporter

\n" + "

Metrics

" + "\n" + "\n"); + response_.body() = body; } else if (request_.target() == "/metrics") { response_.set(http::field::content_type, "text/plain; charset=utf-8"); DaemonMetricCollector &collector = collector_instance(); std::string metrics = collector.get_metrics(); - beast::ostream(response_.body()) << metrics << std::endl; + response_.body() = metrics; } else { - response_.result(http::status::not_found); + response_.result(http::status::method_not_allowed); response_.set(http::field::content_type, "text/plain"); - beast::ostream(response_.body()) << "File not found\r\n"; + response_.body() = "File not found \n"; } } @@ -104,7 +103,7 @@ private: void write_response() { auto self = shared_from_this(); - response_.content_length(response_.body().size()); + response_.prepare_payload(); http::async_write(socket_, response_, [self](beast::error_code ec, std::size_t) { -- 2.39.5