Add API query for peer stats, other related fixes

pull/1312/head
Stephen Shelton 4 years ago
parent 595288e046
commit 5e05defc76
No known key found for this signature in database
GPG Key ID: EE4BADACCE8B631C

@ -1,6 +1,7 @@
#include <peerstats/peer_db.hpp> #include <peerstats/peer_db.hpp>
#include <util/logging/logger.hpp> #include <util/logging/logger.hpp>
#include <util/status.hpp>
#include <util/str.hpp> #include <util/str.hpp>
namespace llarp namespace llarp
@ -80,7 +81,7 @@ namespace llarp
auto end = time_now_ms(); auto end = time_now_ms();
auto elapsed = end - start; auto elapsed = end - start;
LogDebug("PeerDb flush took about ", elapsed, " millis"); LogInfo("PeerDb flush took about ", elapsed, " millis");
m_lastFlush.store(end); m_lastFlush.store(end);
} }
@ -128,19 +129,24 @@ namespace llarp
RouterID id(rc.pubkey); RouterID id(rc.pubkey);
auto& stats = m_peerStats[id]; auto& stats = m_peerStats[id];
stats.routerId = id.ToString();
if (stats.lastRCUpdated < rc.last_updated.count()) if (stats.lastRCUpdated < rc.last_updated.count())
{ {
// we track max expiry as the delta between (time received - last expiration time), if (stats.numDistinctRCsReceived > 0)
// and this value will often be negative for a healthy router {
// TODO: handle case where new RC is also expired? just ignore? // we track max expiry as the delta between (time received - last expiration time),
int64_t expiry = (now.count() - (stats.lastRCUpdated + RouterContact::Lifetime.count())); // and this value will often be negative for a healthy router
// TODO: handle case where new RC is also expired? just ignore?
if (stats.numDistinctRCsReceived == 0) int64_t expiry = (now.count() - (stats.lastRCUpdated + RouterContact::Lifetime.count()));
stats.mostExpiredRCMs = expiry;
else
stats.mostExpiredRCMs = std::max(stats.mostExpiredRCMs, expiry); stats.mostExpiredRCMs = std::max(stats.mostExpiredRCMs, expiry);
if (stats.numDistinctRCsReceived == 1)
stats.mostExpiredRCMs = expiry;
else
stats.mostExpiredRCMs = std::max(stats.mostExpiredRCMs, expiry);
}
stats.numDistinctRCsReceived++; stats.numDistinctRCsReceived++;
stats.lastRCUpdated = rc.last_updated.count(); stats.lastRCUpdated = rc.last_updated.count();
} }
@ -164,4 +170,32 @@ namespace llarp
return (now - m_lastFlush.load() >= TargetFlushInterval); return (now - m_lastFlush.load() >= TargetFlushInterval);
} }
util::StatusObject
PeerDb::ExtractStatus() const
{
std::lock_guard gaurd(m_statsLock);
bool loaded = (m_storage.get() != nullptr);
util::StatusObject dbFile = nullptr;
if (loaded)
dbFile = m_storage->filename();
std::vector<util::StatusObject> statsObjs;
statsObjs.reserve(m_peerStats.size());
LogInfo("Building peer stats...");
for (const auto& pair : m_peerStats)
{
LogInfo("Stat here");
statsObjs.push_back(pair.second.toJson());
}
util::StatusObject obj{
{"dbLoaded", loaded},
{"dbFile", dbFile},
{"lastFlushMs", m_lastFlush.load().count()},
{"stats", statsObjs},
};
return obj;
}
}; // namespace llarp }; // namespace llarp

@ -104,6 +104,12 @@ namespace llarp
bool bool
shouldFlush(llarp_time_t now); shouldFlush(llarp_time_t now);
/// Get JSON status for API
///
/// @return JSON object representing our current status
util::StatusObject
ExtractStatus() const;
private: private:
std::unordered_map<RouterID, PeerStats, RouterID::Hash> m_peerStats; std::unordered_map<RouterID, PeerStats, RouterID::Hash> m_peerStats;
std::mutex m_statsLock; std::mutex m_statsLock;

