diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj
index 07685c299c..92e3af490e 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj
+++ b/Builds/VisualStudio2012/RippleD.vcxproj
@@ -597,6 +597,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -903,6 +909,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -2250,6 +2262,7 @@
+
@@ -2343,6 +2356,7 @@
+
diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters
index 787623a4ae..e1aa4c36a9 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters
@@ -1386,6 +1386,12 @@
[2] Old Ripple\ripple_app\ledger
+
+ [1] Ripple\rpc\impl
+
+
+ [2] Old Ripple\ripple_app\main
+
@@ -2850,6 +2856,12 @@
[1] Ripple\algorithm\api
+
+ [1] Ripple\rpc\api
+
+
+ [2] Old Ripple\ripple_app\main
+
diff --git a/doc/rippled-example.cfg b/doc/rippled-example.cfg
index ec028d64ba..c3678a9fcb 100644
--- a/doc/rippled-example.cfg
+++ b/doc/rippled-example.cfg
@@ -707,6 +707,41 @@
#
#
#
+# [insight]
+#
+# Configuration parameters for the Beast.Insight stats collection module.
+#
+# Insight is a module that collects information from the areas of rippled
+# that have instrumentation. The configuration paramters control where the
+# collection metrics are sent. The parameters are expressed as key = value
+# pairs with no white space. The main parameter is the choice of server:
+#
+# "server"
+#
+# Choice of server to send metrics to. Currently the only choice is
+# "statsd" which sends UDP packets to a StatsD daemon, which must be
+# running while rippled is running. More information on StatsD is
+# available here:
+# https://github.com/b/statsd_spec
+#
+# When server=statsd, these additional keys are used:
+#
+# "address" The UDP address and port of the listening StatsD server,
+# in the format, n.n.n.n:port.
+#
+# "prefix" A string prepended to each collected metric. This is used
+# to distinguish between different running instances of rippled.
+#
+# If this section is missing, or the server type is unspecified or unknown,
+# statistics are not collected or reported.
+#
+# Example:
+#
+# [insight]
+# server=statsd
+# address=192.168.0.95:4201
+# prefix=my_validator
+#
#-------------------------------------------------------------------------------
# Allow other peers to connect to this server.
diff --git a/src/ripple/beast/ripple_beast.cpp b/src/ripple/beast/ripple_beast.cpp
index b4a691264f..f12de1462b 100644
--- a/src/ripple/beast/ripple_beast.cpp
+++ b/src/ripple/beast/ripple_beast.cpp
@@ -43,6 +43,7 @@
#include "../beast/beast/chrono/Chrono.cpp"
#include "../beast/beast/crypto/Crypto.cpp"
#include "../beast/beast/http/HTTP.cpp"
+#include "../beast/beast/insight/Insight.cpp"
#include "../beast/beast/net/Net.cpp"
#include "../beast/beast/smart_ptr/SmartPtr.cpp"
#include "../beast/beast/strings/Strings.cpp"
diff --git a/src/ripple_app/main/Application.cpp b/src/ripple_app/main/Application.cpp
index 6a680ec8ac..135613df79 100644
--- a/src/ripple_app/main/Application.cpp
+++ b/src/ripple_app/main/Application.cpp
@@ -46,6 +46,8 @@ template <> char const* LogPartition::getPartitionName () { ret
class ResourceManagerLog;
template <> char const* LogPartition::getPartitionName () { return "ResourceManager"; }
+template <> char const* LogPartition::getPartitionName () { return "Collector"; }
+
//
//------------------------------------------------------------------------------
@@ -74,6 +76,10 @@ public:
, m_tempNodeCache ("NodeCache", 16384, 90)
, m_sleCache ("LedgerEntryCache", 4096, 120)
+ , m_collectorManager (CollectorManager::New (
+ getConfig().insightSettings,
+ LogPartition::getJournal ()))
+
, m_resourceManager (add (Resource::Manager::New (
LogPartition::getJournal ())))
@@ -83,7 +89,9 @@ public:
// The JobQueue has to come pretty early since
// almost everything is a Stoppable child of the JobQueue.
//
- , m_jobQueue (JobQueue::New (*this, LogPartition::getJournal ()))
+ , m_jobQueue (JobQueue::New (
+ m_collectorManager->collector (),
+ *this, LogPartition::getJournal ()))
// The io_service must be a child of the JobQueue since we call addJob
// in response to newtwork data from peers and also client requests.
@@ -165,6 +173,11 @@ public:
//--------------------------------------------------------------------------
+ CollectorManager& getCollectorManager ()
+ {
+ return *m_collectorManager;
+ }
+
RPC::Manager& getRPCServiceManager()
{
return *m_rpcServiceManager;
@@ -882,6 +895,7 @@ private:
LocalCredentials m_localCredentials;
TransactionMaster m_txMaster;
+ beast::unique_ptr m_collectorManager;
ScopedPointer m_resourceManager;
ScopedPointer m_rpcServiceManager;
diff --git a/src/ripple_app/main/Application.h b/src/ripple_app/main/Application.h
index 12e5e11618..31081d6a40 100644
--- a/src/ripple_app/main/Application.h
+++ b/src/ripple_app/main/Application.h
@@ -27,6 +27,7 @@ namespace NodeStore { class Database; }
namespace RPC { class Manager; }
// VFALCO TODO Fix forward declares required for header dependency loops
+class CollectorManager;
class IFeatures;
class IFeeVote;
class IHashRouter;
@@ -77,9 +78,8 @@ public:
virtual ~Application () { }
virtual boost::asio::io_service& getIOService () = 0;
-
+ virtual CollectorManager& getCollectorManager () = 0;
virtual RPC::Manager& getRPCServiceManager() = 0;
-
virtual JobQueue& getJobQueue () = 0;
virtual SiteFiles::Manager& getSiteFiles () = 0;
virtual NodeCache& getTempNodeCache () = 0;
diff --git a/src/ripple_app/main/CollectorManager.cpp b/src/ripple_app/main/CollectorManager.cpp
new file mode 100644
index 0000000000..3115c8be7a
--- /dev/null
+++ b/src/ripple_app/main/CollectorManager.cpp
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+namespace ripple {
+
+class CollectorManagerImp
+ : public CollectorManager
+{
+public:
+ Journal m_journal;
+ shared_ptr m_collector;
+
+ CollectorManagerImp (StringPairArray const& params,
+ Journal journal)
+ : m_journal (journal)
+ {
+ std::string const& server (params ["server"].toStdString());
+
+ if (server == "statsd")
+ {
+ IPAddress const address (IPAddress::from_string (
+ params ["address"].toStdString ()));
+ std::string const& prefix (params ["prefix"].toStdString ());
+
+ m_collector = insight::StatsDCollector::New (address, prefix, journal);
+ }
+ else
+ {
+ m_collector = insight::NullCollector::New ();
+ }
+ }
+
+ ~CollectorManagerImp ()
+ {
+ }
+
+ shared_ptr const& collector ()
+ {
+ return m_collector;
+ }
+};
+
+//------------------------------------------------------------------------------
+
+CollectorManager::~CollectorManager ()
+{
+}
+
+CollectorManager* CollectorManager::New (StringPairArray const& params,
+ Journal journal)
+{
+ return new CollectorManagerImp (params, journal);
+}
+
+}
diff --git a/src/ripple_app/main/CollectorManager.h b/src/ripple_app/main/CollectorManager.h
new file mode 100644
index 0000000000..82ce026c54
--- /dev/null
+++ b/src/ripple_app/main/CollectorManager.h
@@ -0,0 +1,39 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_RIPPLECOLLECTOR_H_INCLUDED
+#define RIPPLE_RIPPLECOLLECTOR_H_INCLUDED
+
+#include "beast/beast/Insight.h"
+
+namespace ripple {
+
+/** Provides the beast::insight::Collector service. */
+class CollectorManager
+{
+public:
+ static CollectorManager* New (StringPairArray const& params,
+ Journal journal);
+ virtual ~CollectorManager () = 0;
+ virtual shared_ptr const& collector () = 0;
+};
+
+}
+
+#endif
diff --git a/src/ripple_app/ripple_app.cpp b/src/ripple_app/ripple_app.cpp
index 189e8aa330..9fa3d7293f 100644
--- a/src/ripple_app/ripple_app.cpp
+++ b/src/ripple_app/ripple_app.cpp
@@ -42,6 +42,9 @@
#include "beast/beast/Asio.h"
+# include "main/CollectorManager.h"
+#include "main/CollectorManager.cpp"
+
namespace ripple {
//
diff --git a/src/ripple_core/functional/Config.cpp b/src/ripple_core/functional/Config.cpp
index 10bf021e89..bb3e6cdfea 100644
--- a/src/ripple_core/functional/Config.cpp
+++ b/src/ripple_core/functional/Config.cpp
@@ -331,6 +331,8 @@ void Config::load ()
(void) SectionSingleB (secConfig, SECTION_RPC_PASSWORD, RPC_PASSWORD);
(void) SectionSingleB (secConfig, SECTION_RPC_USER, RPC_USER);
+ insightSettings = parseKeyValueSection (secConfig, SECTION_INSIGHT);
+
//---------------------------------------
//
// VFALCO BEGIN CLEAN
diff --git a/src/ripple_core/functional/Config.h b/src/ripple_core/functional/Config.h
index 80d7178e50..9f69204883 100644
--- a/src/ripple_core/functional/Config.h
+++ b/src/ripple_core/functional/Config.h
@@ -298,6 +298,9 @@ public:
//--------------------------------------------------------------------------
+ /** Parameters for the insight collection module */
+ StringPairArray insightSettings;
+
/** Parameters for the main NodeStore database.
This is 1 or more strings of the form =
diff --git a/src/ripple_core/functional/ConfigSections.h b/src/ripple_core/functional/ConfigSections.h
index a77c28bbb6..994615f80a 100644
--- a/src/ripple_core/functional/ConfigSections.h
+++ b/src/ripple_core/functional/ConfigSections.h
@@ -47,6 +47,7 @@ struct ConfigSection
#define SECTION_FEE_ACCOUNT_RESERVE "fee_account_reserve"
#define SECTION_FEE_OWNER_RESERVE "fee_owner_reserve"
#define SECTION_LEDGER_HISTORY "ledger_history"
+#define SECTION_INSIGHT "insight"
#define SECTION_IPS "ips"
#define SECTION_IPS_FIXED "ips_fixed"
#define SECTION_NETWORK_QUORUM "network_quorum"
diff --git a/src/ripple_core/functional/JobQueue.cpp b/src/ripple_core/functional/JobQueue.cpp
index e9b00e4958..2bebdac72d 100644
--- a/src/ripple_core/functional/JobQueue.cpp
+++ b/src/ripple_core/functional/JobQueue.cpp
@@ -22,6 +22,12 @@ class JobQueueImp
, private Workers::Callback
{
public:
+ struct Metrics
+ {
+ insight::Hook hook;
+ insight::Gauge job_count;
+ };
+
// Statistics for each JobType
//
struct Count
@@ -53,6 +59,7 @@ public:
typedef CriticalSection::ScopedLockType ScopedLock;
Journal m_journal;
+ Metrics m_metrics;
CriticalSection m_mutex;
uint64 m_lastJob;
JobSet m_jobSet;
@@ -67,7 +74,8 @@ public:
//--------------------------------------------------------------------------
- JobQueueImp (Stoppable& parent, Journal journal)
+ JobQueueImp (shared_ptr const& collector,
+ Stoppable& parent, Journal journal)
: JobQueue ("JobQueue", parent)
, m_journal (journal)
, m_lastJob (0)
@@ -75,6 +83,10 @@ public:
, m_workers (*this, "JobQueue", 0)
, m_cancelCallback (boost::bind (&Stoppable::isStopping, this))
{
+ m_metrics.hook = collector->make_hook (beast::bind (
+ &JobQueueImp::collect, this));
+ m_metrics.job_count = collector->make_gauge ("job_count");
+
{
ScopedLock lock (m_mutex);
@@ -112,6 +124,12 @@ public:
{
}
+ void collect ()
+ {
+ ScopedLock lock (m_mutex);
+ m_metrics.job_count = m_jobSet.size ();
+ }
+
void addJob (JobType type, const std::string& name, const FUNCTION_TYPE& jobFunc)
{
bassert (type != jtINVALID);
@@ -708,7 +726,8 @@ JobQueue::JobQueue (char const* name, Stoppable& parent)
//------------------------------------------------------------------------------
-JobQueue* JobQueue::New (Stoppable& parent, Journal journal)
+JobQueue* JobQueue::New (shared_ptr const& collector,
+ Stoppable& parent, Journal journal)
{
- return new JobQueueImp (parent, journal);
+ return new JobQueueImp (collector, parent, journal);
}
diff --git a/src/ripple_core/functional/JobQueue.h b/src/ripple_core/functional/JobQueue.h
index b0624fca0f..fd22585d67 100644
--- a/src/ripple_core/functional/JobQueue.h
+++ b/src/ripple_core/functional/JobQueue.h
@@ -26,7 +26,8 @@ protected:
JobQueue (char const* name, Stoppable& parent);
public:
- static JobQueue* New (Stoppable& parent, Journal journal);
+ static JobQueue* New (shared_ptr const& collector,
+ Stoppable& parent, Journal journal);
virtual ~JobQueue () { }
diff --git a/src/ripple_core/ripple_core.h b/src/ripple_core/ripple_core.h
index c59246ed27..d6c8109d0c 100644
--- a/src/ripple_core/ripple_core.h
+++ b/src/ripple_core/ripple_core.h
@@ -24,6 +24,7 @@
#include "../ripple_data/ripple_data.h"
#include "beast/beast/http/URL.h" // for Config
+#include "beast/beast/Insight.h"
#include "../ripple/resource/api/LegacyFees.h"