mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
feat(stats): introduce support for queuing messages
This commit is contained in:
parent
fc4a736e2a
commit
38b1643fe6
@ -772,6 +772,7 @@ void SetupServerArgs(ArgsManager& argsman)
|
|||||||
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
|
|
||||||
argsman.AddArg("-statsenabled", strprintf("Publish internal stats to statsd (default: %u)", DEFAULT_STATSD_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
argsman.AddArg("-statsenabled", strprintf("Publish internal stats to statsd (default: %u)", DEFAULT_STATSD_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
||||||
|
argsman.AddArg("-statsduration=<ms>", strprintf("Specify the number of milliseconds between stats messages (default: %d)", DEFAULT_STATSD_DURATION), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
||||||
argsman.AddArg("-statshost=<ip>", strprintf("Specify statsd host (default: %s)", DEFAULT_STATSD_HOST), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
argsman.AddArg("-statshost=<ip>", strprintf("Specify statsd host (default: %s)", DEFAULT_STATSD_HOST), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
||||||
argsman.AddArg("-statshostname=<ip>", strprintf("Specify statsd host name (default: %s)", DEFAULT_STATSD_HOSTNAME), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
argsman.AddArg("-statshostname=<ip>", strprintf("Specify statsd host name (default: %s)", DEFAULT_STATSD_HOSTNAME), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
||||||
argsman.AddArg("-statsport=<port>", strprintf("Specify statsd port (default: %u)", DEFAULT_STATSD_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
argsman.AddArg("-statsport=<port>", strprintf("Specify statsd port (default: %u)", DEFAULT_STATSD_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
|
||||||
@ -1540,8 +1541,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||||||
// regardless of whether transmitting stats are desirable or not and if
|
// regardless of whether transmitting stats are desirable or not and if
|
||||||
// g_stats_client isn't present when that attempt is made, the client will crash.
|
// g_stats_client isn't present when that attempt is made, the client will crash.
|
||||||
::g_stats_client = std::make_unique<StatsdClient>(args.GetArg("-statshost", DEFAULT_STATSD_HOST),
|
::g_stats_client = std::make_unique<StatsdClient>(args.GetArg("-statshost", DEFAULT_STATSD_HOST),
|
||||||
args.GetArg("-statshostname", DEFAULT_STATSD_HOSTNAME),
|
|
||||||
args.GetArg("-statsport", DEFAULT_STATSD_PORT),
|
args.GetArg("-statsport", DEFAULT_STATSD_PORT),
|
||||||
|
args.GetArg("-statsduration", DEFAULT_STATSD_DURATION),
|
||||||
|
args.GetArg("-statshostname", DEFAULT_STATSD_HOSTNAME),
|
||||||
args.GetArg("-statsns", DEFAULT_STATSD_NAMESPACE),
|
args.GetArg("-statsns", DEFAULT_STATSD_NAMESPACE),
|
||||||
args.GetBoolArg("-statsenabled", DEFAULT_STATSD_ENABLE));
|
args.GetBoolArg("-statsenabled", DEFAULT_STATSD_ENABLE));
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ bool StatsdClient::ShouldSend(float sample_rate)
|
|||||||
return sample_rate > std::uniform_real_distribution<float>(0.f, 1.f)(insecure_rand);
|
return sample_rate > std::uniform_real_distribution<float>(0.f, 1.f)(insecure_rand);
|
||||||
}
|
}
|
||||||
|
|
||||||
StatsdClient::StatsdClient(const std::string& host, const std::string& nodename, uint16_t port,
|
StatsdClient::StatsdClient(const std::string& host, uint16_t port, uint64_t interval_ms, const std::string& nodename,
|
||||||
const std::string& ns, bool enabled) :
|
const std::string& ns, bool enabled) :
|
||||||
m_nodename{nodename},
|
m_nodename{nodename},
|
||||||
m_ns{ns}
|
m_ns{ns}
|
||||||
@ -71,7 +71,7 @@ StatsdClient::StatsdClient(const std::string& host, const std::string& nodename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> error_opt;
|
std::optional<std::string> error_opt;
|
||||||
m_sender = std::make_unique<RawSender>(host, port, error_opt);
|
m_sender = std::make_unique<RawSender>(host, port, interval_ms, error_opt);
|
||||||
if (error_opt.has_value()) {
|
if (error_opt.has_value()) {
|
||||||
LogPrintf("ERROR: %s, cannot initialize StatsdClient.\n", error_opt.value());
|
LogPrintf("ERROR: %s, cannot initialize StatsdClient.\n", error_opt.value());
|
||||||
m_sender.reset();
|
m_sender.reset();
|
||||||
|
@ -21,16 +21,20 @@ static const std::string DEFAULT_STATSD_HOST{"127.0.0.1"};
|
|||||||
static const std::string DEFAULT_STATSD_HOSTNAME{""};
|
static const std::string DEFAULT_STATSD_HOSTNAME{""};
|
||||||
static const std::string DEFAULT_STATSD_NAMESPACE{""};
|
static const std::string DEFAULT_STATSD_NAMESPACE{""};
|
||||||
|
|
||||||
// schedule periodic measurements, in seconds: default - 1 minute, min - 5 sec, max - 1h.
|
/** Default number of milliseconds between flushing a queue of messages */
|
||||||
|
static constexpr int DEFAULT_STATSD_DURATION{1000};
|
||||||
|
/** Default number of seconds between recording periodic stats */
|
||||||
static constexpr int DEFAULT_STATSD_PERIOD{60};
|
static constexpr int DEFAULT_STATSD_PERIOD{60};
|
||||||
|
/** Minimum number of seconds between recording periodic stats */
|
||||||
static constexpr int MIN_STATSD_PERIOD{5};
|
static constexpr int MIN_STATSD_PERIOD{5};
|
||||||
|
/** Maximum number of seconds between recording periodic stats */
|
||||||
static constexpr int MAX_STATSD_PERIOD{60 * 60};
|
static constexpr int MAX_STATSD_PERIOD{60 * 60};
|
||||||
|
|
||||||
class StatsdClient
|
class StatsdClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit StatsdClient(const std::string& host, const std::string& nodename, uint16_t port,
|
explicit StatsdClient(const std::string& host, uint16_t port, uint64_t interval_ms, const std::string& nodename,
|
||||||
const std::string& ns, bool enabled);
|
const std::string& ns, bool enabled);
|
||||||
~StatsdClient();
|
~StatsdClient();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -8,10 +8,13 @@
|
|||||||
#include <netaddress.h>
|
#include <netaddress.h>
|
||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
#include <util/sock.h>
|
#include <util/sock.h>
|
||||||
|
#include <util/thread.h>
|
||||||
|
|
||||||
RawSender::RawSender(const std::string& host, uint16_t port, std::optional<std::string>& error) :
|
RawSender::RawSender(const std::string& host, uint16_t port, uint64_t interval_ms,
|
||||||
|
std::optional<std::string>& error) :
|
||||||
m_host{host},
|
m_host{host},
|
||||||
m_port{port}
|
m_port{port},
|
||||||
|
m_interval_ms{interval_ms}
|
||||||
{
|
{
|
||||||
if (host.empty()) {
|
if (host.empty()) {
|
||||||
error = "No host specified";
|
error = "No host specified";
|
||||||
@ -39,16 +42,42 @@ RawSender::RawSender(const std::string& host, uint16_t port, std::optional<std::
|
|||||||
}
|
}
|
||||||
m_sock = std::make_unique<Sock>(hSocket);
|
m_sock = std::make_unique<Sock>(hSocket);
|
||||||
|
|
||||||
LogPrintf("Started RawSender sending messages to %s:%d\n", m_host, m_port);
|
if (m_interval_ms == 0) {
|
||||||
|
LogPrintf("Send interval is zero, not starting RawSender queueing thread.\n");
|
||||||
|
} else {
|
||||||
|
m_interrupt.reset();
|
||||||
|
m_thread = std::thread(&util::TraceThread, "rawsender", [this] { QueueThreadMain(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrintf("Started %sRawSender sending messages to %s:%d\n", m_thread.joinable() ? "threaded " : "", m_host, m_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
RawSender::~RawSender()
|
RawSender::~RawSender()
|
||||||
{
|
{
|
||||||
LogPrintf("Stopping RawSender instance sending messages to %s:%d. %d successes, %d failures.\n",
|
// If there is a thread, interrupt and stop it
|
||||||
|
if (m_thread.joinable()) {
|
||||||
|
m_interrupt();
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
// Flush queue of uncommitted messages
|
||||||
|
QueueFlush();
|
||||||
|
|
||||||
|
LogPrintf("Stopped RawSender instance sending messages to %s:%d. %d successes, %d failures.\n",
|
||||||
m_host, m_port, m_successes, m_failures);
|
m_host, m_port, m_successes, m_failures);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> RawSender::Send(const RawMessage& msg)
|
std::optional<std::string> RawSender::Send(const RawMessage& msg)
|
||||||
|
{
|
||||||
|
// If there is a thread, append to queue
|
||||||
|
if (m_thread.joinable()) {
|
||||||
|
QueueAdd(msg);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
// There isn't a queue, send directly
|
||||||
|
return SendDirectly(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> RawSender::SendDirectly(const RawMessage& msg)
|
||||||
{
|
{
|
||||||
if (!m_sock) {
|
if (!m_sock) {
|
||||||
m_failures++;
|
m_failures++;
|
||||||
@ -72,3 +101,42 @@ std::optional<std::string> RawSender::Send(const RawMessage& msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string RawSender::ToStringHostPort() const { return strprintf("%s:%d", m_host, m_port); }
|
std::string RawSender::ToStringHostPort() const { return strprintf("%s:%d", m_host, m_port); }
|
||||||
|
|
||||||
|
void RawSender::QueueAdd(const RawMessage& msg)
|
||||||
|
{
|
||||||
|
AssertLockNotHeld(cs);
|
||||||
|
WITH_LOCK(cs, m_queue.push_back(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawSender::QueueFlush()
|
||||||
|
{
|
||||||
|
AssertLockNotHeld(cs);
|
||||||
|
WITH_LOCK(cs, QueueFlush(m_queue));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawSender::QueueFlush(std::deque<RawMessage>& queue)
|
||||||
|
{
|
||||||
|
while (!queue.empty()) {
|
||||||
|
SendDirectly(queue.front());
|
||||||
|
queue.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawSender::QueueThreadMain()
|
||||||
|
{
|
||||||
|
AssertLockNotHeld(cs);
|
||||||
|
|
||||||
|
while (!m_interrupt) {
|
||||||
|
// Swap the queues to commit the existing queue of messages
|
||||||
|
std::deque<RawMessage> queue;
|
||||||
|
WITH_LOCK(cs, m_queue.swap(queue));
|
||||||
|
|
||||||
|
// Flush the committed queue
|
||||||
|
QueueFlush(queue);
|
||||||
|
assert(queue.empty());
|
||||||
|
|
||||||
|
if (!m_interrupt.sleep_for(std::chrono::milliseconds(m_interval_ms))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
|
|
||||||
#include <compat.h>
|
#include <compat.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
|
#include <threadinterrupt.h>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -53,27 +55,44 @@ struct RawMessage : public std::vector<uint8_t>
|
|||||||
class RawSender
|
class RawSender
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RawSender(const std::string& host, uint16_t port, std::optional<std::string>& error);
|
RawSender(const std::string& host, uint16_t port, uint64_t interval_ms, std::optional<std::string>& error);
|
||||||
~RawSender();
|
~RawSender();
|
||||||
|
|
||||||
RawSender(const RawSender&) = delete;
|
RawSender(const RawSender&) = delete;
|
||||||
RawSender& operator=(const RawSender&) = delete;
|
RawSender& operator=(const RawSender&) = delete;
|
||||||
RawSender(RawSender&&) = delete;
|
RawSender(RawSender&&) = delete;
|
||||||
|
|
||||||
std::optional<std::string> Send(const RawMessage& msg);
|
std::optional<std::string> Send(const RawMessage& msg) EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||||
|
std::optional<std::string> SendDirectly(const RawMessage& msg);
|
||||||
|
|
||||||
std::string ToStringHostPort() const;
|
std::string ToStringHostPort() const;
|
||||||
|
|
||||||
|
void QueueAdd(const RawMessage& msg) EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||||
|
void QueueFlush() EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||||
|
void QueueFlush(std::deque<RawMessage>& queue);
|
||||||
|
void QueueThreadMain() EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Socket used to communicate with host */
|
/* Socket used to communicate with host */
|
||||||
std::unique_ptr<Sock> m_sock{nullptr};
|
std::unique_ptr<Sock> m_sock{nullptr};
|
||||||
/* Socket address containing host information */
|
/* Socket address containing host information */
|
||||||
std::pair<struct sockaddr_storage, socklen_t> m_server{{}, sizeof(struct sockaddr_storage)};
|
std::pair<struct sockaddr_storage, socklen_t> m_server{{}, sizeof(struct sockaddr_storage)};
|
||||||
|
|
||||||
|
/* Mutex to protect messages queue */
|
||||||
|
mutable Mutex cs;
|
||||||
|
/* Interrupt for queue processing thread */
|
||||||
|
CThreadInterrupt m_interrupt;
|
||||||
|
/* Queue of messages to be sent */
|
||||||
|
std::deque<RawMessage> m_queue GUARDED_BY(cs);
|
||||||
|
/* Thread that processes queue every m_interval_ms */
|
||||||
|
std::thread m_thread;
|
||||||
|
|
||||||
/* Hostname of server receiving messages */
|
/* Hostname of server receiving messages */
|
||||||
const std::string m_host;
|
const std::string m_host;
|
||||||
/* Port of server receiving messages */
|
/* Port of server receiving messages */
|
||||||
const uint16_t m_port;
|
const uint16_t m_port;
|
||||||
|
/* Time between queue thread runs (expressed in milliseconds) */
|
||||||
|
const uint64_t m_interval_ms;
|
||||||
|
|
||||||
/* Number of messages sent */
|
/* Number of messages sent */
|
||||||
uint64_t m_successes{0};
|
uint64_t m_successes{0};
|
||||||
|
@ -185,8 +185,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
|
|||||||
InitScriptExecutionCache();
|
InitScriptExecutionCache();
|
||||||
::g_stats_client = std::make_unique<StatsdClient>(
|
::g_stats_client = std::make_unique<StatsdClient>(
|
||||||
m_node.args->GetArg("-statshost", DEFAULT_STATSD_HOST),
|
m_node.args->GetArg("-statshost", DEFAULT_STATSD_HOST),
|
||||||
m_node.args->GetArg("-statshostname", DEFAULT_STATSD_HOSTNAME),
|
|
||||||
m_node.args->GetArg("-statsport", DEFAULT_STATSD_PORT),
|
m_node.args->GetArg("-statsport", DEFAULT_STATSD_PORT),
|
||||||
|
m_node.args->GetArg("-statsduration", DEFAULT_STATSD_DURATION),
|
||||||
|
m_node.args->GetArg("-statshostname", DEFAULT_STATSD_HOSTNAME),
|
||||||
m_node.args->GetArg("-statsns", DEFAULT_STATSD_NAMESPACE),
|
m_node.args->GetArg("-statsns", DEFAULT_STATSD_NAMESPACE),
|
||||||
m_node.args->GetBoolArg("-statsenabled", DEFAULT_STATSD_ENABLE)
|
m_node.args->GetBoolArg("-statsenabled", DEFAULT_STATSD_ENABLE)
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user