1
0
Fork 0
arangodb/arangod/V8Server/v8-statistics.cpp

325 lines
14 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// 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 Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "v8-statistics.h"
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/Exceptions.h"
#include "Basics/StringUtils.h"
#include "Basics/process-utils.h"
#include "Rest/GeneralRequest.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/SchedulerFeature.h"
#include "Statistics/ConnectionStatistics.h"
#include "Statistics/RequestStatistics.h"
#include "Statistics/ServerStatistics.h"
#include "Statistics/StatisticsFeature.h"
#include "V8/v8-conv.h"
#include "V8/v8-globals.h"
#include "V8/v8-utils.h"
#include "V8Server/V8DealerFeature.h"
using namespace arangodb;
using namespace arangodb::basics;
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a distribution vector
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Array> DistributionList(v8::Isolate* isolate,
std::vector<double> const& dist) {
v8::EscapableHandleScope scope(isolate);
v8::Handle<v8::Array> result = v8::Array::New(isolate);
for (uint32_t i = 0; i < (uint32_t)dist.size(); ++i) {
result->Set(i, v8::Number::New(isolate, dist[i]));
}
return scope.Escape<v8::Array>(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief fills the distribution
////////////////////////////////////////////////////////////////////////////////
static void FillDistribution(v8::Isolate* isolate, v8::Handle<v8::Object> list,
v8::Handle<v8::String> name,
StatisticsDistribution const& dist) {
v8::Handle<v8::Object> result = v8::Object::New(isolate);
result->Set(TRI_V8_ASCII_STRING(isolate, "sum"), v8::Number::New(isolate, dist._total));
result->Set(TRI_V8_ASCII_STRING(isolate, "count"),
v8::Number::New(isolate, (double)dist._count));
v8::Handle<v8::Array> counts = v8::Array::New(isolate, (int)dist._counts.size());
uint32_t pos = 0;
for (std::vector<uint64_t>::const_iterator i = dist._counts.begin();
i != dist._counts.end(); ++i, ++pos) {
counts->Set(pos, v8::Number::New(isolate, (double)*i));
}
result->Set(TRI_V8_ASCII_STRING(isolate, "counts"), counts);
list->Set(name, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns server statistics
///
/// @FUN{internal.serverStatistics()}
///
/// Returns information about the server:
///
/// - `uptime`: time since server start in seconds.
////////////////////////////////////////////////////////////////////////////////
static void JS_ServerStatistics(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate)
v8::HandleScope scope(isolate);
ServerStatistics info = ServerStatistics::statistics();
v8::Handle<v8::Object> result = v8::Object::New(isolate);
result->Set(TRI_V8_ASCII_STRING(isolate, "uptime"),
v8::Number::New(isolate, (double)info._uptime));
result->Set(TRI_V8_ASCII_STRING(isolate, "physicalMemory"),
v8::Number::New(isolate, (double)TRI_PhysicalMemory));
v8::Handle<v8::Object> v8CountersObj = v8::Object::New(isolate);
V8DealerFeature* dealer =
application_features::ApplicationServer::getFeature<V8DealerFeature>(
"V8Dealer");
auto v8Counters = dealer->getCurrentContextNumbers();
v8CountersObj->Set(TRI_V8_ASCII_STRING(isolate, "available"),
v8::Number::New(isolate, static_cast<int32_t>(v8Counters.available)));
v8CountersObj->Set(TRI_V8_ASCII_STRING(isolate, "busy"),
v8::Number::New(isolate, static_cast<int32_t>(v8Counters.busy)));
v8CountersObj->Set(TRI_V8_ASCII_STRING(isolate, "dirty"),
v8::Number::New(isolate, static_cast<int32_t>(v8Counters.dirty)));
v8CountersObj->Set(TRI_V8_ASCII_STRING(isolate, "free"),
v8::Number::New(isolate, static_cast<int32_t>(v8Counters.free)));
v8CountersObj->Set(TRI_V8_ASCII_STRING(isolate, "max"),
v8::Number::New(isolate, static_cast<int32_t>(v8Counters.max)));
auto memoryStatistics = dealer->getCurrentMemoryNumbers();
v8::Handle<v8::Array> v8ListOfMemory = v8::Array::New(isolate, static_cast<int>(memoryStatistics.size()));
uint32_t pos = 0;
for (auto memStatistic : memoryStatistics) {
v8::Handle<v8::Object> v8MemStat = v8::Object::New(isolate);
v8MemStat->Set(TRI_V8_ASCII_STRING(isolate, "contextId"),
v8::Integer::New(isolate, static_cast<int32_t>(memStatistic.id)));
v8MemStat->Set(TRI_V8_ASCII_STRING(isolate, "tMax"),
v8::Number::New(isolate, (double)memStatistic.tMax));
v8MemStat->Set(TRI_V8_ASCII_STRING(isolate, "countOfTimes"),
v8::Integer::New(isolate, static_cast<int32_t>(memStatistic.countOfTimes)));
v8MemStat->Set(TRI_V8_ASCII_STRING(isolate, "heapMax"),
v8::Number::New(isolate, (double)memStatistic.heapMax));
v8MemStat->Set(TRI_V8_ASCII_STRING(isolate, "heapMin"),
v8::Number::New(isolate, (double)memStatistic.heapMin));
v8ListOfMemory->Set(pos++, v8MemStat);
}
v8CountersObj->Set(TRI_V8_ASCII_STRING(isolate, "memory"),
v8ListOfMemory);
result->Set(TRI_V8_ASCII_STRING(isolate, "v8Context"), v8CountersObj);
v8::Handle<v8::Object> counters = v8::Object::New(isolate);
auto qs = SchedulerFeature::SCHEDULER->queueStatistics();
counters->Set(TRI_V8_ASCII_STRING(isolate, "schedulerThreads"),
v8::Number::New(isolate, static_cast<int32_t>(qs._running)));
counters->Set(TRI_V8_ASCII_STRING(isolate, "inProgress"),
v8::Number::New(isolate, static_cast<int32_t>(qs._working)));
counters->Set(TRI_V8_ASCII_STRING(isolate, "queued"),
v8::Number::New(isolate, static_cast<int32_t>(qs._queued)));
result->Set(TRI_V8_ASCII_STRING(isolate, "threads"), counters);
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not server-side statistics are enabled
////////////////////////////////////////////////////////////////////////////////
static void JS_EnabledStatistics(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate)
v8::HandleScope scope(isolate);
v8::Handle<v8::Value> result = v8::Boolean::New(isolate, StatisticsFeature::enabled());
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current request and connection statistics
////////////////////////////////////////////////////////////////////////////////
static void JS_ClientStatistics(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate)
v8::HandleScope scope(isolate);
v8::Handle<v8::Object> result = v8::Object::New(isolate);
StatisticsCounter httpConnections;
StatisticsCounter totalRequests;
std::vector<StatisticsCounter> methodRequests;
StatisticsCounter asyncRequests;
StatisticsDistribution connectionTime;
ConnectionStatistics::fill(httpConnections, totalRequests, methodRequests,
asyncRequests, connectionTime);
result->Set(TRI_V8_ASCII_STRING(isolate, "httpConnections"),
v8::Number::New(isolate, (double)httpConnections._count));
FillDistribution(isolate, result,
TRI_V8_ASCII_STRING(isolate, "connectionTime"), connectionTime);
StatisticsDistribution totalTime;
StatisticsDistribution requestTime;
StatisticsDistribution queueTime;
StatisticsDistribution ioTime;
StatisticsDistribution bytesSent;
StatisticsDistribution bytesReceived;
RequestStatistics::fill(totalTime, requestTime, queueTime, ioTime, bytesSent, bytesReceived);
FillDistribution(isolate, result, TRI_V8_ASCII_STRING(isolate, "totalTime"), totalTime);
FillDistribution(isolate, result, TRI_V8_ASCII_STRING(isolate, "requestTime"), requestTime);
FillDistribution(isolate, result, TRI_V8_ASCII_STRING(isolate, "queueTime"), queueTime);
FillDistribution(isolate, result, TRI_V8_ASCII_STRING(isolate, "ioTime"), ioTime);
FillDistribution(isolate, result, TRI_V8_ASCII_STRING(isolate, "bytesSent"), bytesSent);
FillDistribution(isolate, result,
TRI_V8_ASCII_STRING(isolate, "bytesReceived"), bytesReceived);
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current http statistics
////////////////////////////////////////////////////////////////////////////////
static void JS_HttpStatistics(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
v8::Handle<v8::Object> result = v8::Object::New(isolate);
StatisticsCounter httpConnections;
StatisticsCounter totalRequests;
std::vector<StatisticsCounter> methodRequests;
StatisticsCounter asyncRequests;
StatisticsDistribution connectionTime;
ConnectionStatistics::fill(httpConnections, totalRequests, methodRequests,
asyncRequests, connectionTime);
// request counters
result->Set(TRI_V8_ASCII_STRING(isolate, "requestsTotal"),
v8::Number::New(isolate, (double)totalRequests._count));
result->Set(TRI_V8_ASCII_STRING(isolate, "requestsAsync"),
v8::Number::New(isolate, (double)asyncRequests._count));
result->Set(TRI_V8_ASCII_STRING(isolate, "requestsGet"),
v8::Number::New(
isolate, (double)methodRequests[(int)rest::RequestType::GET]._count));
result->Set(TRI_V8_ASCII_STRING(isolate, "requestsHead"),
v8::Number::New(
isolate, (double)methodRequests[(int)rest::RequestType::HEAD]._count));
result->Set(TRI_V8_ASCII_STRING(isolate, "requestsPost"),
v8::Number::New(
isolate, (double)methodRequests[(int)rest::RequestType::POST]._count));
result->Set(TRI_V8_ASCII_STRING(isolate, "requestsPut"),
v8::Number::New(
isolate, (double)methodRequests[(int)rest::RequestType::PUT]._count));
result->Set(TRI_V8_ASCII_STRING(isolate, "requestsPatch"),
v8::Number::New(
isolate, (double)methodRequests[(int)rest::RequestType::PATCH]._count));
result->Set(
TRI_V8_ASCII_STRING(isolate, "requestsDelete"),
v8::Number::New(isolate,
(double)methodRequests[(int)rest::RequestType::DELETE_REQ]._count));
result->Set(
TRI_V8_ASCII_STRING(isolate, "requestsOptions"),
v8::Number::New(isolate,
(double)methodRequests[(int)rest::RequestType::OPTIONS]._count));
result->Set(
TRI_V8_ASCII_STRING(isolate, "requestsOther"),
v8::Number::New(isolate,
(double)methodRequests[(int)rest::RequestType::ILLEGAL]._count));
TRI_V8_RETURN(result);
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief initializes the statistics functions
////////////////////////////////////////////////////////////////////////////////
void TRI_InitV8Statistics(v8::Isolate* isolate, v8::Handle<v8::Context> context) {
v8::HandleScope scope(isolate);
// .............................................................................
// create the global functions
// .............................................................................
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate,
"SYS_ENABLED_STATISTICS"),
JS_EnabledStatistics);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate,
"SYS_CLIENT_STATISTICS"),
JS_ClientStatistics);
TRI_AddGlobalFunctionVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "SYS_HTTP_STATISTICS"), JS_HttpStatistics);
TRI_AddGlobalFunctionVocbase(isolate,
TRI_V8_ASCII_STRING(isolate,
"SYS_SERVER_STATISTICS"),
JS_ServerStatistics);
TRI_AddGlobalVariableVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "CONNECTION_TIME_DISTRIBUTION"),
DistributionList(isolate, TRI_ConnectionTimeDistributionVectorStatistics));
TRI_AddGlobalVariableVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "REQUEST_TIME_DISTRIBUTION"),
DistributionList(isolate, TRI_RequestTimeDistributionVectorStatistics));
TRI_AddGlobalVariableVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "BYTES_SENT_DISTRIBUTION"),
DistributionList(isolate, TRI_BytesSentDistributionVectorStatistics));
TRI_AddGlobalVariableVocbase(
isolate, TRI_V8_ASCII_STRING(isolate, "BYTES_RECEIVED_DISTRIBUTION"),
DistributionList(isolate, TRI_BytesReceivedDistributionVectorStatistics));
}