1
0
Fork 0

Replacing statistics handler with c++ (#4653)

This commit is contained in:
Simon 2018-02-26 15:33:43 +01:00 committed by Jan
parent d841b56c77
commit 11a7bbf321
15 changed files with 731 additions and 523 deletions

View File

@ -3,6 +3,8 @@ devel
* fix issue #4583 - add AQL ASSERT and AQL WARN
* remove _admin/echo handler
* remove long disfunctional admin/long_echo handler
* fixed Foxx API:

View File

@ -24,9 +24,6 @@ This is an overview of ArangoDB's HTTP interface for miscellaneous functions.
<!-- js/actions/api-system.js -->
@startDocuBlock JSF_get_admin_time
<!-- js/actions/api-system.js -->
@startDocuBlock JSF_get_admin_echo
@startDocuBlock JSF_get_admin_database_version
<!-- lib/Admin/RestShutdownHandler.cpp -->

View File

@ -1,22 +0,0 @@
@startDocuBlock JSF_get_admin_echo
@brief Send back what was sent in, headers, post body etc.
@RESTHEADER{GET /_admin/echo, Return current request}
@RESTDESCRIPTION
The call returns an object with the following attributes:
- *headers*: object with HTTP headers received
- *requestType*: the HTTP request method (e.g. GET)
- *parameters*: object with query parameters received
@RESTRETURNCODES
@RESTRETURNCODE{200}
Echo was returned successfully.
@endDocuBlock

View File

@ -53,65 +53,6 @@ describe ArangoDB do
end
################################################################################
## /_admin/echo
################################################################################
context "checks /_admin/echo" do
prefix = "api-system"
it "using GET" do
cmd = "/_admin/echo"
doc = ArangoDB.log_get("#{prefix}-echo", cmd)
doc.code.should eq(200)
doc.parsed_response['url'].should eq("/_admin/echo")
doc.parsed_response['path'].should eq("/")
doc.parsed_response['parameters'].should eq({})
doc.parsed_response['requestType'].should eq("GET")
end
it "using GET, with query parameter" do
cmd = "/_admin/echo?a=1"
doc = ArangoDB.log_get("#{prefix}-echo", cmd)
doc.code.should eq(200)
doc.parsed_response['url'].should eq("/_admin/echo?a=1")
doc.parsed_response['path'].should eq("/")
doc.parsed_response['parameters'].should eq({ "a" => "1" })
doc.parsed_response['requestType'].should eq("GET")
end
it "using POST, with query parameters" do
cmd = "/_admin/echo?a=1&b=2&foo[]=bar&foo[]=baz"
body = "{\"foo\": \"bar\", \"baz\": { \"bump\": true, \"moo\": [ ] } }"
doc = ArangoDB.log_post("#{prefix}-echo", cmd, :body => body)
doc.code.should eq(200)
doc.parsed_response['url'].should eq("/_admin/echo?a=1&b=2&foo[]=bar&foo[]=baz")
doc.parsed_response['path'].should eq("/")
doc.parsed_response['parameters'].should eq( { "a"=>"1", "b"=>"2", "foo"=>["bar", "baz"] } )
doc.parsed_response['requestType'].should eq("POST")
doc.parsed_response['requestBody'].should eq("{\"foo\": \"bar\", \"baz\": { \"bump\": true, \"moo\": [ ] } }")
end
it "using PUT, with headers" do
cmd = "/_admin/echo?"
body = "{ }"
headers = { "X-Foo" => "Bar", "x-meow" => "mOO" }
doc = ArangoDB.log_put("#{prefix}-echo", cmd, :body => body, :headers => headers)
doc.code.should eq(200)
doc.parsed_response['url'].should eq("/_admin/echo?")
doc.parsed_response['path'].should eq("/")
doc.parsed_response['parameters'].should eq({ })
doc.parsed_response['requestType'].should eq("PUT")
doc.parsed_response['requestBody'].should eq("{ }")
end
end
################################################################################
## check whether admin interface is accessible
################################################################################

View File

@ -363,6 +363,7 @@ SET(ARANGOD_SOURCES
RestHandler/RestAdminLogHandler.cpp
RestHandler/RestAdminRoutingHandler.cpp
RestHandler/RestAdminServerHandler.cpp
RestHandler/RestAdminStatisticsHandler.cpp
RestHandler/RestAqlFunctionsHandler.cpp
RestHandler/RestAqlUserFunctionsHandler.cpp
RestHandler/RestAuthHandler.cpp
@ -374,7 +375,6 @@ SET(ARANGOD_SOURCES
RestHandler/RestDebugHandler.cpp
RestHandler/RestDemoHandler.cpp
RestHandler/RestDocumentHandler.cpp
RestHandler/RestEchoHandler.cpp
RestHandler/RestEdgesHandler.cpp
RestHandler/RestEndpointHandler.cpp
RestHandler/RestEngineHandler.cpp
@ -436,6 +436,7 @@ SET(ARANGOD_SOURCES
Scheduler/SocketTcp.cpp
Scheduler/Task.cpp
Statistics/ConnectionStatistics.cpp
Statistics/Descriptions.cpp
Statistics/RequestStatistics.cpp
Statistics/ServerStatistics.cpp
Statistics/StatisticsFeature.cpp

View File

@ -45,6 +45,7 @@
#include "RestHandler/RestAdminLogHandler.h"
#include "RestHandler/RestAdminRoutingHandler.h"
#include "RestHandler/RestAdminServerHandler.h"
#include "RestHandler/RestAdminStatisticsHandler.h"
#include "RestHandler/RestAqlFunctionsHandler.h"
#include "RestHandler/RestAqlUserFunctionsHandler.h"
#include "RestHandler/RestAuthHandler.h"
@ -55,7 +56,6 @@
#include "RestHandler/RestDebugHandler.h"
#include "RestHandler/RestDemoHandler.h"
#include "RestHandler/RestDocumentHandler.h"
#include "RestHandler/RestEchoHandler.h"
#include "RestHandler/RestEdgesHandler.h"
#include "RestHandler/RestEndpointHandler.h"
#include "RestHandler/RestEngineHandler.h"
@ -526,9 +526,6 @@ void GeneralServerFeature::defineHandlers() {
"/_admin/work-monitor",
RestHandlerCreator<WorkMonitorHandler>::createNoData);
_handlerFactory->addHandler(
"/_admin/json-echo", RestHandlerCreator<RestEchoHandler>::createNoData);
#ifdef ARANGODB_ENABLE_FAILURE_TESTS
// This handler is to activate SYS_DEBUG_FAILAT on DB servers
_handlerFactory->addPrefixHandler(
@ -548,6 +545,14 @@ void GeneralServerFeature::defineHandlers() {
_handlerFactory->addPrefixHandler(
"/_admin/server",
RestHandlerCreator<arangodb::RestAdminServerHandler>::createNoData);
_handlerFactory->addHandler(
"/_admin/statistics",
RestHandlerCreator<arangodb::RestAdminStatisticsHandler>::createNoData);
_handlerFactory->addHandler(
"/_admin/statistics-description",
RestHandlerCreator<arangodb::RestAdminStatisticsHandler>::createNoData);
// ...........................................................................
// actions defined in v8

View File

@ -0,0 +1,123 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 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 Simon Grätzer
////////////////////////////////////////////////////////////////////////////////
#include "RestAdminStatisticsHandler.h"
#include "Statistics/Descriptions.h"
#include "Statistics/StatisticsFeature.h"
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;
RestAdminStatisticsHandler::RestAdminStatisticsHandler(GeneralRequest* request,
GeneralResponse* response)
: RestBaseHandler(request, response) {}
RestStatus RestAdminStatisticsHandler::execute() {
if (_request->requestType() != rest::RequestType::GET) {
generateError(rest::ResponseCode::METHOD_NOT_ALLOWED,
TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
return RestStatus::DONE;
}
if (_request->requestPath() == "/_admin/statistics") {
getStatistics();
} else if (_request->requestPath() == "/_admin/statistics-description") {
getStatisticsDescription();
} else {
generateError(rest::ResponseCode::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND);
}
// this handler is done
return RestStatus::DONE;
}
void RestAdminStatisticsHandler::getStatistics() {
stats::Descriptions const* desc = StatisticsFeature::descriptions();
if (!desc) {
generateError(rest::ResponseCode::SERVICE_UNAVAILABLE,
TRI_ERROR_SHUTTING_DOWN);
return;
}
VPackBuffer<uint8_t> buffer;
VPackBuilder tmp(buffer);
tmp.add(VPackValue(VPackValueType::Object, true));
tmp.add("time", VPackValue(TRI_microtime()));
tmp.add("enabled", VPackValue(StatisticsFeature::enabled()));
tmp.add("system", VPackValue(VPackValueType::Object, true));
desc->processStatistics(tmp);
tmp.close(); // system
tmp.add("client", VPackValue(VPackValueType::Object, true));
desc->clientStatistics(tmp);
tmp.close(); // client
tmp.add("http", VPackValue(VPackValueType::Object, true));
desc->httpStatistics(tmp);
tmp.close(); // http
tmp.add("server", VPackValue(VPackValueType::Object, true));
desc->serverStatistics(tmp);
tmp.close(); // server
tmp.add(StaticStrings::Error, VPackValue(false));
tmp.add(StaticStrings::Code, VPackValue(static_cast<int>(ResponseCode::OK)));
tmp.close(); // outer
generateResult(ResponseCode::OK, std::move(buffer));
}
void RestAdminStatisticsHandler::getStatisticsDescription() {
stats::Descriptions const* desc = StatisticsFeature::descriptions();
if (!desc) {
generateError(rest::ResponseCode::SERVICE_UNAVAILABLE,
TRI_ERROR_SHUTTING_DOWN);
return;
}
VPackBuffer<uint8_t> buffer;
VPackBuilder tmp(buffer);
tmp.add(VPackValue(VPackValueType::Object));
tmp.add("groups", VPackValue(VPackValueType::Array, true));
for (stats::Group const& group : desc->groups()) {
tmp.openObject();
group.toVPack(tmp);
tmp.close();
}
tmp.close(); // groups
tmp.add("figures", VPackValue(VPackValueType::Array, true));
for (stats::Figure const& figure : desc->figures()) {
tmp.openObject();
figure.toVPack(tmp);
tmp.close();
}
tmp.close(); // figures
tmp.add(StaticStrings::Error, VPackValue(false));
tmp.add(StaticStrings::Code, VPackValue(static_cast<int>(ResponseCode::OK)));
tmp.close(); // outer
generateResult(ResponseCode::OK, std::move(buffer));
}

View File

@ -1,8 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
/// Copyright 2018 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.
@ -18,23 +17,28 @@
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Achim Brandt
/// @author Simon Grätzer
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_REST_HANDLER_REST_ECHO_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_ECHO_HANDLER_H 1
#ifndef ARANGOD_REST_HANDLER_REST_ADMIN_STATISTICS_HANDLER_H
#define ARANGOD_REST_HANDLER_REST_ADMIN_STATISTICS_HANDLER_H 1
#include "RestHandler/RestVocbaseBaseHandler.h"
#include "Basics/Common.h"
#include "RestHandler/RestBaseHandler.h"
namespace arangodb {
class RestEchoHandler : public arangodb::RestVocbaseBaseHandler {
class RestAdminStatisticsHandler : public RestBaseHandler {
public:
RestEchoHandler(GeneralRequest*, GeneralResponse*);
RestAdminStatisticsHandler(GeneralRequest*, GeneralResponse*);
public:
char const* name() const override final { return "RestEchoHandler"; }
bool isDirect() const override { return true; }
RestStatus execute() override;
char const* name() const override final { return "RestAdminStatisticsHandler"; }
bool isDirect() const override final { return false; }
RestStatus execute() override final;
private:
void getStatistics();
void getStatisticsDescription();
};
}

View File

@ -107,7 +107,7 @@ void RestBaseHandler::generateOk(rest::ResponseCode code,
try {
VPackBuffer<uint8_t> buffer;
VPackBuilder tmp(buffer);
tmp.add(VPackValue(VPackValueType::Object));
tmp.add(VPackValue(VPackValueType::Object, true));
tmp.add(StaticStrings::Error, VPackValue(false));
tmp.add(StaticStrings::Code, VPackValue(static_cast<int>(code)));
tmp.add("result", payload);
@ -127,7 +127,7 @@ void RestBaseHandler::generateOk(rest::ResponseCode code,
try {
VPackBuilder tmp;
tmp.add(VPackValue(VPackValueType::Object));
tmp.add(VPackValue(VPackValueType::Object, true));
tmp.add(StaticStrings::Error, VPackValue(false));
tmp.add(StaticStrings::Code, VPackValue(static_cast<int>(code)));
tmp.close();

View File

@ -1,50 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS 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 Achim Brandt
////////////////////////////////////////////////////////////////////////////////
#include "RestEchoHandler.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Rest/HttpRequest.h"
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;
RestEchoHandler::RestEchoHandler(GeneralRequest* request, GeneralResponse* response)
: RestVocbaseBaseHandler(request, response) {}
RestStatus RestEchoHandler::execute() {
bool parseSuccess = true;
std::shared_ptr<VPackBuilder> parsedBody =
parseVelocyPackBody(parseSuccess);
if (parseSuccess) {
VPackBuilder result;
generateResult(rest::ResponseCode::OK, parsedBody->slice());
}
return RestStatus::DONE;
}

View File

@ -0,0 +1,468 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 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 Simon Grätzer
////////////////////////////////////////////////////////////////////////////////
#include "Descriptions.h"
#include "Basics/Common.h"
#include "Basics/process-utils.h"
#include "Statistics/ConnectionStatistics.h"
#include "Statistics/RequestStatistics.h"
#include "Statistics/ServerStatistics.h"
#include "Statistics/StatisticsFeature.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/SchedulerFeature.h"
#include "V8Server/V8DealerFeature.h"
#include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h>
using namespace arangodb;
std::string stats::fromGroupType(stats::GroupType gt) {
switch (gt) {
case stats::GroupType::System:
return "system";
case stats::GroupType::Client:
return "client";
case stats::GroupType::Http:
return "http";
case stats::GroupType::Vst:
return "vst";
case stats::GroupType::Server:
return "server";
}
}
void stats::Group::toVPack(velocypack::Builder& b) const {
b.add("group", VPackValue(stats::fromGroupType(type)));
b.add("name", VPackValue(name));
b.add("description", VPackValue(description));
}
std::string stats::fromFigureType(stats::FigureType t) {
switch (t) {
case stats::FigureType::Current:
return "current";
case stats::FigureType::Accumulated:
return "accumulated";
case stats::FigureType::Distribution:
return "distribution";
}
}
std::string stats::fromUnit(stats::Unit u) {
switch (u) {
case stats::Unit::Seconds:
return "seconds";
case stats::Unit::Bytes:
return "bytes";
case stats::Unit::Percent:
return "percent";
case stats::Unit::Number:
return "number";
}
}
void stats::Figure::toVPack(velocypack::Builder& b) const {
b.add("group", VPackValue(stats::fromGroupType(groupType)));
b.add("identifier", VPackValue(identifier));
b.add("name", VPackValue(name));
b.add("description", VPackValue(description));
b.add("type", VPackValue(stats::fromFigureType(type)));
if (type == stats::FigureType::Distribution) {
TRI_ASSERT(!cuts.empty());
b.add("cuts", VPackValue(VPackValueType::Array, true));
for (double cut : cuts) {
b.add(VPackValue(cut));
}
b.close();
}
b.add("units", VPackValue(stats::fromUnit(units)));
}
stats::Descriptions::Descriptions()
: _requestTimeCuts({0.01, 0.05, 0.1, 0.2, 0.5, 1.0}),
_connectionTimeCuts({0.1, 1.0, 60.0}),
_bytesSendCuts({250, 1000, 2 * 1000, 5 * 1000, 10 * 1000}),
_bytesReceivedCuts({250, 1000, 2 * 1000, 5 * 1000, 10 * 1000}) {
_groups.emplace_back(Group{stats::GroupType::System, "Process Statistics",
"Statistics about the ArangoDB process"});
_groups.emplace_back(Group{stats::GroupType::Client,
"Client Connection Statistics",
"Statistics about the connections."});
_groups.emplace_back(Group{stats::GroupType::Http, "HTTP Request Statistics",
"Statistics about the HTTP requests."});
_groups.emplace_back(Group{stats::GroupType::Server, "Server Statistics",
"Statistics about the ArangoDB server"});
_figures.emplace_back(Figure{stats::GroupType::System,
"userTime",
"User Time",
"Amount of time that this process has been "
"scheduled in user mode, measured in seconds.",
stats::FigureType::Accumulated,
stats::Unit::Seconds,
{}});
_figures.emplace_back(Figure{stats::GroupType::System,
"systemTime",
"System Time",
"Amount of time that this process has been "
"scheduled in kernel mode, measured in seconds.",
stats::FigureType::Accumulated,
stats::Unit::Seconds,
{}});
_figures.emplace_back(Figure{stats::GroupType::System,
"numberOfThreads",
"Number of Threads",
"Number of threads in the arangod process.",
stats::FigureType::Current,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{
stats::GroupType::System,
"residentSize",
"Resident Set Size",
"The total size of the number of pages the process has in real memory. "
"This is just the pages which count toward text, data, or stack space. "
"This does not include pages which have not been demand-loaded in, or "
"which are swapped out. The resident set size is reported in bytes.",
stats::FigureType::Current,
stats::Unit::Bytes,
{}});
_figures.emplace_back(Figure{stats::GroupType::System,
"residentSizePercent",
"Resident Set Size",
"The percentage of physical memory used by the "
"process as resident set size.",
stats::FigureType::Current,
stats::Unit::Percent,
{}});
_figures.emplace_back(Figure{stats::GroupType::System,
"virtualSize",
"Virtual Memory Size",
"On Windows, this figure contains the total "
"amount of memory that the memory manager has "
"committed for the arangod process. On other "
"systems, this figure contains The size of the "
"virtual memory the process is using.",
stats::FigureType::Current,
stats::Unit::Bytes,
{}});
_figures.emplace_back(Figure{stats::GroupType::System,
"minorPageFaults",
"Minor Page Faults",
"The number of minor faults the process has "
"made which have not required loading a memory "
"page from disk. This figure is not reported on "
"Windows.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{
stats::GroupType::System,
"majorPageFaults",
"Major Page Faults",
"On Windows, this figure contains the total number of page faults. On "
"other system, this figure contains the number of major faults the "
"process has made which have required loading a memory page from disk.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
// .............................................................................
// client statistics
// .............................................................................
_figures.emplace_back(
Figure{stats::GroupType::Client,
"httpConnections",
"Client Connections",
"The number of connections that are currently open.",
stats::FigureType::Current,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{
stats::GroupType::Client, "totalTime", "Total Time",
"Total time needed to answer a request.", stats::FigureType::Distribution,
// cuts: internal.requestTimeDistribution,
stats::Unit::Seconds, _requestTimeCuts});
_figures.emplace_back(Figure{stats::GroupType::Client, "requestTime",
"Request Time",
"Request time needed to answer a request.",
stats::FigureType::Distribution,
// cuts: internal.requestTimeDistribution,
stats::Unit::Seconds, _requestTimeCuts});
_figures.emplace_back(Figure{
stats::GroupType::Client, "queueTime", "Queue Time",
"Queue time needed to answer a request.", stats::FigureType::Distribution,
// cuts: internal.requestTimeDistribution,
stats::Unit::Seconds, _requestTimeCuts});
_figures.emplace_back(Figure{stats::GroupType::Client, "bytesSent",
"Bytes Sent", "Bytes sents for a request.",
stats::FigureType::Distribution,
// cuts: internal.bytesSentDistribution,
stats::Unit::Bytes, _bytesSendCuts});
_figures.emplace_back(
Figure{stats::GroupType::Client, "bytesReceived", "Bytes Received",
"Bytes receiveds for a request.", stats::FigureType::Distribution,
// cuts: internal.bytesReceivedDistribution,
stats::Unit::Bytes, _bytesReceivedCuts});
_figures.emplace_back(Figure{
stats::GroupType::Client, "connectionTime", "Connection Time",
"Total connection time of a client.", stats::FigureType::Distribution,
// cuts: internal.connectionTimeDistribution,
stats::Unit::Seconds, _connectionTimeCuts});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsTotal",
"Total requests",
"Total number of HTTP requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(
Figure{stats::GroupType::Http,
"requestsAsync",
"Async requests",
"Number of asynchronously executed HTTP requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsGet",
"HTTP GET requests",
"Number of HTTP GET requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsHead",
"HTTP HEAD requests",
"Number of HTTP HEAD requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsPost",
"HTTP POST requests",
"Number of HTTP POST requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsPut",
"HTTP PUT requests",
"Number of HTTP PUT requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsPatch",
"HTTP PATCH requests",
"Number of HTTP PATCH requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsDelete",
"HTTP DELETE requests",
"Number of HTTP DELETE requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsOptions",
"HTTP OPTIONS requests",
"Number of HTTP OPTIONS requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
_figures.emplace_back(Figure{stats::GroupType::Http,
"requestsOther",
"other HTTP requests",
"Number of other HTTP requests.",
stats::FigureType::Accumulated,
stats::Unit::Number,
{}});
// .............................................................................
// server statistics
// .............................................................................
_figures.emplace_back(Figure{stats::GroupType::Server,
"uptime",
"Server Uptime",
"Number of seconds elapsed since server start.",
stats::FigureType::Current,
stats::Unit::Seconds,
{}});
_figures.emplace_back(Figure{stats::GroupType::Server,
"physicalMemory",
"Physical Memory",
"Physical memory in bytes.",
stats::FigureType::Current,
stats::Unit::Bytes,
{}});
}
void stats::Descriptions::serverStatistics(velocypack::Builder& b) const {
ServerStatistics info = ServerStatistics::statistics();
b.add("uptime", VPackValue(info._uptime));
b.add("physicalMemory", VPackValue((double)TRI_PhysicalMemory));
V8DealerFeature* dealer =
application_features::ApplicationServer::getFeature<V8DealerFeature>("V8Dealer");
b.add("v8Context", VPackValue(VPackValueType::Object, true));
auto v8Counters = dealer->getCurrentContextNumbers();
b.add( "available", VPackValue(static_cast<int32_t>(v8Counters.available)));
b.add( "busy", VPackValue(static_cast<int32_t>(v8Counters.busy)));
b.add( "dirty", VPackValue(static_cast<int32_t>(v8Counters.dirty)));
b.add( "free", VPackValue(static_cast<int32_t>(v8Counters.free)));
b.add( "max", VPackValue(static_cast<int32_t>(v8Counters.max)));
b.close();
b.add("threads", VPackValue(VPackValueType::Object, true));
auto countersRaw = SchedulerFeature::SCHEDULER->getCounters();
b.add("running", VPackValue(static_cast<int32_t>(rest::Scheduler::numRunning(countersRaw))));
b.add("working", VPackValue(static_cast<int32_t>(rest::Scheduler::numWorking(countersRaw))));
b.add("blocked", VPackValue(static_cast<int32_t>(rest::Scheduler::numBlocked(countersRaw))));
b.add("queued", VPackValue(static_cast<int32_t>(SchedulerFeature::SCHEDULER->numQueued())));
b.close();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief fills the distribution
////////////////////////////////////////////////////////////////////////////////
static void FillDistribution(VPackBuilder& b, std::string const& name,
basics::StatisticsDistribution const& dist) {
b.add(name, VPackValue(VPackValueType::Object, true));
b.add("sum", VPackValue(dist._total));
b.add("count", VPackValue((double)dist._count));
b.add("counts", VPackValue(VPackValueType::Array, true));
for (std::vector<uint64_t>::const_iterator i = dist._counts.begin();
i != dist._counts.end(); ++i) {
b.add(VPackValue(*i));
}
b.close();
b.close();
}
void stats::Descriptions::clientStatistics(velocypack::Builder& b) const {
basics::StatisticsCounter httpConnections;
basics::StatisticsCounter totalRequests;
std::vector<basics::StatisticsCounter> methodRequests;
basics::StatisticsCounter asyncRequests;
basics::StatisticsDistribution connectionTime;
// FIXME why are httpConnections in here ?
ConnectionStatistics::fill(httpConnections, totalRequests, methodRequests,
asyncRequests, connectionTime);
b.add("httpConnections", VPackValue((double)httpConnections._count));
FillDistribution(b, "connectionTime", connectionTime);
basics::StatisticsDistribution totalTime;
basics::StatisticsDistribution requestTime;
basics::StatisticsDistribution queueTime;
basics::StatisticsDistribution ioTime;
basics::StatisticsDistribution bytesSent;
basics::StatisticsDistribution bytesReceived;
RequestStatistics::fill(totalTime, requestTime, queueTime, ioTime, bytesSent,
bytesReceived);
FillDistribution(b, "totalTime", totalTime);
FillDistribution(b, "requestTime", requestTime);
FillDistribution(b, "queueTime", queueTime);
FillDistribution(b, "ioTime", ioTime);
FillDistribution(b, "bytesSent", bytesSent);
FillDistribution(b, "bytesReceived", bytesReceived);
}
void stats::Descriptions::httpStatistics(velocypack::Builder& b) const {
basics::StatisticsCounter httpConnections;
basics::StatisticsCounter totalRequests;
std::vector<basics::StatisticsCounter> methodRequests;
basics::StatisticsCounter asyncRequests;
basics::StatisticsDistribution connectionTime;
ConnectionStatistics::fill(httpConnections, totalRequests, methodRequests,
asyncRequests, connectionTime);
// request counters
b.add("requestsTotal", VPackValue((double)totalRequests._count));
b.add("requestsAsync", VPackValue((double)asyncRequests._count));
b.add("requestsGet", VPackValue((double)methodRequests[(int)rest::RequestType::GET]._count));
b.add("requestsHead", VPackValue((double)methodRequests[(int)rest::RequestType::HEAD]._count));
b.add("requestsPost", VPackValue((double)methodRequests[(int)rest::RequestType::POST]._count));
b.add("requestsPut", VPackValue((double)methodRequests[(int)rest::RequestType::PUT]._count));
b.add("requestsPatch", VPackValue((double)methodRequests[(int)rest::RequestType::PATCH]._count));
b.add("requestsDelete", VPackValue((double)methodRequests[(int)rest::RequestType::DELETE_REQ]._count));
b.add("requestsOptions", VPackValue((double)methodRequests[(int)rest::RequestType::OPTIONS]._count));
b.add("requestsOther", VPackValue((double)methodRequests[(int)rest::RequestType::ILLEGAL]._count));
}
void stats::Descriptions::processStatistics(VPackBuilder& b) const {
ProcessInfo info = TRI_ProcessInfoSelf();
double rss = (double)info._residentSize;
double rssp = 0;
if (TRI_PhysicalMemory != 0) {
rssp = rss / TRI_PhysicalMemory;
}
b.add("minorPageFaults", VPackValue((double)info._minorPageFaults));
b.add("majorPageFaults", VPackValue((double)info._majorPageFaults));
b.add("userTime", VPackValue((double)info._userTime / (double)info._scClkTck));
b.add("systemTime", VPackValue((double)info._systemTime / (double)info._scClkTck));
b.add("numberOfThreads", VPackValue((double)info._numberThreads));
b.add("residentSize", VPackValue(rss));
b.add("residentSizePercent", VPackValue(rssp));
b.add("virtualSize", VPackValue((double)info._virtualSize));
}

View File

@ -0,0 +1,95 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 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 Simon Grätzer
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_STATISTICS_DESCRIPTIONS_H
#define ARANGOD_STATISTICS_DESCRIPTIONS_H 1
#include <velocypack/Builder.h>
#include <string>
namespace arangodb {
namespace stats {
enum class GroupType { System, Client, Http, Vst, Server };
std::string fromGroupType(stats::GroupType);
struct Group {
stats::GroupType type;
std::string name;
std::string description;
public:
void toVPack(velocypack::Builder&) const;
};
enum class FigureType : char { Current, Accumulated, Distribution };
std::string fromFigureType(stats::FigureType);
enum class Unit : char { Seconds, Bytes, Percent, Number };
std::string fromUnit(stats::Unit);
struct Figure {
stats::GroupType groupType;
std::string identifier;
std::string name;
std::string description;
stats::FigureType type;
stats::Unit units;
std::vector<double> cuts;
public:
void toVPack(velocypack::Builder&) const;
};
class Descriptions final {
public:
Descriptions();
std::vector<stats::Group> const& groups() const { return _groups; }
std::vector<stats::Figure> const& figures() const {
return _figures;
}
void serverStatistics(velocypack::Builder&) const;
void clientStatistics(velocypack::Builder&) const;
void httpStatistics(velocypack::Builder&) const;
void processStatistics(velocypack::Builder&) const;
private:
std::vector<double> _requestTimeCuts;
std::vector<double> _connectionTimeCuts;
std::vector<double> _bytesSendCuts;
std::vector<double> _bytesReceivedCuts;
std::vector<stats::Group> _groups;
std::vector<stats::Figure> _figures;
};
}
}
#endif

View File

@ -25,6 +25,7 @@
#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"
@ -117,7 +118,9 @@ StatisticsFeature* StatisticsFeature::STATISTICS = nullptr;
StatisticsFeature::StatisticsFeature(
application_features::ApplicationServer* server)
: ApplicationFeature(server, "Statistics"), _statistics(true) {
: ApplicationFeature(server, "Statistics"),
_statistics(true),
_descriptions(new stats::Descriptions()) {
startsAfter("Logger");
startsAfter("Aql");
}

View File

@ -45,6 +45,9 @@ extern StatisticsVector TRI_ConnectionTimeDistributionVectorStatistics;
extern StatisticsVector TRI_RequestTimeDistributionVectorStatistics;
extern std::vector<StatisticsCounter> TRI_MethodRequestsStatistics;
}
namespace stats{
class Descriptions;
}
class StatisticsThread;
class StatisticsWorker;
@ -70,12 +73,20 @@ class StatisticsFeature final
void start() override final;
void unprepare() override final;
static stats::Descriptions const* descriptions() {
if (STATISTICS != nullptr) {
return STATISTICS->_descriptions.get();
}
return nullptr;
}
public:
void disableStatistics() { _statistics = false; }
private:
bool _statistics;
std::unique_ptr<stats::Descriptions> _descriptions;
std::unique_ptr<StatisticsThread> _statisticsThread;
std::unique_ptr<StatisticsWorker> _statisticsWorker;
};

View File

@ -32,7 +32,6 @@ var internal = require('internal');
var console = require('console');
var actions = require('@arangodb/actions');
var arangodb = require('@arangodb');
// //////////////////////////////////////////////////////////////////////////////
// / @brief was docuBlock JSF_get_admin_time
@ -47,375 +46,6 @@ actions.defineHttp({
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief was docuBlock JSF_get_admin_echo
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/echo',
prefix: true,
callback: function (req, res) {
res.responseCode = actions.HTTP_OK;
res.contentType = 'application/json; charset=utf-8';
req.rawRequestBody = require('internal').rawRequestBody(req);
res.body = JSON.stringify(req);
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief was docuBlock JSF_get_admin_statistics
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/statistics',
prefix: false,
callback: function (req, res) {
var result;
try {
result = {};
result.time = internal.time();
result.enabled = internal.enabledStatistics();
result.system = internal.processStatistics();
result.client = internal.clientStatistics();
result.http = internal.httpStatistics();
result.server = internal.serverStatistics();
actions.resultOk(req, res, actions.HTTP_OK, result);
} catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief was docuBlock JSF_get_admin_statistics_description
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/statistics-description',
prefix: false,
callback: function (req, res) {
var result;
try {
result = {
groups: [
{
group: 'system',
name: 'Process Statistics',
description: 'Statistics about the ArangoDB process'
},
{
group: 'client',
name: 'Client Connection Statistics',
description: 'Statistics about the connections.'
},
{
group: 'http',
name: 'HTTP Request Statistics',
description: 'Statistics about the HTTP requests.'
},
{
group: 'server',
name: 'Server Statistics',
description: 'Statistics about the ArangoDB server'
}
],
figures: [
// .............................................................................
// system statistics
// .............................................................................
{
group: 'system',
identifier: 'userTime',
name: 'User Time',
description: 'Amount of time that this process has been scheduled in user mode, ' +
'measured in seconds.',
type: 'accumulated',
units: 'seconds'
},
{
group: 'system',
identifier: 'systemTime',
name: 'System Time',
description: 'Amount of time that this process has been scheduled in kernel mode, ' +
'measured in seconds.',
type: 'accumulated',
units: 'seconds'
},
{
group: 'system',
identifier: 'numberOfThreads',
name: 'Number of Threads',
description: 'Number of threads in the arangod process.',
type: 'current',
units: 'number'
},
{
group: 'system',
identifier: 'residentSize',
name: 'Resident Set Size',
description: 'The total size of the number of pages the process has in real memory. ' +
'This is just the pages which count toward text, data, or stack space. ' +
'This does not include pages which have not been demand-loaded in, ' +
'or which are swapped out. The resident set size is reported in bytes.',
type: 'current',
units: 'bytes'
},
{
group: 'system',
identifier: 'residentSizePercent',
name: 'Resident Set Size',
description: 'The percentage of physical memory used by the process as resident ' +
'set size.',
type: 'current',
units: 'percent'
},
{
group: 'system',
identifier: 'virtualSize',
name: 'Virtual Memory Size',
description: 'On Windows, this figure contains the total amount of memory that the ' +
'memory manager has committed for the arangod process. On other ' +
'systems, this figure contains The size of the virtual memory the ' +
'process is using.',
type: 'current',
units: 'bytes'
},
{
group: 'system',
identifier: 'minorPageFaults',
name: 'Minor Page Faults',
description: 'The number of minor faults the process has made which have ' +
'not required loading a memory page from disk. This figure is ' +
'not reported on Windows.',
type: 'accumulated',
units: 'number'
},
{
group: 'system',
identifier: 'majorPageFaults',
name: 'Major Page Faults',
description: 'On Windows, this figure contains the total number of page faults. ' +
'On other system, this figure contains the number of major faults the ' +
'process has made which have required loading a memory page from disk.',
type: 'accumulated',
units: 'number'
},
// .............................................................................
// client statistics
// .............................................................................
{
group: 'client',
identifier: 'httpConnections',
name: 'Client Connections',
description: 'The number of connections that are currently open.',
type: 'current',
units: 'number'
},
{
group: 'client',
identifier: 'totalTime',
name: 'Total Time',
description: 'Total time needed to answer a request.',
type: 'distribution',
cuts: internal.requestTimeDistribution,
units: 'seconds'
},
{
group: 'client',
identifier: 'requestTime',
name: 'Request Time',
description: 'Request time needed to answer a request.',
type: 'distribution',
cuts: internal.requestTimeDistribution,
units: 'seconds'
},
{
group: 'client',
identifier: 'queueTime',
name: 'Queue Time',
description: 'Queue time needed to answer a request.',
type: 'distribution',
cuts: internal.requestTimeDistribution,
units: 'seconds'
},
{
group: 'client',
identifier: 'bytesSent',
name: 'Bytes Sent',
description: 'Bytes sents for a request.',
type: 'distribution',
cuts: internal.bytesSentDistribution,
units: 'bytes'
},
{
group: 'client',
identifier: 'bytesReceived',
name: 'Bytes Received',
description: 'Bytes receiveds for a request.',
type: 'distribution',
cuts: internal.bytesReceivedDistribution,
units: 'bytes'
},
{
group: 'client',
identifier: 'connectionTime',
name: 'Connection Time',
description: 'Total connection time of a client.',
type: 'distribution',
cuts: internal.connectionTimeDistribution,
units: 'seconds'
},
{
group: 'http',
identifier: 'requestsTotal',
name: 'Total requests',
description: 'Total number of HTTP requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsAsync',
name: 'Async requests',
description: 'Number of asynchronously executed HTTP requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsGet',
name: 'HTTP GET requests',
description: 'Number of HTTP GET requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsHead',
name: 'HTTP HEAD requests',
description: 'Number of HTTP HEAD requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsPost',
name: 'HTTP POST requests',
description: 'Number of HTTP POST requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsPut',
name: 'HTTP PUT requests',
description: 'Number of HTTP PUT requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsPatch',
name: 'HTTP PATCH requests',
description: 'Number of HTTP PATCH requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsDelete',
name: 'HTTP DELETE requests',
description: 'Number of HTTP DELETE requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsOptions',
name: 'HTTP OPTIONS requests',
description: 'Number of HTTP OPTIONS requests.',
type: 'accumulated',
units: 'number'
},
{
group: 'http',
identifier: 'requestsOther',
name: 'other HTTP requests',
description: 'Number of other HTTP requests.',
type: 'accumulated',
units: 'number'
},
// .............................................................................
// server statistics
// .............................................................................
{
group: 'server',
identifier: 'uptime',
name: 'Server Uptime',
description: 'Number of seconds elapsed since server start.',
type: 'current',
units: 'seconds'
},
{
group: 'server',
identifier: 'physicalMemory',
name: 'Physical Memory',
description: 'Physical memory in bytes.',
type: 'current',
units: 'bytes'
}
]
};
actions.resultOk(req, res, actions.HTTP_OK, result);
} catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief was docuBlock JSF_post_admin_execute
// //////////////////////////////////////////////////////////////////////////////