| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #include "kudu/server/startup_path_handler.h" |
| |
| #include <functional> |
| #include <iosfwd> |
| #include <string> |
| |
| #include "kudu/gutil/strings/human_readable.h" |
| #include "kudu/server/webserver.h" |
| #include "kudu/util/easy_json.h" |
| #include "kudu/util/metrics.h" |
| #include "kudu/util/monotime.h" |
| #include "kudu/util/timer.h" |
| #include "kudu/util/web_callback_registry.h" |
| |
| METRIC_DEFINE_gauge_int32(server, startup_progress_steps_remaining, |
| "Server Startup Steps Remaining", |
| kudu::MetricUnit::kUnits, |
| "Server startup progress steps remaining ", |
| kudu::MetricLevel::kWarn); |
| |
| METRIC_DEFINE_gauge_int64(server, startup_progress_time_elapsed, |
| "Server Startup Progress Time Elapsed", |
| kudu::MetricUnit::kMilliseconds, |
| "Time taken by the server to complete the startup or" |
| "time elapsed so far for the server to startup", |
| kudu::MetricLevel::kInfo); |
| |
| using std::ifstream; |
| using std::ostringstream; |
| using std::string; |
| |
| namespace kudu { |
| |
| namespace server { |
| |
| void SetWebResponse(EasyJson* output, const string& step, |
| const Timer& startup_step, const int percent = -1) { |
| output->Set(step + "_status", percent == -1 ? (startup_step.IsStopped() ? 100 : 0) : percent); |
| output->Set(step + "_time", HumanReadableElapsedTime::ToShortString( |
| (startup_step.TimeElapsed()).ToSeconds())); |
| } |
| |
| StartupPathHandler::StartupPathHandler(const scoped_refptr<MetricEntity>& entity): |
| tablets_processed_(0), |
| tablets_total_(0), |
| containers_processed_(0), |
| containers_total_(0), |
| is_tablet_server_(false), |
| is_using_lbm_(true) { |
| METRIC_startup_progress_steps_remaining.InstantiateFunctionGauge(entity, |
| [this]() {return StartupProgressStepsRemainingMetric();}) |
| ->AutoDetachToLastValue(&metric_detacher_); |
| METRIC_startup_progress_time_elapsed.InstantiateFunctionGauge(entity, |
| [this]() {return StartupProgressTimeElapsedMetric().ToMilliseconds();}) |
| ->AutoDetachToLastValue(&metric_detacher_); |
| } |
| |
| void StartupPathHandler::Startup(const Webserver::WebRequest& /*req*/, |
| Webserver::WebResponse* resp) { |
| |
| auto* output = &resp->output; |
| |
| output->Set("is_tablet_server", is_tablet_server_); |
| output->Set("is_master_server", !is_tablet_server_); |
| output->Set("is_log_block_manager", is_using_lbm_); |
| |
| // Populate the different startup steps with their progress |
| SetWebResponse(output, "init", init_progress_); |
| SetWebResponse(output, "read_filesystem", read_filesystem_progress_); |
| SetWebResponse(output, "read_instance_metadatafiles", read_instance_metadata_files_progress_); |
| |
| // Populate the progress percentage of opening of container files in case of lbm and non-lbm |
| if (is_using_lbm_) { |
| if (containers_total_ == 0) { |
| SetWebResponse(output, "read_data_directories", read_data_directories_progress_); |
| } else { |
| SetWebResponse(output, "read_data_directories", read_data_directories_progress_, |
| containers_processed_ * 100 / containers_total_); |
| } |
| output->Set("containers_processed", containers_processed_.load()); |
| output->Set("containers_total", containers_total_.load()); |
| } else { |
| SetWebResponse(output, "read_data_directories", read_data_directories_progress_); |
| } |
| |
| // Set the bootstrapping and opening tablets step and handle the case of zero tablets |
| // present in the server |
| if (tablets_total_ == 0) { |
| SetWebResponse(output, "start_tablets", start_tablets_progress_); |
| } else { |
| SetWebResponse(output, "start_tablets", start_tablets_progress_, |
| tablets_processed_ * 100 / tablets_total_); |
| } |
| |
| if (is_tablet_server_) { |
| output->Set("tablets_processed", tablets_processed_.load()); |
| output->Set("tablets_total", tablets_total_.load()); |
| } |
| |
| SetWebResponse(output, "initialize_master_catalog", initialize_master_catalog_progress_); |
| SetWebResponse(output, "start_rpc_server", start_rpc_server_progress_); |
| } |
| |
| void StartupPathHandler::RegisterStartupPathHandler(Webserver *webserver) { |
| bool styled = true; |
| bool on_nav_bar = true; |
| webserver->RegisterPathHandler("/startup", "Startup", |
| [this](const Webserver::WebRequest& req, |
| Webserver::WebResponse* resp) { |
| this->Startup(req, resp); |
| }, |
| styled, on_nav_bar); |
| } |
| |
| void StartupPathHandler::set_is_tablet_server(bool is_tablet_server) { |
| is_tablet_server_ = is_tablet_server; |
| } |
| |
| void StartupPathHandler::set_is_using_lbm(bool is_using_lbm) { |
| is_using_lbm_ = is_using_lbm; |
| } |
| |
| int StartupPathHandler::StartupProgressStepsRemainingMetric() { |
| int counter = 0; |
| counter += (init_progress_.IsStopped() ? 0 : 1); |
| counter += (read_filesystem_progress_.IsStopped() ? 0 : 1); |
| if (is_tablet_server_) { |
| counter += start_tablets_progress_.IsStopped() ? 0 : 1; |
| } else { |
| counter += initialize_master_catalog_progress_.IsStopped() ? 0 : 1; |
| } |
| counter += (start_rpc_server_progress_.IsStopped() ? 0 : 1); |
| return counter; |
| } |
| |
| MonoDelta StartupPathHandler::StartupProgressTimeElapsedMetric() { |
| MonoDelta time_elapsed; |
| time_elapsed = init_progress_.TimeElapsed(); |
| time_elapsed += read_filesystem_progress_.TimeElapsed(); |
| if (is_tablet_server_) { |
| time_elapsed += start_tablets_progress_.TimeElapsed(); |
| } else { |
| time_elapsed += initialize_master_catalog_progress_.TimeElapsed(); |
| } |
| time_elapsed += start_rpc_server_progress_.TimeElapsed(); |
| return time_elapsed; |
| } |
| |
| } // namespace server |
| } // namespace kudu |