@ -30,6 +30,7 @@ namespace llarp
longestRCReceiveIntervalMs = longestRCReceiveIntervalMs =
std::max(longestRCReceiveIntervalMs, other.longestRCReceiveIntervalMs); std::max(longestRCReceiveIntervalMs, other.longestRCReceiveIntervalMs);
mostExpiredRCMs = std::max(mostExpiredRCMs, other.mostExpiredRCMs); mostExpiredRCMs = std::max(mostExpiredRCMs, other.mostExpiredRCMs);
lastRCUpdated = std::max(lastRCUpdated, other.lastRCUpdated);
return *this; return *this;
} }
@ -52,7 +53,30 @@ namespace llarp
and peakBandwidthBytesPerSec == other.peakBandwidthBytesPerSec and peakBandwidthBytesPerSec == other.peakBandwidthBytesPerSec
and longestRCReceiveIntervalMs == other.longestRCReceiveIntervalMs and longestRCReceiveIntervalMs == other.longestRCReceiveIntervalMs
and mostExpiredRCMs == other.mostExpiredRCMs; and mostExpiredRCMs == other.mostExpiredRCMs and lastRCUpdated == other.lastRCUpdated;
}
util::StatusObject
PeerStats::toJson() const
{
return {
{"routerId", routerId},
// {"numConnectionAttempts", numConnectionAttempts},
// {"numConnectionSuccesses", numConnectionSuccesses},
// {"numConnectionRejections", numConnectionRejections},
// {"numConnectionTimeouts", numConnectionTimeouts},
// {"numPathBuilds", numPathBuilds},
// {"numPacketsAttempted", numPacketsAttempted},
// {"numPacketsSent", numPacketsSent},
// {"numPacketsDropped", numPacketsDropped},
// {"numPacketsResent", numPacketsResent},
{"numDistinctRCsReceived", numDistinctRCsReceived},
{"numLateRCs", numLateRCs},
// {"peakBandwidthBytesPerSec", peakBandwidthBytesPerSec},
{"longestRCReceiveIntervalMs", longestRCReceiveIntervalMs},
{"mostExpiredRCMs", mostExpiredRCMs},
{"lastRCUpdated", lastRCUpdated},
};
} }
}; // namespace llarp }; // namespace llarp

@ -4,6 +4,7 @@
#include <unordered_map> #include <unordered_map>
#include <router_id.hpp> #include <router_id.hpp>
#include <util/status.hpp>
#include <util/time.hpp> #include <util/time.hpp>
/// Types stored in our peerstats database are declared here /// Types stored in our peerstats database are declared here
@ -41,6 +42,9 @@ namespace llarp
operator+=(const PeerStats& other); operator+=(const PeerStats& other);
bool bool
operator==(const PeerStats& other); operator==(const PeerStats& other);
util::StatusObject
toJson() const;
}; };
} // namespace llarp } // namespace llarp

@ -23,6 +23,7 @@
#include <ev/ev.hpp> #include <ev/ev.hpp>
#include "tooling/router_event.hpp" #include "tooling/router_event.hpp"
#include "util/status.hpp"
#include <fstream> #include <fstream>
#include <cstdlib> #include <cstdlib>
@ -80,13 +81,19 @@ namespace llarp
{ {
if (_running) if (_running)
{ {
return util::StatusObject{{"running", true}, util::StatusObject peerStatsObj = nullptr;
{"numNodesKnown", _nodedb->num_loaded()}, if (m_peerDb)
{"dht", _dht->impl->ExtractStatus()}, peerStatsObj = m_peerDb->ExtractStatus();
{"services", _hiddenServiceContext.ExtractStatus()},
{"exit", _exitContext.ExtractStatus()}, return util::StatusObject{
{"links", _linkManager.ExtractStatus()}, {"running", true},
{"outboundMessages", _outboundMessageHandler.ExtractStatus()}}; {"numNodesKnown", _nodedb->num_loaded()},
{"dht", _dht->impl->ExtractStatus()},
{"services", _hiddenServiceContext.ExtractStatus()},
{"exit", _exitContext.ExtractStatus()},
{"links", _linkManager.ExtractStatus()},
{"outboundMessages", _outboundMessageHandler.ExtractStatus()},
{"peerStats", peerStatsObj}};
} }
else else
{ {

@ -130,7 +130,7 @@ TEST_CASE("Test PeerDb handleGossipedRC", "[PeerDb]")
auto stats = db.getCurrentPeerStats(id); auto stats = db.getCurrentPeerStats(id);
CHECK(stats.has_value()); CHECK(stats.has_value());
CHECK(stats.value().mostExpiredRCMs == (0s - rcLifetime).count()); CHECK(stats.value().mostExpiredRCMs == 0); // not calculated on first received RC
CHECK(stats.value().numDistinctRCsReceived == 1); CHECK(stats.value().numDistinctRCsReceived == 1);
CHECK(stats.value().lastRCUpdated == 10000); CHECK(stats.value().lastRCUpdated == 10000);
@ -139,7 +139,7 @@ TEST_CASE("Test PeerDb handleGossipedRC", "[PeerDb]")
stats = db.getCurrentPeerStats(id); stats = db.getCurrentPeerStats(id);
CHECK(stats.has_value()); CHECK(stats.has_value());
// these values should remain unchanged, this is not a new RC // these values should remain unchanged, this is not a new RC
CHECK(stats.value().mostExpiredRCMs == (0s - rcLifetime).count()); CHECK(stats.value().mostExpiredRCMs == 0);
CHECK(stats.value().numDistinctRCsReceived == 1); CHECK(stats.value().numDistinctRCsReceived == 1);
CHECK(stats.value().lastRCUpdated == 10000); CHECK(stats.value().lastRCUpdated == 10000);

Loading…
Cancel
Save