blob: eda0019f7dfd0f69be9210ca8edcea63fc27b24f [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/mini-cluster/webui_checker.h"
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <iostream>
#include <random>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include <glog/logging.h>
#include "kudu/gutil/strings/substitute.h"
#include "kudu/mini-cluster/external_mini_cluster.h"
#include "kudu/util/curl_util.h"
#include "kudu/util/faststring.h"
#include "kudu/util/monotime.h"
#include "kudu/util/net/net_util.h"
#include "kudu/util/status.h"
using std::string;
using std::thread;
using std::vector;
using strings::Substitute;
namespace kudu {
PeriodicWebUIChecker::PeriodicWebUIChecker(
const cluster::ExternalMiniCluster& cluster,
MonoDelta period,
const string& tablet_id,
const vector<string>& master_pages,
const vector<string>& ts_pages)
: period_(period),
is_running_(true) {
// List of tserver web pages to fetch.
vector<string> ts_pages_spec(ts_pages);
if (tablet_id.empty()) {
ts_pages_spec.emplace_back("/transactions");
} else {
ts_pages_spec.emplace_back(
Substitute("/transactions?tablet_id=$0", tablet_id));
}
// Generate list of urls for each master and tablet server
for (int i = 0; i < cluster.num_masters(); i++) {
for (const auto& page : master_pages) {
urls_.emplace_back(Substitute(
"http://$0$1",
cluster.master(i)->bound_http_hostport().ToString(),
page));
}
}
for (int i = 0; i < cluster.num_tablet_servers(); i++) {
for (const auto& page : ts_pages_spec) {
urls_.emplace_back(Substitute(
"http://$0$1",
cluster.tablet_server(i)->bound_http_hostport().ToString(),
page));
}
}
std::random_device rdev;
std::mt19937 gen(rdev());
std::shuffle(urls_.begin(), urls_.end(), gen);
checker_ = thread([this]() { this->CheckThread(); });
}
PeriodicWebUIChecker::~PeriodicWebUIChecker() {
LOG(INFO) << "shutting down CURL thread";
is_running_ = false;
checker_.join();
}
void PeriodicWebUIChecker::CheckThread() {
EasyCurl curl;
curl.set_timeout(MonoDelta::FromSeconds(120));
std::ostringstream ostr;
ostr << "curl thread will poll the following URLs every "
<< period_.ToString() << ":\n";
for (const auto& url : urls_) {
ostr << " " << url << "\n";
}
LOG(INFO) << ostr.str();
faststring dst;
while (is_running_) {
// Poll all of the URLs.
const MonoTime start = MonoTime::Now();
bool compression_enabled = true;
for (const auto& url : urls_) {
// Switch compression back and forth.
Status s = compression_enabled
? curl.FetchURL(url, &dst, {"Accept-Encoding: gzip"})
: curl.FetchURL(url, &dst);
compression_enabled = !compression_enabled;
if (s.ok()) {
CHECK_GT(dst.length(), 0);
}
CHECK(!s.IsTimedOut()) << Substitute(
"could not fetch $0 ($1 compression, $2 connections): $3",
url, compression_enabled ? "gzip" : "no", curl.num_connects(), s.ToString());
}
// Sleep until the next period
const MonoDelta elapsed = MonoTime::Now() - start;
const int64_t sleep_ns = period_.ToNanoseconds() - elapsed.ToNanoseconds();
if (sleep_ns > 0) {
SleepFor(MonoDelta::FromNanoseconds(sleep_ns));
}
}
}
} // namespace kudu