1
0
Fork 0
arangodb/arangod/Statistics/StatisticsFeature.cpp

260 lines
9.4 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "StatisticsFeature.h"
#include "Basics/application-exit.h"
#include "Cluster/ServerState.h"
#include "FeaturePhases/AqlFeaturePhase.h"
#include "Logger/LogMacros.h"
#include "Logger/Logger.h"
#include "Logger/LoggerStream.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/MetricsFeature.h"
#include "RestServer/SystemDatabaseFeature.h"
#include "RestServer/DatabaseFeature.h"
#include "Statistics/ConnectionStatistics.h"
#include "Statistics/Descriptions.h"
#include "Statistics/RequestStatistics.h"
#include "Statistics/ServerStatistics.h"
#include "Statistics/StatisticsWorker.h"
#include "VocBase/vocbase.h"
#include <chrono>
#include <thread>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
// -----------------------------------------------------------------------------
// --SECTION-- global variables
// -----------------------------------------------------------------------------
namespace arangodb {
namespace basics {
Mutex TRI_RequestsStatisticsMutex;
std::vector<double> const TRI_BytesReceivedDistributionVectorStatistics({250, 1000, 2000,
5000, 10000});
std::vector<double> const TRI_BytesSentDistributionVectorStatistics({250, 1000, 2000,
5000, 10000});
std::vector<double> const TRI_ConnectionTimeDistributionVectorStatistics({0.1, 1.0, 60.0});
std::vector<double> const TRI_RequestTimeDistributionVectorStatistics({0.01, 0.05, 0.1,
0.2, 0.5, 1.0});
StatisticsCounter TRI_AsyncRequestsStatistics;
StatisticsCounter TRI_HttpConnectionsStatistics;
StatisticsCounter TRI_TotalRequestsStatistics;
std::array<StatisticsCounter, MethodRequestsStatisticsSize> TRI_MethodRequestsStatistics;
StatisticsDistribution TRI_BytesReceivedDistributionStatistics(TRI_BytesReceivedDistributionVectorStatistics);
StatisticsDistribution TRI_BytesSentDistributionStatistics(TRI_BytesSentDistributionVectorStatistics);
StatisticsDistribution TRI_ConnectionTimeDistributionStatistics(TRI_ConnectionTimeDistributionVectorStatistics);
StatisticsDistribution TRI_IoTimeDistributionStatistics(TRI_RequestTimeDistributionVectorStatistics);
StatisticsDistribution TRI_QueueTimeDistributionStatistics(TRI_RequestTimeDistributionVectorStatistics);
StatisticsDistribution TRI_RequestTimeDistributionStatistics(TRI_RequestTimeDistributionVectorStatistics);
StatisticsDistribution TRI_TotalTimeDistributionStatistics(TRI_RequestTimeDistributionVectorStatistics);
StatisticsDistribution TRI_BytesReceivedDistributionStatisticsUser(TRI_BytesReceivedDistributionVectorStatistics);
StatisticsDistribution TRI_BytesSentDistributionStatisticsUser(TRI_BytesSentDistributionVectorStatistics);
StatisticsDistribution TRI_IoTimeDistributionStatisticsUser(TRI_RequestTimeDistributionVectorStatistics);
StatisticsDistribution TRI_QueueTimeDistributionStatisticsUser(TRI_RequestTimeDistributionVectorStatistics);
StatisticsDistribution TRI_RequestTimeDistributionStatisticsUser(TRI_RequestTimeDistributionVectorStatistics);
StatisticsDistribution TRI_TotalTimeDistributionStatisticsUser(TRI_RequestTimeDistributionVectorStatistics);
} // namespace basics
} // namespace arangodb
// -----------------------------------------------------------------------------
// --SECTION-- StatisticsThread
// -----------------------------------------------------------------------------
class StatisticsThread final : public Thread {
public:
explicit StatisticsThread(ApplicationServer& server)
: Thread(server, "Statistics") {}
~StatisticsThread() { shutdown(); }
public:
void run() override {
auto& databaseFeature = server().getFeature<arangodb::DatabaseFeature>();
if (databaseFeature.upgrade()) {
// don't start the thread when we are running an upgrade
return;
}
uint64_t const MAX_SLEEP_TIME = 250;
uint64_t sleepTime = 100;
int nothingHappened = 0;
while (!isStopping() && StatisticsFeature::enabled()) {
size_t count = RequestStatistics::processAll();
if (count == 0) {
if (++nothingHappened == 10 * 30) {
// increase sleep time every 30 seconds
nothingHappened = 0;
sleepTime += 50;
if (sleepTime > MAX_SLEEP_TIME) {
sleepTime = MAX_SLEEP_TIME;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
} else {
nothingHappened = 0;
if (count < 10) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} else if (count < 100) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
}
}
};
// -----------------------------------------------------------------------------
// --SECTION-- StatisticsFeature
// -----------------------------------------------------------------------------
StatisticsFeature* StatisticsFeature::STATISTICS = nullptr;
StatisticsFeature::StatisticsFeature(application_features::ApplicationServer& server)
: ApplicationFeature(server, "Statistics"),
_statistics(true),
_statisticsHistory(true),
_statisticsHistoryTouched(false),
_descriptions(new stats::Descriptions()) {
setOptional(true);
startsAfter<AqlFeaturePhase>();
}
void StatisticsFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addOldOption("server.disable-statistics", "server.statistics");
options->addSection("server", "Server features");
options->addOption("--server.statistics",
"turn statistics gathering on or off",
new BooleanParameter(&_statistics),
arangodb::options::makeFlags(arangodb::options::Flags::Hidden));
options->addOption("--server.statistics-history",
"turn storing statistics in database on or off",
new BooleanParameter(&_statisticsHistory),
arangodb::options::makeFlags(arangodb::options::Flags::Hidden))
.setIntroducedIn(30409)
.setIntroducedIn(30501);
}
void StatisticsFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
if (!_statistics) {
// turn ourselves off
disable();
}
_statisticsHistoryTouched = options->processingResult().touched("--server.statistics-history");
}
void StatisticsFeature::prepare() {
// initialize counters for all HTTP request types
STATISTICS = this;
server().getFeature<MetricsFeature>().serverStatistics().initialize(
StatisticsFeature::time());
ConnectionStatistics::initialize();
RequestStatistics::initialize();
}
void StatisticsFeature::start() {
TRI_ASSERT(isEnabled());
if (!server().hasFeature<arangodb::SystemDatabaseFeature>()) {
LOG_TOPIC("9b551", FATAL, arangodb::Logger::STATISTICS)
<< "could not find feature 'SystemDatabase'";
FATAL_ERROR_EXIT();
}
auto& sysDbFeature = server().getFeature<arangodb::SystemDatabaseFeature>();
auto vocbase = sysDbFeature.use();
if (!vocbase) {
LOG_TOPIC("cff56", FATAL, arangodb::Logger::STATISTICS)
<< "could not find system database";
FATAL_ERROR_EXIT();
}
_statisticsThread.reset(new StatisticsThread(server()));
if (!_statisticsThread->start()) {
LOG_TOPIC("46b0c", FATAL, arangodb::Logger::STATISTICS)
<< "could not start statistics thread";
FATAL_ERROR_EXIT();
}
// force history disable on Agents
if (arangodb::ServerState::instance()->isAgent() && !_statisticsHistoryTouched) {
_statisticsHistory = false;
} // if
if (_statisticsHistory) {
_statisticsWorker.reset(new StatisticsWorker(*vocbase));
if (!_statisticsWorker->start()) {
LOG_TOPIC("6ecdc", FATAL, arangodb::Logger::STATISTICS)
<< "could not start statistics worker";
FATAL_ERROR_EXIT();
}
} // if
}
void StatisticsFeature::stop() {
if (_statisticsThread != nullptr) {
_statisticsThread->beginShutdown();
while (_statisticsThread->isRunning()) {
std::this_thread::sleep_for(std::chrono::microseconds(10000));
}
}
if (_statisticsWorker != nullptr) {
_statisticsWorker->beginShutdown();
while (_statisticsWorker->isRunning()) {
std::this_thread::sleep_for(std::chrono::microseconds(10000));
}
}
_statisticsThread.reset();
_statisticsWorker.reset();
STATISTICS = nullptr;
}