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

241 lines
8.3 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 "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "Statistics/ConnectionStatistics.h"
#include "Statistics/Descriptions.h"
#include "Statistics/RequestStatistics.h"
#include "Statistics/ServerStatistics.h"
#include "Statistics/StatisticsWorker.h"
#include <thread>
#include <chrono>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
// -----------------------------------------------------------------------------
// --SECTION-- global variables
// -----------------------------------------------------------------------------
namespace arangodb {
namespace basics {
StatisticsCounter TRI_AsyncRequestsStatistics;
StatisticsCounter TRI_HttpConnectionsStatistics;
StatisticsCounter TRI_TotalRequestsStatistics;
StatisticsDistribution* TRI_BytesReceivedDistributionStatistics;
StatisticsDistribution* TRI_BytesSentDistributionStatistics;
StatisticsDistribution* TRI_ConnectionTimeDistributionStatistics;
StatisticsDistribution* TRI_IoTimeDistributionStatistics;
StatisticsDistribution* TRI_QueueTimeDistributionStatistics;
StatisticsDistribution* TRI_RequestTimeDistributionStatistics;
StatisticsDistribution* TRI_TotalTimeDistributionStatistics;
StatisticsVector TRI_BytesReceivedDistributionVectorStatistics;
StatisticsVector TRI_BytesSentDistributionVectorStatistics;
StatisticsVector TRI_ConnectionTimeDistributionVectorStatistics;
StatisticsVector TRI_RequestTimeDistributionVectorStatistics;
std::vector<StatisticsCounter> TRI_MethodRequestsStatistics;
}
}
// -----------------------------------------------------------------------------
// --SECTION-- StatisticsThread
// -----------------------------------------------------------------------------
class arangodb::StatisticsThread final : public Thread {
public:
StatisticsThread() : Thread("Statistics") {}
~StatisticsThread() { shutdown(); }
public:
void run() override {
uint64_t const MAX_SLEEP_TIME = 250 * 1000;
uint64_t sleepTime = 100 * 1000;
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 * 1000;
if (sleepTime > MAX_SLEEP_TIME) {
sleepTime = MAX_SLEEP_TIME;
}
}
std::this_thread::sleep_for(std::chrono::microseconds(sleepTime));
} else {
nothingHappened = 0;
if (count < 10) {
std::this_thread::sleep_for(std::chrono::microseconds(10 * 1000));
} else if (count < 100) {
std::this_thread::sleep_for(std::chrono::microseconds(1 * 1000));
}
}
}
RequestStatistics::shutdown();
ConnectionStatistics::shutdown();
ServerStatistics::shutdown();
}
};
// -----------------------------------------------------------------------------
// --SECTION-- StatisticsFeature
// -----------------------------------------------------------------------------
StatisticsFeature* StatisticsFeature::STATISTICS = nullptr;
StatisticsFeature::StatisticsFeature(
application_features::ApplicationServer* server)
: ApplicationFeature(server, "Statistics"),
_statistics(true),
_descriptions(new stats::Descriptions()) {
startsAfter("Logger");
startsAfter("Aql");
}
void StatisticsFeature::collectOptions(
std::shared_ptr<ProgramOptions> options) {
options->addOldOption("server.disable-statistics", "server.statistics");
options->addSection("server", "Server features");
options->addHiddenOption("--server.statistics",
"turn statistics gathering on or off",
new BooleanParameter(&_statistics));
}
void StatisticsFeature::prepare() {
// initialize counters for all HTTP request types
TRI_MethodRequestsStatistics.clear();
for (int i = 0; i < ((int)arangodb::rest::RequestType::ILLEGAL) + 1; ++i) {
StatisticsCounter c;
TRI_MethodRequestsStatistics.emplace_back(c);
}
TRI_ConnectionTimeDistributionVectorStatistics << (0.1) << (1.0) << (60.0);
TRI_BytesSentDistributionVectorStatistics << (250) << (1000) << (2 * 1000)
<< (5 * 1000) << (10 * 1000);
TRI_BytesReceivedDistributionVectorStatistics << (250) << (1000) << (2 * 1000)
<< (5 * 1000) << (10 * 1000);
TRI_RequestTimeDistributionVectorStatistics << (0.01) << (0.05) << (0.1)
<< (0.2) << (0.5) << (1.0);
TRI_ConnectionTimeDistributionStatistics = new StatisticsDistribution(
TRI_ConnectionTimeDistributionVectorStatistics);
TRI_TotalTimeDistributionStatistics =
new StatisticsDistribution(TRI_RequestTimeDistributionVectorStatistics);
TRI_RequestTimeDistributionStatistics =
new StatisticsDistribution(TRI_RequestTimeDistributionVectorStatistics);
TRI_QueueTimeDistributionStatistics =
new StatisticsDistribution(TRI_RequestTimeDistributionVectorStatistics);
TRI_IoTimeDistributionStatistics =
new StatisticsDistribution(TRI_RequestTimeDistributionVectorStatistics);
TRI_BytesSentDistributionStatistics =
new StatisticsDistribution(TRI_BytesSentDistributionVectorStatistics);
TRI_BytesReceivedDistributionStatistics =
new StatisticsDistribution(TRI_BytesReceivedDistributionVectorStatistics);
STATISTICS = this;
ServerStatistics::initialize();
ConnectionStatistics::initialize();
RequestStatistics::initialize();
}
void StatisticsFeature::start() {
if (!_statistics) {
return;
}
_statisticsThread.reset(new StatisticsThread);
_statisticsWorker.reset(new StatisticsWorker);
if (!_statisticsThread->start()) {
LOG_TOPIC(FATAL, arangodb::Logger::STATISTICS) << "could not start statistics thread";
FATAL_ERROR_EXIT();
}
if (!_statisticsWorker->start()) {
LOG_TOPIC(FATAL, arangodb::Logger::STATISTICS) << "could not start statistics worker";
FATAL_ERROR_EXIT();
}
}
void StatisticsFeature::unprepare() {
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();
delete TRI_ConnectionTimeDistributionStatistics;
TRI_ConnectionTimeDistributionStatistics = nullptr;
delete TRI_TotalTimeDistributionStatistics;
TRI_TotalTimeDistributionStatistics = nullptr;
delete TRI_RequestTimeDistributionStatistics;
TRI_RequestTimeDistributionStatistics = nullptr;
delete TRI_QueueTimeDistributionStatistics;
TRI_QueueTimeDistributionStatistics = nullptr;
delete TRI_IoTimeDistributionStatistics;
TRI_IoTimeDistributionStatistics = nullptr;
delete TRI_BytesSentDistributionStatistics;
TRI_BytesSentDistributionStatistics = nullptr;
delete TRI_BytesReceivedDistributionStatistics;
TRI_BytesReceivedDistributionStatistics = nullptr;
STATISTICS = nullptr;
}