blob: e059c1f98248bec04d141ea2d1d39a9be7497402 [file] [log] [blame]
// 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