mirror of https://github.com/oxen-io/lokinet
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
584cc61f8f
|
@ -2,7 +2,7 @@
|
|||
# copy a lokinet binary into this cluster
|
||||
cp ../../lokinet .
|
||||
# generate default config file
|
||||
./lokinet -g lokinet.ini
|
||||
./lokinet -g -r lokinet.ini
|
||||
# make seed node
|
||||
./makenode.sh 1
|
||||
# establish bootstrap
|
||||
|
|
|
@ -44,6 +44,7 @@ set(LIB_UTIL_SRC
|
|||
util/timerqueue.cpp
|
||||
util/traits.cpp
|
||||
util/types.cpp
|
||||
util/variant.cpp
|
||||
)
|
||||
|
||||
add_library(${UTIL_LIB} STATIC ${LIB_UTIL_SRC})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <metrics/metrictank_publisher.hpp>
|
||||
|
||||
#include <util/logger.hpp>
|
||||
#include <util/variant.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <absl/strings/str_cat.h>
|
||||
|
@ -44,7 +45,20 @@ namespace llarp
|
|||
}
|
||||
|
||||
absl::optional< std::string >
|
||||
formatValue(const Record &record, double elapsedTime,
|
||||
makeStr(int i)
|
||||
{
|
||||
if(i == std::numeric_limits< int >::min()
|
||||
|| i == std::numeric_limits< int >::max())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::to_string(i);
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
absl::optional< std::string >
|
||||
formatValue(const Record< Value > &record, double elapsedTime,
|
||||
Publication::Type publicationType)
|
||||
{
|
||||
switch(publicationType)
|
||||
|
@ -76,7 +90,8 @@ namespace llarp
|
|||
break;
|
||||
case Publication::Type::Avg:
|
||||
{
|
||||
return makeStr(record.total() / record.count());
|
||||
return makeStr(static_cast< double >(record.total())
|
||||
/ static_cast< double >(record.count()));
|
||||
}
|
||||
break;
|
||||
case Publication::Type::Rate:
|
||||
|
@ -100,9 +115,10 @@ namespace llarp
|
|||
return absl::StrCat(id, ".", name, suffix);
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
std::vector< MetricTankPublisherInterface::PublishData >
|
||||
recordToData(const Record &record, absl::Time time, double elapsedTime,
|
||||
string_view suffix)
|
||||
recordToData(const Record< Value > &record, absl::Time time,
|
||||
double elapsedTime, string_view suffix)
|
||||
{
|
||||
std::vector< MetricTankPublisherInterface::PublishData > result;
|
||||
|
||||
|
@ -127,14 +143,14 @@ namespace llarp
|
|||
result.emplace_back(addName(id, "total", suffix),
|
||||
std::to_string(record.total()), time);
|
||||
|
||||
if(Record::DEFAULT_MIN != record.min() && !std::isnan(record.min())
|
||||
&& !std::isinf(record.min()))
|
||||
if(Record< Value >::DEFAULT_MIN() != record.min()
|
||||
&& !std::isnan(record.min()) && !std::isinf(record.min()))
|
||||
{
|
||||
result.emplace_back(addName(id, "min", suffix),
|
||||
std::to_string(record.min()), time);
|
||||
}
|
||||
if(Record::DEFAULT_MAX == record.max() && !std::isnan(record.max())
|
||||
&& !std::isinf(record.max()))
|
||||
if(Record< Value >::DEFAULT_MAX() == record.max()
|
||||
&& !std::isnan(record.max()) && !std::isinf(record.max()))
|
||||
{
|
||||
result.emplace_back(addName(id, "max", suffix),
|
||||
std::to_string(record.max()), time);
|
||||
|
@ -197,6 +213,8 @@ namespace llarp
|
|||
&& (static_cast< size_t >(sentLen) < val.size()));
|
||||
}
|
||||
|
||||
LogInfo("Sent ", toSend.size(), " metrics to metrictank");
|
||||
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
}
|
||||
|
@ -333,14 +351,17 @@ namespace llarp
|
|||
auto prev = values.begin();
|
||||
for(; gIt != values.end(); ++gIt)
|
||||
{
|
||||
const double elapsedTime = absl::ToDoubleSeconds(gIt->samplePeriod());
|
||||
const double elapsedTime = absl::ToDoubleSeconds(samplePeriod(*gIt));
|
||||
|
||||
forSampleGroup(*gIt, [&](const auto &d) {
|
||||
for(const auto &record : d)
|
||||
{
|
||||
auto partial =
|
||||
recordToData(record, sampleTime, elapsedTime, m_suffix);
|
||||
result.insert(result.end(), partial.begin(), partial.end());
|
||||
}
|
||||
});
|
||||
|
||||
for(const auto &record : *gIt)
|
||||
{
|
||||
auto partial =
|
||||
recordToData(record, sampleTime, elapsedTime, m_suffix);
|
||||
result.insert(result.end(), partial.begin(), partial.end());
|
||||
}
|
||||
prev = gIt;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
void
|
||||
formatValue(std::ostream &stream, const Record &record,
|
||||
formatValue(std::ostream &stream, const Record< Value > &record,
|
||||
double elapsedTime, Publication::Type publicationType,
|
||||
const FormatSpec *formatSpec)
|
||||
{
|
||||
|
@ -75,8 +76,9 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
void
|
||||
publishRecord(std::ostream &stream, const Record &record,
|
||||
publishRecord(std::ostream &stream, const Record< Value > &record,
|
||||
double elapsedTime)
|
||||
{
|
||||
auto publicationType = record.id().description()->type();
|
||||
|
@ -111,7 +113,7 @@ namespace llarp
|
|||
formatValue(stream, record.count(), countSpec);
|
||||
stream << ", total = ";
|
||||
formatValue(stream, record.total(), totalSpec);
|
||||
if(Record::DEFAULT_MIN == record.min())
|
||||
if(Record< Value >::DEFAULT_MIN() == record.min())
|
||||
{
|
||||
stream << ", min = undefined";
|
||||
}
|
||||
|
@ -120,7 +122,7 @@ namespace llarp
|
|||
stream << ", min = ";
|
||||
formatValue(stream, record.min(), minSpec);
|
||||
}
|
||||
if(Record::DEFAULT_MAX == record.max())
|
||||
if(Record< Value >::DEFAULT_MAX() == record.max())
|
||||
{
|
||||
stream << ", max = undefined";
|
||||
}
|
||||
|
@ -133,8 +135,9 @@ namespace llarp
|
|||
stream << " ]\n";
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
void
|
||||
formatValue(nlohmann::json &result, const Record &record,
|
||||
formatValue(nlohmann::json &result, const Record< Value > &record,
|
||||
double elapsedTime, Publication::Type publicationType)
|
||||
{
|
||||
switch(publicationType)
|
||||
|
@ -182,8 +185,9 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
nlohmann::json
|
||||
recordToJson(const Record &record, double elapsedTime)
|
||||
recordToJson(const Record< Value > &record, double elapsedTime)
|
||||
{
|
||||
nlohmann::json result;
|
||||
result["id"] = record.id().toString();
|
||||
|
@ -200,11 +204,11 @@ namespace llarp
|
|||
result["count"] = record.count();
|
||||
result["total"] = record.total();
|
||||
|
||||
if(Record::DEFAULT_MIN != record.min())
|
||||
if(Record< Value >::DEFAULT_MIN() != record.min())
|
||||
{
|
||||
result["min"] = record.min();
|
||||
}
|
||||
if(Record::DEFAULT_MAX == record.max())
|
||||
if(Record< Value >::DEFAULT_MAX() == record.max())
|
||||
{
|
||||
result["max"] = record.max();
|
||||
}
|
||||
|
@ -230,17 +234,20 @@ namespace llarp
|
|||
auto prev = values.begin();
|
||||
for(; gIt != values.end(); ++gIt)
|
||||
{
|
||||
const double elapsedTime = absl::ToDoubleSeconds(gIt->samplePeriod());
|
||||
const double elapsedTime = absl::ToDoubleSeconds(samplePeriod(*gIt));
|
||||
|
||||
if(gIt == prev || gIt->samplePeriod() != prev->samplePeriod())
|
||||
if(gIt == prev || samplePeriod(*gIt) != samplePeriod(*prev))
|
||||
{
|
||||
m_stream << "\tElapsed Time: " << elapsedTime << "s\n";
|
||||
}
|
||||
|
||||
for(const auto &record : *gIt)
|
||||
{
|
||||
publishRecord(m_stream, record, elapsedTime);
|
||||
}
|
||||
forSampleGroup(*gIt, [&](const auto &x) {
|
||||
for(const auto &record : x)
|
||||
{
|
||||
publishRecord(m_stream, record, elapsedTime);
|
||||
}
|
||||
});
|
||||
|
||||
prev = gIt;
|
||||
}
|
||||
}
|
||||
|
@ -261,17 +268,20 @@ namespace llarp
|
|||
auto prev = values.begin();
|
||||
for(; gIt != values.end(); ++gIt)
|
||||
{
|
||||
const double elapsedTime = absl::ToDoubleSeconds(gIt->samplePeriod());
|
||||
const double elapsedTime = absl::ToDoubleSeconds(samplePeriod(*gIt));
|
||||
|
||||
if(gIt == prev || gIt->samplePeriod() != prev->samplePeriod())
|
||||
if(gIt == prev || samplePeriod(*gIt) != samplePeriod(*prev))
|
||||
{
|
||||
result["elapsedTime"] = elapsedTime;
|
||||
}
|
||||
|
||||
for(const auto &record : *gIt)
|
||||
{
|
||||
result["record"].emplace_back(recordToJson(record, elapsedTime));
|
||||
}
|
||||
forSampleGroup(*gIt, [&](const auto &x) {
|
||||
for(const auto &record : x)
|
||||
{
|
||||
result["record"].emplace_back(recordToJson(record, elapsedTime));
|
||||
}
|
||||
});
|
||||
|
||||
prev = gIt;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,14 +41,15 @@ namespace llarp
|
|||
|
||||
#define METRICS_UNIQUE_NAME(X) METRICS_NAME_CAT(X, METRICS_UNIQ_NUMBER)
|
||||
|
||||
#define METRICS_TIME_BLOCK_IMP(CAT, METRIC, VAR_NAME) \
|
||||
llarp::metrics::DoubleCollector* VAR_NAME = nullptr; \
|
||||
if(llarp::metrics::DefaultManager::instance()) \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
CollectorRepo& repo = DefaultManager::instance()->collectorRepo(); \
|
||||
VAR_NAME = repo.defaultDoubleCollector((CAT), (METRIC)); \
|
||||
} \
|
||||
#define METRICS_TIME_BLOCK_IMP(CAT, METRIC, VAR_NAME) \
|
||||
llarp::metrics::DoubleCollector* VAR_NAME = nullptr; \
|
||||
if(llarp::metrics::DefaultManager::instance()) \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
CollectorRepo< double >& repo = \
|
||||
DefaultManager::instance()->doubleCollectorRepo(); \
|
||||
VAR_NAME = repo.defaultCollector((CAT), (METRIC)); \
|
||||
} \
|
||||
llarp::metrics::TimerGuard METRICS_UNIQUE_NAME(timer_guard)(VAR_NAME);
|
||||
|
||||
#define METRICS_TIME_BLOCK(CAT, METRIC) \
|
||||
|
@ -66,20 +67,20 @@ namespace llarp
|
|||
BALM_METRICS_IF_CATEGORY_ENABLED_IMP(CAT, METRICS_UNIQUE_NAME(Container))
|
||||
|
||||
// For when the category/metric may change during the program run
|
||||
#define METRICS_DYNAMIC_INT_UPDATE(CAT, METRIC, VALUE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
if(DefaultManager::instance()) \
|
||||
{ \
|
||||
CollectorRepo& repository = DefaultManager::instance()->collectorRepo(); \
|
||||
IntCollector* collector = \
|
||||
repository.defaultIntCollector((CAT), (METRIC)); \
|
||||
if(collector->id().category()->enabled()) \
|
||||
{ \
|
||||
collector->tick((VALUE)); \
|
||||
} \
|
||||
} \
|
||||
#define METRICS_DYNAMIC_INT_UPDATE(CAT, METRIC, VALUE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
if(DefaultManager::instance()) \
|
||||
{ \
|
||||
CollectorRepo< int >& repository = \
|
||||
DefaultManager::instance()->intCollectorRepo(); \
|
||||
IntCollector* collector = repository.defaultCollector((CAT), (METRIC)); \
|
||||
if(collector->id().category()->enabled()) \
|
||||
{ \
|
||||
collector->tick((VALUE)); \
|
||||
} \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
// For when the category/metric remain static
|
||||
|
@ -119,20 +120,21 @@ namespace llarp
|
|||
} while(false)
|
||||
|
||||
// For when the category/metric may change during the program run
|
||||
#define METRICS_DYNAMIC_UPDATE(CAT, METRIC, VALUE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
if(DefaultManager::instance()) \
|
||||
{ \
|
||||
CollectorRepo& repository = DefaultManager::instance()->collectorRepo(); \
|
||||
DoubleCollector* collector = \
|
||||
repository.defaultDoubleCollector((CAT), (METRIC)); \
|
||||
if(collector->id().category()->enabled()) \
|
||||
{ \
|
||||
collector->tick((VALUE)); \
|
||||
} \
|
||||
} \
|
||||
#define METRICS_DYNAMIC_UPDATE(CAT, METRIC, VALUE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
if(DefaultManager::instance()) \
|
||||
{ \
|
||||
CollectorRepo< double >& repository = \
|
||||
DefaultManager::instance()->doubleCollectorRepo(); \
|
||||
DoubleCollector* collector = \
|
||||
repository.defaultCollector((CAT), (METRIC)); \
|
||||
if(collector->id().category()->enabled()) \
|
||||
{ \
|
||||
collector->tick((VALUE)); \
|
||||
} \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
// For when the category/metric remain static
|
||||
|
|
|
@ -6,56 +6,8 @@ namespace llarp
|
|||
{
|
||||
namespace metrics
|
||||
{
|
||||
Record
|
||||
IntCollector::loadAndClear()
|
||||
{
|
||||
size_t count;
|
||||
uint64_t total;
|
||||
int min;
|
||||
int max;
|
||||
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
|
||||
count = m_count;
|
||||
total = m_total;
|
||||
min = m_min;
|
||||
max = m_max;
|
||||
|
||||
m_count = 0;
|
||||
m_total = 0;
|
||||
m_min = DEFAULT_MIN;
|
||||
m_max = DEFAULT_MAX;
|
||||
}
|
||||
|
||||
return {m_id, count, static_cast< double >(total),
|
||||
(min == DEFAULT_MIN) ? Record::DEFAULT_MIN
|
||||
: static_cast< double >(min),
|
||||
(max == DEFAULT_MAX) ? Record::DEFAULT_MAX
|
||||
: static_cast< double >(max)};
|
||||
}
|
||||
|
||||
Record
|
||||
IntCollector::load()
|
||||
{
|
||||
size_t count;
|
||||
int64_t total;
|
||||
int min;
|
||||
int max;
|
||||
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
|
||||
count = m_count;
|
||||
total = m_total;
|
||||
min = m_min;
|
||||
max = m_max;
|
||||
}
|
||||
|
||||
return {m_id, count, static_cast< double >(total),
|
||||
(min == DEFAULT_MIN) ? Record::DEFAULT_MIN : min,
|
||||
(max == DEFAULT_MAX) ? Record::DEFAULT_MAX : max};
|
||||
}
|
||||
using DoubleRecords = std::vector< Record< double > >;
|
||||
using IntRecords = std::vector< Record< int > >;
|
||||
|
||||
std::tuple< Id, bool >
|
||||
Registry::insert(const char *category, const char *name)
|
||||
|
@ -237,125 +189,6 @@ namespace llarp
|
|||
return result;
|
||||
}
|
||||
|
||||
MetricCollectors &
|
||||
CollectorRepo::getCollectors(const Id &id)
|
||||
{
|
||||
auto it = m_collectors.find(id);
|
||||
|
||||
if(it == m_collectors.end())
|
||||
{
|
||||
assert(id.valid());
|
||||
|
||||
const Category *cat = id.category();
|
||||
|
||||
auto ptr = std::make_shared< MetricCollectors >(id);
|
||||
auto &vec = m_categories[cat];
|
||||
vec.reserve(vec.size() + 1);
|
||||
|
||||
it = m_collectors.emplace(id, ptr).first;
|
||||
vec.push_back(ptr.get());
|
||||
}
|
||||
|
||||
return *it->second.get();
|
||||
}
|
||||
|
||||
std::vector< Record >
|
||||
CollectorRepo::collectAndClear(const Category *category)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
|
||||
std::vector< Record > result;
|
||||
|
||||
auto it = m_categories.find(category);
|
||||
|
||||
if(it != m_categories.end())
|
||||
{
|
||||
auto &collectors = it->second;
|
||||
result.reserve(collectors.size());
|
||||
|
||||
std::transform(
|
||||
collectors.begin(), collectors.end(), std::back_inserter(result),
|
||||
[](MetricCollectors *c) { return c->combineAndClear(); });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector< Record >
|
||||
CollectorRepo::collect(const Category *category)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
|
||||
std::vector< Record > result;
|
||||
|
||||
auto it = m_categories.find(category);
|
||||
|
||||
if(it != m_categories.end())
|
||||
{
|
||||
auto &collectors = it->second;
|
||||
result.reserve(collectors.size());
|
||||
|
||||
std::transform(collectors.begin(), collectors.end(),
|
||||
std::back_inserter(result),
|
||||
[](MetricCollectors *c) { return c->combine(); });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DoubleCollector *
|
||||
CollectorRepo::defaultDoubleCollector(const Id &id)
|
||||
{
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
auto it = m_collectors.find(id);
|
||||
if(it != m_collectors.end())
|
||||
{
|
||||
return it->second->doubleCollectors().defaultCollector();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
return getCollectors(id).doubleCollectors().defaultCollector();
|
||||
}
|
||||
}
|
||||
|
||||
IntCollector *
|
||||
CollectorRepo::defaultIntCollector(const Id &id)
|
||||
{
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
auto it = m_collectors.find(id);
|
||||
if(it != m_collectors.end())
|
||||
{
|
||||
return it->second->intCollectors().defaultCollector();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
return getCollectors(id).intCollectors().defaultCollector();
|
||||
}
|
||||
}
|
||||
|
||||
std::pair< std::vector< std::shared_ptr< DoubleCollector > >,
|
||||
std::vector< std::shared_ptr< IntCollector > > >
|
||||
CollectorRepo::allCollectors(const Id &id)
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
|
||||
auto it = m_collectors.find(id);
|
||||
|
||||
if(it == m_collectors.end())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return {it->second->doubleCollectors().collectors(),
|
||||
it->second->intCollectors().collectors()};
|
||||
}
|
||||
|
||||
struct PublisherHelper
|
||||
{
|
||||
using SampleCache = std::map< std::shared_ptr< Publisher >, Sample >;
|
||||
|
@ -363,49 +196,38 @@ namespace llarp
|
|||
static void
|
||||
updateSampleCache(SampleCache &cache,
|
||||
const std::shared_ptr< Publisher > &publisher,
|
||||
const SampleGroup &sampleGroup,
|
||||
const SampleGroup< double > &doubleGroup,
|
||||
const SampleGroup< int > &intGroup,
|
||||
const absl::Time &timeStamp)
|
||||
{
|
||||
SampleCache::iterator it = cache.find(publisher);
|
||||
if(it == cache.end())
|
||||
{
|
||||
Sample newSample;
|
||||
newSample.sampleTime(timeStamp);
|
||||
it = cache.emplace(publisher, newSample).first;
|
||||
Sample sample;
|
||||
sample.sampleTime(timeStamp);
|
||||
it = cache.emplace(publisher, sample).first;
|
||||
}
|
||||
it->second.pushGroup(sampleGroup);
|
||||
it->second.pushGroup(doubleGroup);
|
||||
it->second.pushGroup(intGroup);
|
||||
}
|
||||
|
||||
static std::pair< std::vector< Record >, absl::Duration >
|
||||
struct CollectResult
|
||||
{
|
||||
Records records;
|
||||
absl::Duration samplePeriod;
|
||||
};
|
||||
|
||||
static CollectResult
|
||||
collect(Manager &manager, const Category *category,
|
||||
const absl::Duration &now, bool clear)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(manager.m_mutex)
|
||||
{
|
||||
using Callback = Manager::RecordCallback;
|
||||
using CallbackVector = std::vector< const Callback * >;
|
||||
using RegistryIterator = CallbackRegistry::iterator;
|
||||
CallbackVector callbacks;
|
||||
|
||||
RegistryIterator begin = manager.m_callbacks.lowerBound(category);
|
||||
RegistryIterator end = manager.m_callbacks.upperBound(category);
|
||||
|
||||
std::vector< Record > result;
|
||||
std::for_each(begin, end, [&](const auto &x) {
|
||||
std::vector< Record > tmp = (x.second)(clear);
|
||||
result.insert(result.end(), tmp.begin(), tmp.end());
|
||||
});
|
||||
|
||||
// Collect records from the repo.
|
||||
if(clear)
|
||||
{
|
||||
std::vector< Record > tmp = manager.m_repo.collectAndClear(category);
|
||||
result.insert(result.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector< Record > tmp = manager.m_repo.collect(category);
|
||||
result.insert(result.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
const Records result = clear
|
||||
? Records(manager.m_doubleRepo.collectAndClear(category),
|
||||
manager.m_intRepo.collectAndClear(category))
|
||||
: Records(manager.m_doubleRepo.collect(category),
|
||||
manager.m_intRepo.collect(category));
|
||||
|
||||
// Get the time since last reset, and clear if needed.
|
||||
Manager::ResetTimes::iterator it = manager.m_resetTimes.find(category);
|
||||
|
@ -428,6 +250,10 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
using RecordBuffer =
|
||||
std::vector< std::shared_ptr< std::vector< Record< Type > > > >;
|
||||
|
||||
template < typename CategoryIterator >
|
||||
static void
|
||||
publish(Manager &manager, const CategoryIterator &categoriesBegin,
|
||||
|
@ -437,10 +263,9 @@ namespace llarp
|
|||
{
|
||||
return;
|
||||
}
|
||||
using RecordBuffer =
|
||||
std::vector< std::shared_ptr< std::vector< Record > > >;
|
||||
|
||||
RecordBuffer recordBuffer;
|
||||
RecordBuffer< double > doubleRecordBuffer;
|
||||
RecordBuffer< int > intRecordBuffer;
|
||||
|
||||
SampleCache sampleCache;
|
||||
|
||||
|
@ -462,40 +287,47 @@ namespace llarp
|
|||
continue;
|
||||
}
|
||||
// Collect the metrics.
|
||||
auto result = collect(manager, *catIt, now, clear);
|
||||
auto result = collect(manager, *catIt, now, clear);
|
||||
const auto &records = result.records;
|
||||
|
||||
// If their are no collected records then this category can be
|
||||
// If there are no collected records then this category can be
|
||||
// ignored.
|
||||
if(result.first.empty())
|
||||
if(records.doubleRecords.empty() && records.intRecords.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(result.second == absl::Duration())
|
||||
if(result.samplePeriod == absl::Duration())
|
||||
{
|
||||
std::cerr << "Invalid elapsed time interval of 0 for "
|
||||
"published metrics.";
|
||||
result.second += absl::Nanoseconds(1);
|
||||
result.samplePeriod += absl::Nanoseconds(1);
|
||||
}
|
||||
|
||||
// Append the collected records to the buffer of records.
|
||||
auto records =
|
||||
std::make_shared< std::vector< Record > >(result.first);
|
||||
recordBuffer.push_back(records);
|
||||
SampleGroup sampleGroup(absl::Span< Record >(*records),
|
||||
result.second);
|
||||
auto dRecords =
|
||||
std::make_shared< DoubleRecords >(records.doubleRecords);
|
||||
doubleRecordBuffer.push_back(dRecords);
|
||||
SampleGroup< double > doubleGroup(
|
||||
absl::Span< Record< double > >(*dRecords), result.samplePeriod);
|
||||
|
||||
std::for_each(
|
||||
manager.m_publishers.globalBegin(),
|
||||
manager.m_publishers.globalEnd(), [&](const auto &ptr) {
|
||||
updateSampleCache(sampleCache, ptr, sampleGroup, timeStamp);
|
||||
});
|
||||
auto iRecords = std::make_shared< IntRecords >(records.intRecords);
|
||||
intRecordBuffer.push_back(iRecords);
|
||||
SampleGroup< int > intGroup(absl::Span< Record< int > >(*iRecords),
|
||||
result.samplePeriod);
|
||||
|
||||
std::for_each(manager.m_publishers.globalBegin(),
|
||||
manager.m_publishers.globalEnd(),
|
||||
[&](const auto &ptr) {
|
||||
updateSampleCache(sampleCache, ptr, doubleGroup,
|
||||
intGroup, timeStamp);
|
||||
});
|
||||
|
||||
std::for_each(manager.m_publishers.lowerBound(*catIt),
|
||||
manager.m_publishers.upperBound(*catIt),
|
||||
[&](const auto &val) {
|
||||
updateSampleCache(sampleCache, val.second,
|
||||
sampleGroup, timeStamp);
|
||||
doubleGroup, intGroup, timeStamp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -503,15 +335,14 @@ namespace llarp
|
|||
for(auto &entry : sampleCache)
|
||||
{
|
||||
Publisher *publisher = entry.first.get();
|
||||
Sample &sample = entry.second;
|
||||
|
||||
publisher->publish(sample);
|
||||
publisher->publish(entry.second);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Sample
|
||||
Manager::collectSample(std::vector< Record > &records,
|
||||
Manager::collectSample(Records &records,
|
||||
absl::Span< const Category * > categories,
|
||||
bool clear)
|
||||
{
|
||||
|
@ -523,8 +354,10 @@ namespace llarp
|
|||
|
||||
// Use a tuple to hold 'references' to the collected records
|
||||
using SampleDescription = std::tuple< size_t, size_t, absl::Duration >;
|
||||
std::vector< SampleDescription > samples;
|
||||
samples.reserve(categories.size());
|
||||
std::vector< SampleDescription > dSamples;
|
||||
std::vector< SampleDescription > iSamples;
|
||||
dSamples.reserve(categories.size());
|
||||
iSamples.reserve(categories.size());
|
||||
|
||||
// 1
|
||||
absl::WriterMutexLock publishGuard(&m_publishLock);
|
||||
|
@ -538,29 +371,46 @@ namespace llarp
|
|||
continue;
|
||||
}
|
||||
|
||||
size_t beginIndex = records.size();
|
||||
size_t dBeginIndex = records.doubleRecords.size();
|
||||
size_t iBeginIndex = records.intRecords.size();
|
||||
|
||||
// Collect the metrics.
|
||||
std::vector< Record > catRecords;
|
||||
absl::Duration elapsedTime;
|
||||
std::tie(catRecords, elapsedTime) =
|
||||
PublisherHelper::collect(*this, category, now, clear);
|
||||
records.insert(records.end(), catRecords.begin(), catRecords.end());
|
||||
auto collectRes = PublisherHelper::collect(*this, category, now, clear);
|
||||
DoubleRecords catDRecords = collectRes.records.doubleRecords;
|
||||
IntRecords catIRecords = collectRes.records.intRecords;
|
||||
|
||||
size_t size = records.size() - beginIndex;
|
||||
absl::Duration elapsedTime = collectRes.samplePeriod;
|
||||
|
||||
records.doubleRecords.insert(records.doubleRecords.end(),
|
||||
catDRecords.begin(), catDRecords.end());
|
||||
records.intRecords.insert(records.intRecords.end(), catIRecords.begin(),
|
||||
catIRecords.end());
|
||||
|
||||
size_t dSize = records.doubleRecords.size() - dBeginIndex;
|
||||
size_t iSize = records.intRecords.size() - iBeginIndex;
|
||||
|
||||
// If there are no collected records then this category can be ignored.
|
||||
if(size != 0)
|
||||
if(dSize != 0)
|
||||
{
|
||||
samples.emplace_back(beginIndex, size, elapsedTime);
|
||||
dSamples.emplace_back(dBeginIndex, dSize, elapsedTime);
|
||||
}
|
||||
if(iSize != 0)
|
||||
{
|
||||
iSamples.emplace_back(iBeginIndex, iSize, elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have all the records, we can build our sample
|
||||
for(const SampleDescription &s : samples)
|
||||
for(const SampleDescription &s : dSamples)
|
||||
{
|
||||
sample.pushGroup(&records[std::get< 0 >(s)], std::get< 1 >(s),
|
||||
std::get< 2 >(s));
|
||||
sample.pushGroup(&records.doubleRecords[std::get< 0 >(s)],
|
||||
std::get< 1 >(s), std::get< 2 >(s));
|
||||
}
|
||||
|
||||
for(const SampleDescription &s : iSamples)
|
||||
{
|
||||
sample.pushGroup(&records.intRecords[std::get< 0 >(s)],
|
||||
std::get< 1 >(s), std::get< 2 >(s));
|
||||
}
|
||||
|
||||
return sample;
|
||||
|
|
|
@ -14,96 +14,22 @@ namespace llarp
|
|||
{
|
||||
namespace metrics
|
||||
{
|
||||
class IntCollector
|
||||
template < typename Type >
|
||||
class Collector
|
||||
{
|
||||
const Id m_id;
|
||||
size_t m_count GUARDED_BY(m_mutex);
|
||||
int64_t m_total GUARDED_BY(m_mutex);
|
||||
int m_min GUARDED_BY(m_mutex);
|
||||
int m_max GUARDED_BY(m_mutex);
|
||||
public:
|
||||
using RecordType = Record< Type >;
|
||||
|
||||
private:
|
||||
RecordType m_record GUARDED_BY(m_mutex);
|
||||
mutable util::Mutex m_mutex;
|
||||
|
||||
IntCollector(const IntCollector &) = delete;
|
||||
IntCollector &
|
||||
operator=(const IntCollector &) = delete;
|
||||
Collector(const Collector &) = delete;
|
||||
Collector &
|
||||
operator=(const Collector &) = delete;
|
||||
|
||||
public:
|
||||
static constexpr int DEFAULT_MIN = std::numeric_limits< int >::max();
|
||||
static constexpr int DEFAULT_MAX = std::numeric_limits< int >::min();
|
||||
|
||||
IntCollector(const Id &id)
|
||||
: m_id(id)
|
||||
, m_count(0)
|
||||
, m_total(0)
|
||||
, m_min(DEFAULT_MIN)
|
||||
, m_max(DEFAULT_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
const Id &
|
||||
id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_count = 0;
|
||||
m_total = 0;
|
||||
m_min = DEFAULT_MIN;
|
||||
m_max = DEFAULT_MAX;
|
||||
}
|
||||
|
||||
Record
|
||||
loadAndClear();
|
||||
|
||||
Record
|
||||
load();
|
||||
|
||||
void
|
||||
tick(int value)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_count++;
|
||||
m_total += value;
|
||||
m_min = std::min(m_min, value);
|
||||
m_max = std::max(m_max, value);
|
||||
}
|
||||
|
||||
void
|
||||
accumulate(size_t count, int total, int min, int max)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_count += count;
|
||||
m_total += total;
|
||||
m_min = std::min(m_min, min);
|
||||
m_max = std::max(m_max, max);
|
||||
}
|
||||
|
||||
void
|
||||
set(size_t count, int total, int min, int max)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_count = count;
|
||||
m_total = total;
|
||||
m_min = min;
|
||||
m_max = max;
|
||||
}
|
||||
};
|
||||
|
||||
class DoubleCollector
|
||||
{
|
||||
Record m_record GUARDED_BY(m_mutex);
|
||||
mutable util::Mutex m_mutex;
|
||||
|
||||
DoubleCollector(const DoubleCollector &) = delete;
|
||||
DoubleCollector &
|
||||
operator=(const DoubleCollector &) = delete;
|
||||
|
||||
public:
|
||||
DoubleCollector(const Id &id) : m_record(id)
|
||||
Collector(const Id &id) : m_record(id)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -111,26 +37,20 @@ namespace llarp
|
|||
clear()
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.count() = 0;
|
||||
m_record.total() = 0.0;
|
||||
m_record.min() = Record::DEFAULT_MIN;
|
||||
m_record.max() = Record::DEFAULT_MAX;
|
||||
m_record.clear();
|
||||
}
|
||||
|
||||
Record
|
||||
RecordType
|
||||
loadAndClear()
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
Record rec = m_record;
|
||||
m_record.count() = 0;
|
||||
m_record.total() = 0.0;
|
||||
m_record.min() = Record::DEFAULT_MIN;
|
||||
m_record.max() = Record::DEFAULT_MAX;
|
||||
RecordType rec = m_record;
|
||||
m_record.clear();
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
Record
|
||||
RecordType
|
||||
load()
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
|
@ -138,7 +58,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
tick(double value)
|
||||
tick(Type value)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.count()++;
|
||||
|
@ -148,7 +68,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
accumulate(size_t count, double total, double min, double max)
|
||||
accumulate(size_t count, Type total, Type min, Type max)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.count() += count;
|
||||
|
@ -158,7 +78,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
set(size_t count, double total, double min, double max)
|
||||
set(size_t count, Type total, Type min, Type max)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.count() = count;
|
||||
|
@ -175,36 +95,38 @@ namespace llarp
|
|||
}
|
||||
};
|
||||
|
||||
using IntCollector = Collector< int >;
|
||||
using DoubleCollector = Collector< double >;
|
||||
|
||||
class Publisher
|
||||
{
|
||||
public:
|
||||
virtual ~Publisher() = 0;
|
||||
virtual ~Publisher() = default;
|
||||
|
||||
virtual void
|
||||
publish(const Sample &sample) = 0;
|
||||
};
|
||||
|
||||
inline Publisher::~Publisher()
|
||||
{
|
||||
}
|
||||
|
||||
template < typename LhsType, typename RhsType >
|
||||
static inline void
|
||||
combine(Record &record, const Record &toAdd)
|
||||
combine(Record< LhsType > &record, const Record< RhsType > &toAdd)
|
||||
{
|
||||
static_assert(std::is_convertible< RhsType, LhsType >::value, "");
|
||||
record.id() = toAdd.id();
|
||||
record.count() += toAdd.count();
|
||||
record.total() += toAdd.total();
|
||||
record.min() = std::min(record.min(), toAdd.min());
|
||||
record.max() = std::max(record.max(), toAdd.max());
|
||||
record.min() = std::min(record.min(), LhsType(toAdd.min()));
|
||||
record.max() = std::max(record.max(), LhsType(toAdd.max()));
|
||||
}
|
||||
|
||||
template < typename Collector >
|
||||
template < typename Type >
|
||||
class Collectors
|
||||
{
|
||||
using CollectorPtr = std::shared_ptr< Collector >;
|
||||
using CollectorSet = std::set< CollectorPtr >;
|
||||
using CollectorType = Collector< Type >;
|
||||
using CollectorPtr = std::shared_ptr< CollectorType >;
|
||||
using CollectorSet = std::set< CollectorPtr >;
|
||||
|
||||
Collector m_default;
|
||||
CollectorType m_default;
|
||||
CollectorSet m_collectors;
|
||||
|
||||
Collectors(const Collectors &) = delete;
|
||||
|
@ -216,32 +138,32 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
Collector *
|
||||
CollectorType *
|
||||
defaultCollector()
|
||||
{
|
||||
return &m_default;
|
||||
}
|
||||
|
||||
std::shared_ptr< Collector >
|
||||
std::shared_ptr< CollectorType >
|
||||
add()
|
||||
{
|
||||
auto ptr = std::make_shared< Collector >(m_default.id());
|
||||
auto ptr = std::make_shared< CollectorType >(m_default.id());
|
||||
m_collectors.insert(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool
|
||||
remove(Collector *collector)
|
||||
remove(CollectorType *collector)
|
||||
{
|
||||
std::shared_ptr< Collector > ptr(collector, [](Collector *) {});
|
||||
std::shared_ptr< CollectorType > ptr(collector, [](CollectorType *) {});
|
||||
size_t count = m_collectors.erase(ptr);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
Record
|
||||
Record< Type >
|
||||
combineAndClear()
|
||||
{
|
||||
Record rec = m_default.loadAndClear();
|
||||
Record< Type > rec = m_default.loadAndClear();
|
||||
|
||||
for(auto &ptr : m_collectors)
|
||||
{
|
||||
|
@ -251,10 +173,10 @@ namespace llarp
|
|||
return rec;
|
||||
}
|
||||
|
||||
Record
|
||||
Record< Type >
|
||||
combine()
|
||||
{
|
||||
Record rec = m_default.load();
|
||||
Record< Type > rec = m_default.load();
|
||||
|
||||
for(auto &ptr : m_collectors)
|
||||
{
|
||||
|
@ -263,11 +185,11 @@ namespace llarp
|
|||
return rec;
|
||||
}
|
||||
|
||||
std::vector< std::shared_ptr< Collector > >
|
||||
std::vector< std::shared_ptr< CollectorType > >
|
||||
collectors() const
|
||||
{
|
||||
return std::vector< std::shared_ptr< Collector > >(m_collectors.begin(),
|
||||
m_collectors.end());
|
||||
return std::vector< std::shared_ptr< CollectorType > >(
|
||||
m_collectors.begin(), m_collectors.end());
|
||||
}
|
||||
|
||||
const Id &
|
||||
|
@ -277,70 +199,8 @@ namespace llarp
|
|||
}
|
||||
};
|
||||
|
||||
class MetricCollectors
|
||||
{
|
||||
using DoubleCollectors = Collectors< DoubleCollector >;
|
||||
using IntCollectors = Collectors< IntCollector >;
|
||||
|
||||
DoubleCollectors m_doubleCollectors;
|
||||
IntCollectors m_intCollectors;
|
||||
|
||||
MetricCollectors(const MetricCollectors &) = delete;
|
||||
MetricCollectors &
|
||||
operator=(const MetricCollectors &) = delete;
|
||||
|
||||
public:
|
||||
MetricCollectors(const Id &id)
|
||||
: m_doubleCollectors(id), m_intCollectors(id)
|
||||
{
|
||||
}
|
||||
|
||||
Collectors< DoubleCollector > &
|
||||
doubleCollectors()
|
||||
{
|
||||
return m_doubleCollectors;
|
||||
}
|
||||
|
||||
Collectors< IntCollector > &
|
||||
intCollectors()
|
||||
{
|
||||
return m_intCollectors;
|
||||
}
|
||||
|
||||
const Collectors< DoubleCollector > &
|
||||
doubleCollectors() const
|
||||
{
|
||||
return m_doubleCollectors;
|
||||
}
|
||||
|
||||
const Collectors< IntCollector > &
|
||||
intCollectors() const
|
||||
{
|
||||
return m_intCollectors;
|
||||
}
|
||||
|
||||
Record
|
||||
combineAndClear()
|
||||
{
|
||||
Record res = m_doubleCollectors.combineAndClear();
|
||||
metrics::combine(res, m_intCollectors.combineAndClear());
|
||||
return res;
|
||||
}
|
||||
|
||||
Record
|
||||
combine()
|
||||
{
|
||||
Record res = m_doubleCollectors.combine();
|
||||
metrics::combine(res, m_intCollectors.combine());
|
||||
return res;
|
||||
}
|
||||
|
||||
const Id &
|
||||
id() const
|
||||
{
|
||||
return m_intCollectors.id();
|
||||
}
|
||||
};
|
||||
using DoubleCollectors = Collectors< double >;
|
||||
using IntCollectors = Collectors< int >;
|
||||
|
||||
class Registry
|
||||
{
|
||||
|
@ -436,83 +296,163 @@ namespace llarp
|
|||
getAll() const;
|
||||
};
|
||||
|
||||
using DoubleRecords = std::vector< Record< double > >;
|
||||
using IntRecords = std::vector< Record< int > >;
|
||||
|
||||
struct Records
|
||||
{
|
||||
DoubleRecords doubleRecords;
|
||||
IntRecords intRecords;
|
||||
|
||||
Records()
|
||||
{
|
||||
}
|
||||
|
||||
Records(const DoubleRecords &d, const IntRecords &i)
|
||||
: doubleRecords(d), intRecords(i)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator==(const Records &lhs, const Records &rhs)
|
||||
{
|
||||
return std::tie(lhs.doubleRecords, lhs.intRecords)
|
||||
== std::tie(rhs.doubleRecords, rhs.intRecords);
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
class CollectorRepo
|
||||
{
|
||||
using MetricCollectorsPtr = std::shared_ptr< MetricCollectors >;
|
||||
using IdCollectors = std::map< Id, MetricCollectorsPtr >;
|
||||
using CollectorsPtr = std::shared_ptr< Collectors< Type > >;
|
||||
using IdCollectors = std::map< Id, CollectorsPtr >;
|
||||
using CategoryCollectors =
|
||||
std::map< const Category *, std::vector< MetricCollectors * > >;
|
||||
std::map< const Category *, std::vector< Collectors< Type > * > >;
|
||||
|
||||
Registry *m_registry;
|
||||
IdCollectors m_collectors;
|
||||
CategoryCollectors m_categories;
|
||||
|
||||
mutable util::Mutex m_mutex;
|
||||
|
||||
CollectorRepo(const CollectorRepo &) = delete;
|
||||
CollectorRepo &
|
||||
operator=(const CollectorRepo &) = delete;
|
||||
|
||||
MetricCollectors &
|
||||
getCollectors(const Id &id);
|
||||
Collectors< Type > &
|
||||
getCollectors(const Id &id)
|
||||
{
|
||||
auto it = m_collectors.find(id);
|
||||
|
||||
if(it == m_collectors.end())
|
||||
{
|
||||
assert(id.valid());
|
||||
|
||||
const Category *cat = id.category();
|
||||
|
||||
auto ptr = std::make_shared< Collectors< Type > >(id);
|
||||
auto &vec = m_categories[cat];
|
||||
vec.reserve(vec.size() + 1);
|
||||
|
||||
it = m_collectors.emplace(id, ptr).first;
|
||||
vec.push_back(ptr.get());
|
||||
}
|
||||
|
||||
return *it->second.get();
|
||||
}
|
||||
|
||||
template < Record< Type > (Collectors< Type >::*func)() >
|
||||
std::vector< Record< Type > >
|
||||
collectOp(const Category *category)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
|
||||
auto it = m_categories.find(category);
|
||||
|
||||
if(it == m_categories.end())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector< Record< Type > > result;
|
||||
auto &collectors = it->second;
|
||||
result.reserve(collectors.size());
|
||||
|
||||
std::transform(collectors.begin(), collectors.end(),
|
||||
std::back_inserter(result),
|
||||
[](auto &collector) { return (collector->*func)(); });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
CollectorRepo(Registry *registry) : m_registry(registry)
|
||||
explicit CollectorRepo(Registry *registry) : m_registry(registry)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector< Record >
|
||||
collectAndClear(const Category *category);
|
||||
|
||||
std::vector< Record >
|
||||
collect(const Category *category);
|
||||
|
||||
DoubleCollector *
|
||||
defaultDoubleCollector(const char *category, const char *name)
|
||||
std::vector< Record< Type > >
|
||||
collectAndClear(const Category *category)
|
||||
{
|
||||
return defaultDoubleCollector(m_registry->get(category, name));
|
||||
return collectOp< &Collectors< Type >::combineAndClear >(category);
|
||||
}
|
||||
|
||||
DoubleCollector *
|
||||
defaultDoubleCollector(const Id &id);
|
||||
|
||||
IntCollector *
|
||||
defaultIntCollector(const char *category, const char *name)
|
||||
std::vector< Record< Type > >
|
||||
collect(const Category *category)
|
||||
{
|
||||
return defaultIntCollector(m_registry->get(category, name));
|
||||
return collectOp< &Collectors< Type >::combine >(category);
|
||||
}
|
||||
|
||||
IntCollector *
|
||||
defaultIntCollector(const Id &id);
|
||||
|
||||
std::shared_ptr< DoubleCollector >
|
||||
addDoubleCollector(const char *category, const char *name)
|
||||
Collector< Type > *
|
||||
defaultCollector(const char *category, const char *name)
|
||||
{
|
||||
return addDoubleCollector(m_registry->get(category, name));
|
||||
return defaultCollector(m_registry->get(category, name));
|
||||
}
|
||||
|
||||
std::shared_ptr< DoubleCollector >
|
||||
addDoubleCollector(const Id &id)
|
||||
Collector< Type > *
|
||||
defaultCollector(const Id &id)
|
||||
{
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
auto it = m_collectors.find(id);
|
||||
if(it != m_collectors.end())
|
||||
{
|
||||
return it->second->defaultCollector();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
return getCollectors(id).defaultCollector();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr< Collector< Type > >
|
||||
addCollector(const char *category, const char *name)
|
||||
{
|
||||
return addCollector(m_registry->get(category, name));
|
||||
}
|
||||
|
||||
std::shared_ptr< Collector< Type > >
|
||||
addCollector(const Id &id)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
return getCollectors(id).doubleCollectors().add();
|
||||
return getCollectors(id).add();
|
||||
}
|
||||
|
||||
std::shared_ptr< IntCollector >
|
||||
addIntCollector(const char *category, const char *name)
|
||||
std::vector< std::shared_ptr< Collector< Type > > >
|
||||
allCollectors(const Id &id)
|
||||
{
|
||||
return addIntCollector(m_registry->get(category, name));
|
||||
}
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
|
||||
std::shared_ptr< IntCollector >
|
||||
addIntCollector(const Id &id)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
return getCollectors(id).intCollectors().add();
|
||||
}
|
||||
auto it = m_collectors.find(id);
|
||||
|
||||
std::pair< std::vector< std::shared_ptr< DoubleCollector > >,
|
||||
std::vector< std::shared_ptr< IntCollector > > >
|
||||
allCollectors(const Id &id);
|
||||
if(it == m_collectors.end())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return it->second->collectors();
|
||||
}
|
||||
|
||||
Registry &
|
||||
registry()
|
||||
|
@ -677,91 +617,6 @@ namespace llarp
|
|||
}
|
||||
};
|
||||
|
||||
class CallbackRegistry
|
||||
{
|
||||
using Handle = uint64_t;
|
||||
using RecordCallback = std::function< std::vector< Record >(bool) >;
|
||||
using CallbackMap = std::multimap< const Category *, RecordCallback >;
|
||||
using HandleMap = std::map< Handle, CallbackMap::iterator >;
|
||||
|
||||
Handle m_next;
|
||||
CallbackMap m_callbackMap;
|
||||
HandleMap m_handleMap;
|
||||
|
||||
CallbackRegistry(const CallbackRegistry &) = delete;
|
||||
CallbackRegistry &
|
||||
operator=(const CallbackRegistry &) = delete;
|
||||
|
||||
public:
|
||||
using iterator = CallbackMap::iterator;
|
||||
|
||||
CallbackRegistry() : m_next(1)
|
||||
{
|
||||
}
|
||||
|
||||
Handle
|
||||
registerCallback(const Category *category, const RecordCallback &callback)
|
||||
{
|
||||
Handle handle = m_next++;
|
||||
|
||||
auto it = m_callbackMap.emplace(category, callback);
|
||||
m_handleMap.emplace(handle, it);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool
|
||||
removeCallback(Handle handle)
|
||||
{
|
||||
auto it = m_handleMap.find(handle);
|
||||
|
||||
if(it == m_handleMap.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_callbackMap.erase(it->second);
|
||||
m_handleMap.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
return m_callbackMap.begin();
|
||||
}
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
return m_callbackMap.end();
|
||||
}
|
||||
|
||||
iterator
|
||||
lowerBound(const Category *category)
|
||||
{
|
||||
return m_callbackMap.lower_bound(category);
|
||||
}
|
||||
iterator
|
||||
upperBound(const Category *category)
|
||||
{
|
||||
return m_callbackMap.upper_bound(category);
|
||||
}
|
||||
|
||||
std::vector< const RecordCallback * >
|
||||
callbacksFor(const Category *category) const
|
||||
{
|
||||
std::vector< const RecordCallback * > result;
|
||||
auto beg = m_callbackMap.lower_bound(category);
|
||||
auto end = m_callbackMap.upper_bound(category);
|
||||
|
||||
result.reserve(std::distance(beg, end));
|
||||
std::transform(beg, end, std::back_inserter(result),
|
||||
[](const auto &x) { return &x.second; });
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct PublisherHelper;
|
||||
|
||||
/// The big dog.
|
||||
|
@ -772,8 +627,6 @@ namespace llarp
|
|||
public:
|
||||
// Public callback. If the bool flag is true, clear the metrics back to
|
||||
// their default state.
|
||||
using RecordCallback = std::function< std::vector< Record >(bool) >;
|
||||
|
||||
using Handle = uint64_t;
|
||||
|
||||
private:
|
||||
|
@ -783,8 +636,8 @@ namespace llarp
|
|||
friend struct PublisherHelper;
|
||||
|
||||
Registry m_registry;
|
||||
CollectorRepo m_repo;
|
||||
CallbackRegistry m_callbacks GUARDED_BY(m_mutex);
|
||||
CollectorRepo< double > m_doubleRepo;
|
||||
CollectorRepo< int > m_intRepo;
|
||||
PublisherRegistry m_publishers GUARDED_BY(m_mutex);
|
||||
|
||||
const absl::Duration m_createTime;
|
||||
|
@ -798,30 +651,12 @@ namespace llarp
|
|||
std::numeric_limits< Handle >::max();
|
||||
|
||||
Manager()
|
||||
: m_repo(&m_registry), m_createTime(absl::Now() - absl::UnixEpoch())
|
||||
: m_doubleRepo(&m_registry)
|
||||
, m_intRepo(&m_registry)
|
||||
, m_createTime(absl::Now() - absl::UnixEpoch())
|
||||
{
|
||||
}
|
||||
|
||||
/// Register a callback for
|
||||
Handle
|
||||
registerCallback(const char *categoryName, const RecordCallback &callback)
|
||||
{
|
||||
return registerCallback(m_registry.get(categoryName), callback);
|
||||
}
|
||||
Handle
|
||||
registerCallback(const Category *category, const RecordCallback &callback)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
return m_callbacks.registerCallback(category, callback);
|
||||
}
|
||||
|
||||
bool
|
||||
removeCallback(Handle handle)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
return m_callbacks.removeCallback(handle);
|
||||
}
|
||||
|
||||
/// Add a `publisher` which will receive all events
|
||||
bool
|
||||
addGlobalPublisher(const std::shared_ptr< Publisher > &publisher)
|
||||
|
@ -862,23 +697,23 @@ namespace llarp
|
|||
}
|
||||
|
||||
// clang-format off
|
||||
CollectorRepo& collectorRepo() { return m_repo; }
|
||||
const CollectorRepo& collectorRepo() const { return m_repo; }
|
||||
CollectorRepo<double>& doubleCollectorRepo() { return m_doubleRepo; }
|
||||
CollectorRepo<int>& intCollectorRepo() { return m_intRepo; }
|
||||
Registry& registry() { return m_registry; }
|
||||
const Registry& registry() const { return m_registry; }
|
||||
// clang-format on
|
||||
|
||||
/// Publish specific categories of metric matching the category/categories
|
||||
Sample
|
||||
collectSample(std::vector< Record > &records, bool clear = false)
|
||||
collectSample(Records &records, bool clear = false)
|
||||
{
|
||||
std::vector< const Category * > allCategories = m_registry.getAll();
|
||||
return collectSample(
|
||||
records, absl::Span< const Category * >{allCategories}, clear);
|
||||
}
|
||||
|
||||
Sample
|
||||
collectSample(std::vector< Record > &records,
|
||||
absl::Span< const Category * > categories,
|
||||
collectSample(Records &records, absl::Span< const Category * > categories,
|
||||
bool clear = false);
|
||||
|
||||
/// Publish specific categories of metric matching the category/categories
|
||||
|
@ -1026,8 +861,7 @@ namespace llarp
|
|||
};
|
||||
|
||||
template < typename Collector, typename Value,
|
||||
Collector *(CollectorRepo::*catFunc)(const char *, const char *),
|
||||
Collector *(CollectorRepo::*idFunc)(const Id &) >
|
||||
CollectorRepo< Value > &(Manager::*repoFunc)() >
|
||||
class Metric
|
||||
{
|
||||
Collector *m_collector; // can be null
|
||||
|
@ -1038,7 +872,7 @@ namespace llarp
|
|||
lookup(const char *category, const char *name, Manager *manager = nullptr)
|
||||
{
|
||||
manager = DefaultManager::manager(manager);
|
||||
return manager ? (manager->collectorRepo().*catFunc)(category, name)
|
||||
return manager ? (manager->*repoFunc)().defaultCollector(category, name)
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
@ -1046,7 +880,7 @@ namespace llarp
|
|||
lookup(const Id &id, Manager *manager = nullptr)
|
||||
{
|
||||
manager = DefaultManager::manager(manager);
|
||||
return manager ? (manager->collectorRepo().*idFunc)(id) : 0;
|
||||
return manager ? (manager->*repoFunc)().defaultCollector(id) : 0;
|
||||
}
|
||||
|
||||
Metric(const char *category, const char *name, Manager *manager)
|
||||
|
@ -1135,7 +969,7 @@ namespace llarp
|
|||
const char *category, const char *metric)
|
||||
{
|
||||
Manager *manager = DefaultManager::instance();
|
||||
*collector = manager->collectorRepo().*catFunc(category, metric);
|
||||
*collector = (manager->*repoFunc().defaultCollector)(category, metric);
|
||||
manager->registry().registerContainer((*collector)->id().category(),
|
||||
container);
|
||||
}
|
||||
|
@ -1146,7 +980,7 @@ namespace llarp
|
|||
Publication::Type type)
|
||||
{
|
||||
Manager *manager = DefaultManager::instance();
|
||||
*collector = manager->collectorRepo().*catFunc(category, metric);
|
||||
*collector = (manager->*repoFunc().defaultCollector)(category, metric);
|
||||
manager->registry().registerContainer((*collector)->id().category(),
|
||||
container);
|
||||
manager->registry().publicationType((*collector)->id(), type);
|
||||
|
@ -1154,12 +988,9 @@ namespace llarp
|
|||
};
|
||||
|
||||
using DoubleMetric =
|
||||
Metric< DoubleCollector, double, &CollectorRepo::defaultDoubleCollector,
|
||||
&CollectorRepo::defaultDoubleCollector >;
|
||||
Metric< DoubleCollector, double, &Manager::doubleCollectorRepo >;
|
||||
|
||||
using IntMetric =
|
||||
Metric< IntCollector, int, &CollectorRepo::defaultIntCollector,
|
||||
&CollectorRepo::defaultIntCollector >;
|
||||
using IntMetric = Metric< IntCollector, int, &Manager::intCollectorRepo >;
|
||||
|
||||
class TimerGuard
|
||||
{
|
||||
|
|
|
@ -139,40 +139,6 @@ namespace llarp
|
|||
|
||||
return stream;
|
||||
}
|
||||
|
||||
const double Record::DEFAULT_MIN = std::numeric_limits< double >::max() * 2;
|
||||
const double Record::DEFAULT_MAX =
|
||||
std::numeric_limits< double >::max() * -2;
|
||||
|
||||
std::ostream &
|
||||
Record::print(std::ostream &stream, int level, int spaces) const
|
||||
{
|
||||
Printer printer(stream, level, spaces);
|
||||
printer.printAttribute("id", m_id);
|
||||
printer.printAttribute("count", m_count);
|
||||
printer.printAttribute("total", m_total);
|
||||
printer.printAttribute("min", m_min);
|
||||
printer.printAttribute("max", m_max);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
SampleGroup::print(std::ostream &stream, int level, int spaces) const
|
||||
{
|
||||
Printer::PrintFunction< absl::Duration > durationPrinter =
|
||||
[](std::ostream &stream, const absl::Duration &duration, int,
|
||||
int) -> std::ostream & {
|
||||
stream << duration;
|
||||
return stream;
|
||||
};
|
||||
Printer printer(stream, level, spaces);
|
||||
printer.printAttribute("records", m_records);
|
||||
printer.printForeignAttribute("samplePeriod", m_samplePeriod,
|
||||
durationPrinter);
|
||||
|
||||
return stream;
|
||||
}
|
||||
} // namespace metrics
|
||||
|
||||
} // namespace llarp
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
#ifndef LLARP_METRICS_TYPES_HPP
|
||||
#define LLARP_METRICS_TYPES_HPP
|
||||
|
||||
#include <util/printer.hpp>
|
||||
#include <util/string_view.hpp>
|
||||
#include <util/threading.hpp>
|
||||
#include <util/types.hpp>
|
||||
#include <util/variant.hpp>
|
||||
|
||||
#include <absl/types/span.h>
|
||||
#include <absl/types/optional.h>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <absl/types/variant.h>
|
||||
#include <cstring>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -368,32 +372,55 @@ namespace llarp
|
|||
return id.print(stream, -1, -1);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// Forwarding class to specialise for metric types
|
||||
template<typename Type>
|
||||
struct RecordMax {
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RecordMax<double> {
|
||||
static constexpr double min() { return std::numeric_limits< double >::infinity(); }
|
||||
static constexpr double max() { return -std::numeric_limits< double >::infinity(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RecordMax<int> {
|
||||
static constexpr int min() { return std::numeric_limits< int >::max(); }
|
||||
static constexpr int max() { return std::numeric_limits< int >::min(); }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
template < typename Type >
|
||||
class Record
|
||||
{
|
||||
Id m_id;
|
||||
size_t m_count;
|
||||
double m_total;
|
||||
double m_min;
|
||||
double m_max;
|
||||
Type m_total;
|
||||
Type m_min;
|
||||
Type m_max;
|
||||
|
||||
public:
|
||||
static const double DEFAULT_MIN;
|
||||
static const double DEFAULT_MAX;
|
||||
// clang-format off
|
||||
static constexpr Type DEFAULT_MIN() { return RecordMax<Type>::min(); };
|
||||
static constexpr Type DEFAULT_MAX() { return RecordMax<Type>::max(); };
|
||||
// clang-format on
|
||||
|
||||
Record()
|
||||
: m_id()
|
||||
, m_count(0)
|
||||
, m_total(0.0)
|
||||
, m_min(DEFAULT_MIN)
|
||||
, m_max(DEFAULT_MAX)
|
||||
, m_min(DEFAULT_MIN())
|
||||
, m_max(DEFAULT_MAX())
|
||||
{
|
||||
}
|
||||
|
||||
explicit Record(const Id &id)
|
||||
: m_id(id)
|
||||
, m_count(0)
|
||||
, m_total(0.0)
|
||||
, m_min(DEFAULT_MIN)
|
||||
, m_max(DEFAULT_MAX)
|
||||
, m_total()
|
||||
, m_min(DEFAULT_MIN())
|
||||
, m_max(DEFAULT_MAX())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -409,53 +436,84 @@ namespace llarp
|
|||
size_t count() const { return m_count; }
|
||||
size_t& count() { return m_count; }
|
||||
|
||||
double total() const { return m_total; }
|
||||
double& total() { return m_total; }
|
||||
Type total() const { return m_total; }
|
||||
Type& total() { return m_total; }
|
||||
|
||||
double min() const { return m_min; }
|
||||
double& min() { return m_min; }
|
||||
Type min() const { return m_min; }
|
||||
Type& min() { return m_min; }
|
||||
|
||||
double max() const { return m_max; }
|
||||
double& max() { return m_max; }
|
||||
Type max() const { return m_max; }
|
||||
Type& max() { return m_max; }
|
||||
// clang-format on
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
m_count = 0;
|
||||
m_total = 0;
|
||||
m_min = DEFAULT_MIN();
|
||||
m_max = DEFAULT_MAX();
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
print(std::ostream &stream, int level, int spaces) const;
|
||||
print(std::ostream &stream, int level, int spaces) const
|
||||
{
|
||||
Printer printer(stream, level, spaces);
|
||||
printer.printAttribute("id", m_id);
|
||||
printer.printAttribute("count", m_count);
|
||||
printer.printAttribute("total", m_total);
|
||||
printer.printAttribute("min", m_min);
|
||||
printer.printAttribute("max", m_max);
|
||||
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename Type >
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream &stream, const Record &rec)
|
||||
operator<<(std::ostream &stream, const Record< Type > &rec)
|
||||
{
|
||||
return rec.print(stream, -1, -1);
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
inline bool
|
||||
operator==(const Record &lhs, const Record &rhs)
|
||||
operator==(const Record< Type > &lhs, const Record< Type > &rhs)
|
||||
{
|
||||
return (lhs.id() == rhs.id() && lhs.count() == rhs.count()
|
||||
&& lhs.total() == rhs.total() && lhs.min() == rhs.min()
|
||||
&& lhs.max() == rhs.max());
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
inline bool
|
||||
operator!=(const Record< Type > &lhs, const Record< Type > &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
class SampleGroup
|
||||
{
|
||||
absl::Span< const Record > m_records;
|
||||
absl::Span< const Record< Type > > m_records;
|
||||
absl::Duration m_samplePeriod;
|
||||
|
||||
public:
|
||||
using const_iterator = absl::Span< const Record >::const_iterator;
|
||||
using RecordType = Record< Type >;
|
||||
using const_iterator =
|
||||
typename absl::Span< const RecordType >::const_iterator;
|
||||
|
||||
SampleGroup() : m_records(), m_samplePeriod()
|
||||
{
|
||||
}
|
||||
|
||||
SampleGroup(const Record *records, size_t size,
|
||||
SampleGroup(const RecordType *records, size_t size,
|
||||
absl::Duration samplePeriod)
|
||||
: m_records(records, size), m_samplePeriod(samplePeriod)
|
||||
{
|
||||
}
|
||||
|
||||
SampleGroup(const absl::Span< const Record > &records,
|
||||
SampleGroup(const absl::Span< const RecordType > &records,
|
||||
absl::Duration samplePeriod)
|
||||
: m_records(records), m_samplePeriod(samplePeriod)
|
||||
{
|
||||
|
@ -465,8 +523,8 @@ namespace llarp
|
|||
void samplePeriod(absl::Duration duration) { m_samplePeriod = duration; }
|
||||
absl::Duration samplePeriod() const { return m_samplePeriod; }
|
||||
|
||||
void records(absl::Span<const Record> recs) { m_records = recs; }
|
||||
absl::Span<const Record> records() const { return m_records; }
|
||||
void records(absl::Span<const RecordType> recs) { m_records = recs; }
|
||||
absl::Span<const RecordType> records() const { return m_records; }
|
||||
|
||||
bool empty() const { return m_records.empty(); }
|
||||
size_t size() const { return m_records.size(); }
|
||||
|
@ -476,17 +534,33 @@ namespace llarp
|
|||
// clang-format on
|
||||
|
||||
std::ostream &
|
||||
print(std::ostream &stream, int level, int spaces) const;
|
||||
print(std::ostream &stream, int level, int spaces) const
|
||||
{
|
||||
Printer::PrintFunction< absl::Duration > durationPrinter =
|
||||
[](std::ostream &stream, const absl::Duration &duration, int,
|
||||
int) -> std::ostream & {
|
||||
stream << duration;
|
||||
return stream;
|
||||
};
|
||||
Printer printer(stream, level, spaces);
|
||||
printer.printAttribute("records", m_records);
|
||||
printer.printForeignAttribute("samplePeriod", m_samplePeriod,
|
||||
durationPrinter);
|
||||
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename Type >
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream &stream, const SampleGroup &group)
|
||||
operator<<(std::ostream &stream, const SampleGroup< Type > &group)
|
||||
{
|
||||
return group.print(stream, -1, -1);
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
inline bool
|
||||
operator==(const SampleGroup &lhs, const SampleGroup &rhs)
|
||||
operator==(const SampleGroup< Type > &lhs, const SampleGroup< Type > &rhs)
|
||||
{
|
||||
return lhs.records() == rhs.records()
|
||||
&& lhs.samplePeriod() == rhs.samplePeriod();
|
||||
|
@ -495,11 +569,12 @@ namespace llarp
|
|||
class Sample
|
||||
{
|
||||
absl::Time m_sampleTime;
|
||||
std::vector< SampleGroup > m_samples;
|
||||
std::vector< absl::variant< SampleGroup< double >, SampleGroup< int > > >
|
||||
m_samples;
|
||||
size_t m_recordCount;
|
||||
|
||||
public:
|
||||
using const_iterator = std::vector< SampleGroup >::const_iterator;
|
||||
using const_iterator = typename decltype(m_samples)::const_iterator;
|
||||
|
||||
Sample() : m_sampleTime(), m_recordCount(0)
|
||||
{
|
||||
|
@ -509,23 +584,26 @@ namespace llarp
|
|||
void sampleTime(const absl::Time& time) { m_sampleTime = time; }
|
||||
absl::Time sampleTime() const { return m_sampleTime; }
|
||||
|
||||
void pushGroup(const SampleGroup& group) {
|
||||
template<typename Type>
|
||||
void pushGroup(const SampleGroup<Type>& group) {
|
||||
if (!group.empty()) {
|
||||
m_samples.push_back(group);
|
||||
m_samples.emplace_back(group);
|
||||
m_recordCount += group.size();
|
||||
}
|
||||
}
|
||||
|
||||
void pushGroup(const Record *records, size_t size, absl::Duration duration) {
|
||||
template<typename Type>
|
||||
void pushGroup(const Record<Type> *records, size_t size, absl::Duration duration) {
|
||||
if (size != 0) {
|
||||
m_samples.emplace_back(records, size, duration);
|
||||
m_samples.emplace_back(SampleGroup<Type>(records, size, duration));
|
||||
m_recordCount += size;
|
||||
}
|
||||
}
|
||||
|
||||
void pushGroup(const absl::Span< const Record > &records,absl::Duration duration) {
|
||||
template<typename Type>
|
||||
void pushGroup(const absl::Span< const Record<Type> > &records,absl::Duration duration) {
|
||||
if (!records.empty()) {
|
||||
m_samples.emplace_back(records, duration);
|
||||
m_samples.emplace_back(SampleGroup<Type>(records, duration));
|
||||
m_recordCount += records.size();
|
||||
}
|
||||
}
|
||||
|
@ -535,7 +613,7 @@ namespace llarp
|
|||
m_recordCount = 0;
|
||||
}
|
||||
|
||||
const SampleGroup& group(size_t index) {
|
||||
const absl::variant<SampleGroup<double>, SampleGroup<int> >& group(size_t index) {
|
||||
assert(index < m_samples.size());
|
||||
return m_samples[index];
|
||||
}
|
||||
|
@ -547,6 +625,36 @@ namespace llarp
|
|||
size_t recordCount() const { return m_recordCount; }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
auto
|
||||
forSampleGroup(
|
||||
const absl::variant< SampleGroup< double >, SampleGroup< int > > &group,
|
||||
const T &func)
|
||||
-> decltype(func(std::declval< SampleGroup< double > >()))
|
||||
{
|
||||
return absl::visit(
|
||||
util::overloaded(
|
||||
[&](const SampleGroup< double > &d) { return func(d); },
|
||||
[&](const SampleGroup< int > &i) { return func(i); }),
|
||||
group);
|
||||
}
|
||||
|
||||
inline absl::Duration
|
||||
samplePeriod(
|
||||
const absl::variant< SampleGroup< double >, SampleGroup< int > > &group)
|
||||
{
|
||||
return forSampleGroup(group,
|
||||
[](const auto &x) { return x.samplePeriod(); });
|
||||
}
|
||||
|
||||
inline size_t
|
||||
sampleSize(
|
||||
const absl::variant< SampleGroup< double >, SampleGroup< int > > &group)
|
||||
{
|
||||
return forSampleGroup(group, [](const auto &x) { return x.size(); });
|
||||
}
|
||||
|
||||
} // namespace metrics
|
||||
} // namespace llarp
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include <util/variant.hpp>
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef LLARP_VARIANT_HPP
|
||||
#define LLARP_VARIANT_HPP
|
||||
|
||||
#include <absl/types/variant.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
template < typename... Ts >
|
||||
struct _overloaded;
|
||||
|
||||
template < typename T, typename... Ts >
|
||||
struct _overloaded<T, Ts...> : T, _overloaded<Ts...>
|
||||
{
|
||||
_overloaded(T&& t, Ts&&... ts) : T(t), _overloaded<Ts...>(std::forward<Ts>(ts)...) {}
|
||||
using T::operator();
|
||||
|
||||
using _overloaded< Ts... >::operator();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct _overloaded<T> : T
|
||||
{
|
||||
_overloaded(T&& t) : T(t) {}
|
||||
|
||||
using T::operator();
|
||||
};
|
||||
|
||||
template < typename... Ts >
|
||||
constexpr auto overloaded(Ts&&... ts)->_overloaded< Ts... >
|
||||
{
|
||||
return _overloaded<Ts...>(std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
|
@ -17,7 +17,7 @@ TEST(MetricsPublisher, StreamPublisher)
|
|||
std::stringstream stream;
|
||||
metrics::StreamPublisher myPublisher(stream);
|
||||
|
||||
std::vector< metrics::Record > records;
|
||||
std::vector< metrics::Record< double > > records;
|
||||
|
||||
records.emplace_back(metricA, 5, 25.0, 6.0, 25.0);
|
||||
records.emplace_back(metricB, 2, 7.0, 3.0, 11.0);
|
||||
|
|
|
@ -41,19 +41,19 @@ TYPED_TEST_P(CollectorTest, Collector)
|
|||
ASSERT_EQ(METRIC_A, collector1.id().description());
|
||||
ASSERT_EQ(METRIC_B, collector2.id().description());
|
||||
|
||||
Record record1 = collector1.load();
|
||||
typename TypeParam::RecordType record1 = collector1.load();
|
||||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(0, record1.count());
|
||||
ASSERT_EQ(0, record1.total());
|
||||
ASSERT_EQ(Record::DEFAULT_MAX, record1.max());
|
||||
ASSERT_EQ(Record::DEFAULT_MIN, record1.min());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
|
||||
|
||||
Record record2 = collector2.load();
|
||||
typename TypeParam::RecordType record2 = collector2.load();
|
||||
ASSERT_EQ(METRIC_B, record2.id().description());
|
||||
ASSERT_EQ(0, record2.count());
|
||||
ASSERT_EQ(0, record2.total());
|
||||
ASSERT_EQ(Record::DEFAULT_MIN, record2.min());
|
||||
ASSERT_EQ(Record::DEFAULT_MAX, record2.max());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record2.min());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record2.max());
|
||||
|
||||
collector1.tick(1);
|
||||
record1 = collector1.load();
|
||||
|
@ -84,8 +84,8 @@ TYPED_TEST_P(CollectorTest, Collector)
|
|||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(0, record1.count());
|
||||
ASSERT_EQ(0, record1.total());
|
||||
ASSERT_EQ(Record::DEFAULT_MIN, record1.min());
|
||||
ASSERT_EQ(Record::DEFAULT_MAX, record1.max());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
|
||||
|
||||
collector1.tick(3);
|
||||
record1 = collector1.loadAndClear();
|
||||
|
@ -99,8 +99,8 @@ TYPED_TEST_P(CollectorTest, Collector)
|
|||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(0, record1.count());
|
||||
ASSERT_EQ(0, record1.total());
|
||||
ASSERT_EQ(Record::DEFAULT_MIN, record1.min());
|
||||
ASSERT_EQ(Record::DEFAULT_MAX, record1.max());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(CollectorTest, Collector);
|
||||
|
@ -311,35 +311,27 @@ MATCHER_P5(RecordCatEq, category, count, total, min, max, "")
|
|||
TEST(MetricsCore, RepoBasic)
|
||||
{
|
||||
Registry registry;
|
||||
CollectorRepo repo(®istry);
|
||||
CollectorRepo< double > repo(®istry);
|
||||
|
||||
DoubleCollector *collector1 = repo.defaultDoubleCollector("Test", "C1");
|
||||
DoubleCollector *collector2 = repo.defaultDoubleCollector("Test", "C2");
|
||||
IntCollector *intCollector1 = repo.defaultIntCollector("Test", "C3");
|
||||
IntCollector *intCollector2 = repo.defaultIntCollector("Test", "C4");
|
||||
DoubleCollector *collector1 = repo.defaultCollector("Test", "C1");
|
||||
DoubleCollector *collector2 = repo.defaultCollector("Test", "C2");
|
||||
|
||||
ASSERT_NE(collector1, collector2);
|
||||
ASSERT_EQ(collector1, repo.defaultDoubleCollector("Test", "C1"));
|
||||
ASSERT_NE(intCollector1, intCollector2);
|
||||
ASSERT_EQ(intCollector1, repo.defaultIntCollector("Test", "C3"));
|
||||
ASSERT_EQ(collector1, repo.defaultCollector("Test", "C1"));
|
||||
|
||||
collector1->tick(1.0);
|
||||
collector1->tick(2.0);
|
||||
collector2->tick(4.0);
|
||||
|
||||
intCollector1->tick(5);
|
||||
intCollector2->tick(6);
|
||||
|
||||
std::vector< Record > records = repo.collectAndClear(registry.get("Test"));
|
||||
ASSERT_THAT(records, SizeIs(4));
|
||||
std::vector< Record< double > > records =
|
||||
repo.collectAndClear(registry.get("Test"));
|
||||
EXPECT_THAT(records, SizeIs(2));
|
||||
// clang-format off
|
||||
ASSERT_THAT(
|
||||
EXPECT_THAT(
|
||||
records,
|
||||
ElementsAre(
|
||||
RecordEq("Test", "C1", 2u, 3, 1, 2),
|
||||
RecordEq("Test", "C2", 1u, 4, 4, 4),
|
||||
RecordEq("Test", "C3", 1u, 5, 5, 5),
|
||||
RecordEq("Test", "C4", 1u, 6, 6, 6)
|
||||
RecordEq("Test", "C2", 1u, 4, 4, 4)
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
|
@ -359,7 +351,7 @@ TEST(MetricsCore, RepoCollect)
|
|||
|
||||
for(int i = 0; i < static_cast< int >(CATEGORIES.size()); ++i)
|
||||
{
|
||||
CollectorRepo repo(®istry);
|
||||
CollectorRepo< int > repo(®istry);
|
||||
|
||||
for(int j = 0; j < static_cast< int >(CATEGORIES.size()); ++j)
|
||||
{
|
||||
|
@ -369,16 +361,13 @@ TEST(MetricsCore, RepoCollect)
|
|||
Id metric = registry.get(CATEGORY, METRICS[k]);
|
||||
for(int l = 0; l < NUM_COLS; ++l)
|
||||
{
|
||||
DoubleCollector *dCol = repo.addDoubleCollector(metric).get();
|
||||
IntCollector *iCol = repo.addIntCollector(metric).get();
|
||||
IntCollector *iCol = repo.addCollector(metric).get();
|
||||
if(i == j)
|
||||
{
|
||||
dCol->set(k, 2 * k, -k, k);
|
||||
iCol->set(k, 2 * k, -k, k);
|
||||
}
|
||||
else
|
||||
{
|
||||
dCol->set(100, 100, 100, 100);
|
||||
iCol->set(100, 100, 100, 100);
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +379,7 @@ TEST(MetricsCore, RepoCollect)
|
|||
const char *CATEGORY = CATEGORIES[i];
|
||||
const Category *category = registry.get(CATEGORY);
|
||||
|
||||
std::vector< Record > records = repo.collect(category);
|
||||
std::vector< Record< int > > records = repo.collect(category);
|
||||
|
||||
ASSERT_THAT(records, SizeIs(static_cast< int >(METRICS.size())));
|
||||
// clang-format off
|
||||
|
@ -398,8 +387,8 @@ TEST(MetricsCore, RepoCollect)
|
|||
records,
|
||||
UnorderedElementsAre(
|
||||
RecordEq(CATEGORY, "A", 0u, 0, 0, 0),
|
||||
RecordEq(CATEGORY, "B", 6u, 12, -1, 1),
|
||||
RecordEq(CATEGORY, "C", 12u, 24, -2, 2)
|
||||
RecordEq(CATEGORY, "B", 3u, 6, -1, 1),
|
||||
RecordEq(CATEGORY, "C", 6u, 12, -2, 2)
|
||||
)
|
||||
);
|
||||
// clang-format on
|
||||
|
@ -409,16 +398,12 @@ TEST(MetricsCore, RepoCollect)
|
|||
{
|
||||
Id metric = registry.get(CATEGORY, METRICS[j]);
|
||||
|
||||
auto collectors = repo.allCollectors(metric);
|
||||
const auto &doubleCols = collectors.first;
|
||||
const auto &intCols = collectors.second;
|
||||
for(int k = 0; k < static_cast< int >(doubleCols.size()); ++k)
|
||||
auto collectors = repo.allCollectors(metric);
|
||||
for(int k = 0; k < static_cast< int >(collectors.size()); ++k)
|
||||
{
|
||||
Record E(metric, j, 2 * j, -j, j);
|
||||
Record record1 = doubleCols[k]->load();
|
||||
Record record2 = intCols[k]->load();
|
||||
ASSERT_EQ(record1, E);
|
||||
ASSERT_EQ(record2, E);
|
||||
Record< int > EI(metric, j, 2 * j, -j, j);
|
||||
Record< int > record = collectors[k]->load();
|
||||
ASSERT_EQ(record, EI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -434,17 +419,13 @@ TEST(MetricsCore, RepoCollect)
|
|||
|
||||
for(int k = 0; k < static_cast< int >(METRICS.size()); ++k)
|
||||
{
|
||||
Id metric = registry.get(CATEGORY, METRICS[j]);
|
||||
auto collectors = repo.allCollectors(metric);
|
||||
const auto &doubleCols = collectors.first;
|
||||
const auto &intCols = collectors.second;
|
||||
Id metric = registry.get(CATEGORY, METRICS[j]);
|
||||
auto collectors = repo.allCollectors(metric);
|
||||
|
||||
for(int l = 0; l < static_cast< int >(doubleCols.size()); ++l)
|
||||
for(int l = 0; l < static_cast< int >(collectors.size()); ++l)
|
||||
{
|
||||
Record record1 = doubleCols[k]->load();
|
||||
ASSERT_THAT(record1, RecordEq(metric, 100u, 100, 100, 100));
|
||||
Record record2 = intCols[k]->load();
|
||||
ASSERT_THAT(record2, RecordEq(metric, 100u, 100, 100, 100));
|
||||
Record< int > record = collectors[k]->load();
|
||||
ASSERT_THAT(record, RecordEq(metric, 100u, 100, 100, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,16 +441,18 @@ MATCHER_P2(WithinWindow, expectedTime, window, "")
|
|||
}
|
||||
|
||||
const Category *
|
||||
firstCategory(const SampleGroup &group)
|
||||
firstCategory(
|
||||
const absl::variant< SampleGroup< double >, SampleGroup< int > > &g)
|
||||
{
|
||||
EXPECT_THAT(group, Not(IsEmpty()));
|
||||
const Category *value = group.begin()->id().category();
|
||||
for(const Record &record : group.records())
|
||||
{
|
||||
EXPECT_EQ(value, record.id().category());
|
||||
}
|
||||
|
||||
return value;
|
||||
return forSampleGroup(g, [](const auto &group) {
|
||||
EXPECT_THAT(group, Not(IsEmpty()));
|
||||
const Category *value = group.begin()->id().category();
|
||||
for(const auto &record : group.records())
|
||||
{
|
||||
EXPECT_EQ(value, record.id().category());
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
TEST(MetricsCore, ManagerCollectSample1)
|
||||
|
@ -481,39 +464,40 @@ TEST(MetricsCore, ManagerCollectSample1)
|
|||
const int NUM_METRICS = sizeof(METRICS) / sizeof(*METRICS);
|
||||
|
||||
Manager manager;
|
||||
CollectorRepo &rep = manager.collectorRepo();
|
||||
CollectorRepo< double > &rep = manager.doubleCollectorRepo();
|
||||
|
||||
for(int i = 0; i < NUM_CATEGORIES; ++i)
|
||||
{
|
||||
for(int j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j])->tick(1);
|
||||
rep.defaultCollector(CATEGORIES[i], METRICS[j])->tick(1);
|
||||
}
|
||||
}
|
||||
|
||||
absl::Time start = absl::Now();
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(100000));
|
||||
|
||||
std::vector< Record > records;
|
||||
Records records;
|
||||
Sample sample = manager.collectSample(records, false);
|
||||
|
||||
absl::Duration window = absl::Now() - start;
|
||||
absl::Time now = absl::Now();
|
||||
ASSERT_EQ(NUM_CATEGORIES * NUM_METRICS, records.size());
|
||||
ASSERT_EQ(NUM_CATEGORIES * NUM_METRICS, records.doubleRecords.size());
|
||||
ASSERT_EQ(NUM_CATEGORIES * NUM_METRICS, sample.recordCount());
|
||||
ASSERT_EQ(NUM_CATEGORIES, sample.groupCount());
|
||||
ASSERT_THAT(sample.sampleTime(), WithinWindow(now, absl::Milliseconds(10)));
|
||||
|
||||
for(size_t i = 0; i < sample.groupCount(); ++i)
|
||||
{
|
||||
const SampleGroup &group = sample.group(i);
|
||||
const SampleGroup< double > &group =
|
||||
absl::get< SampleGroup< double > >(sample.group(i));
|
||||
ASSERT_EQ(NUM_METRICS, group.size());
|
||||
ASSERT_THAT(group.samplePeriod(),
|
||||
WithinWindow(window, absl::Milliseconds(10)))
|
||||
<< group;
|
||||
|
||||
const char *name = group.records()[0].id().categoryName();
|
||||
for(const Record &record : group.records())
|
||||
for(const Record< double > &record : group.records())
|
||||
{
|
||||
ASSERT_THAT(record, RecordCatEq(name, 1u, 1, 1, 1));
|
||||
}
|
||||
|
@ -522,17 +506,17 @@ TEST(MetricsCore, ManagerCollectSample1)
|
|||
{
|
||||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col =
|
||||
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record record = col->load();
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
ASSERT_THAT(record, RecordEq(1u, 1, 1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
records.clear();
|
||||
records.doubleRecords.clear();
|
||||
records.intRecords.clear();
|
||||
sample = manager.collectSample(records, true);
|
||||
|
||||
ASSERT_EQ(NUM_CATEGORIES * NUM_METRICS, records.size());
|
||||
ASSERT_EQ(NUM_CATEGORIES * NUM_METRICS, records.doubleRecords.size());
|
||||
ASSERT_EQ(NUM_CATEGORIES * NUM_METRICS, sample.recordCount());
|
||||
ASSERT_EQ(NUM_CATEGORIES, sample.groupCount());
|
||||
|
||||
|
@ -540,10 +524,9 @@ TEST(MetricsCore, ManagerCollectSample1)
|
|||
{
|
||||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col =
|
||||
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record record = col->load();
|
||||
ASSERT_EQ(Record(record.id()), record);
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
ASSERT_EQ(Record< double >(record.id()), record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -559,8 +542,8 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
Manager manager;
|
||||
std::vector< const Category * > allCategories;
|
||||
|
||||
CollectorRepo &rep = manager.collectorRepo();
|
||||
Registry ® = manager.registry();
|
||||
CollectorRepo< double > &rep = manager.doubleCollectorRepo();
|
||||
Registry ® = manager.registry();
|
||||
for(size_t i = 0; i < NUM_CATEGORIES; ++i)
|
||||
{
|
||||
const Category *cat = reg.get(CATEGORIES[i]);
|
||||
|
@ -575,8 +558,7 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
{
|
||||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col =
|
||||
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
col->clear();
|
||||
col->tick(1);
|
||||
}
|
||||
|
@ -584,7 +566,7 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
|
||||
// Test without a reset.
|
||||
std::vector< const Category * > cats = combIt.currentCombo;
|
||||
std::vector< Record > records;
|
||||
Records records;
|
||||
Sample sample = manager.collectSample(
|
||||
records, absl::Span< const Category * >{cats}, false);
|
||||
|
||||
|
@ -608,13 +590,12 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
{
|
||||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col =
|
||||
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record record = col->load();
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
ASSERT_THAT(record, RecordEq(1u, 1, 1, 1));
|
||||
}
|
||||
}
|
||||
std::vector< Record > records2;
|
||||
Records records2;
|
||||
|
||||
// Test with a reset.
|
||||
sample = manager.collectSample(records2,
|
||||
|
@ -641,12 +622,11 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
{
|
||||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col =
|
||||
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record record = col->load();
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
if(combIt.includesElement(i))
|
||||
{
|
||||
ASSERT_EQ(Record(record.id()), record);
|
||||
ASSERT_EQ(Record< double >(record.id()), record);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -661,8 +641,8 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
struct MockPublisher : public Publisher
|
||||
{
|
||||
std::atomic_int invocations;
|
||||
std::vector< Record > recordBuffer;
|
||||
std::vector< Record > sortedRecords;
|
||||
std::vector< Record< double > > recordBuffer;
|
||||
std::vector< Record< double > > sortedRecords;
|
||||
Sample m_sample;
|
||||
|
||||
std::set< absl::Duration > times;
|
||||
|
@ -686,17 +666,19 @@ struct MockPublisher : public Publisher
|
|||
|
||||
recordBuffer.reserve(sample.recordCount());
|
||||
|
||||
for(const auto &s : sample)
|
||||
for(const auto &_s : sample)
|
||||
{
|
||||
auto git = s.begin();
|
||||
ASSERT_TRUE(absl::holds_alternative< SampleGroup< double > >(_s));
|
||||
const auto &s = absl::get< SampleGroup< double > >(_s);
|
||||
auto git = s.begin();
|
||||
ASSERT_NE(git, s.end());
|
||||
recordBuffer.push_back(*git);
|
||||
Record *head = &recordBuffer.back();
|
||||
Record< double > *head = &recordBuffer.back();
|
||||
for(++git; git != s.end(); ++git)
|
||||
{
|
||||
recordBuffer.push_back(*git);
|
||||
}
|
||||
m_sample.pushGroup(head, s.size(), s.samplePeriod());
|
||||
m_sample.pushGroup(head, s.size(), samplePeriod(s));
|
||||
times.insert(s.samplePeriod());
|
||||
}
|
||||
|
||||
|
@ -719,7 +701,7 @@ struct MockPublisher : public Publisher
|
|||
int
|
||||
indexOf(const Id &id)
|
||||
{
|
||||
Record searchRecord(id);
|
||||
Record< double > searchRecord(id);
|
||||
auto it = std::lower_bound(
|
||||
sortedRecords.begin(), sortedRecords.end(), searchRecord,
|
||||
[](const auto &lhs, const auto &rhs) { return lhs.id() < rhs.id(); });
|
||||
|
@ -820,8 +802,8 @@ TEST(MetricsCore, PublishAll)
|
|||
const int NUM_METRICS = sizeof(METRICS) / sizeof(*METRICS);
|
||||
|
||||
Manager manager;
|
||||
Registry ®istry = manager.registry();
|
||||
CollectorRepo &repository = manager.collectorRepo();
|
||||
Registry ®istry = manager.registry();
|
||||
CollectorRepo< double > &repository = manager.doubleCollectorRepo();
|
||||
|
||||
auto globalPub = std::make_shared< MockPublisher >();
|
||||
|
||||
|
@ -844,7 +826,7 @@ TEST(MetricsCore, PublishAll)
|
|||
for(int j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col =
|
||||
repository.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
|
||||
repository.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
col->clear();
|
||||
col->tick(1);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
using namespace llarp;
|
||||
using namespace ::testing;
|
||||
|
||||
using RecordT = metrics::Record< double >;
|
||||
using SampleGroupT = metrics::SampleGroup< double >;
|
||||
|
||||
struct MetricFormatSpecTestData
|
||||
{
|
||||
float m_scale;
|
||||
|
@ -130,7 +133,7 @@ TEST(MetricsTypes, CatContainer)
|
|||
|
||||
TEST(MetricsTypes, Record)
|
||||
{
|
||||
metrics::Record r;
|
||||
RecordT r;
|
||||
ASSERT_GT(r.min(), r.max());
|
||||
}
|
||||
|
||||
|
@ -146,12 +149,12 @@ TEST(MetricsTypes, Sample)
|
|||
metrics::Id metricC(&descC);
|
||||
|
||||
absl::Time timeStamp = absl::Now();
|
||||
metrics::Record recordA(metricA, 0, 0, 0, 0);
|
||||
metrics::Record recordB(metricB, 1, 2, 3, 4);
|
||||
metrics::Record recordC(metricC, 4, 3, 2, 1);
|
||||
RecordT recordA(metricA, 0, 0, 0, 0);
|
||||
RecordT recordB(metricB, 1, 2, 3, 4);
|
||||
RecordT recordC(metricC, 4, 3, 2, 1);
|
||||
|
||||
metrics::Record buffer1[] = {recordA, recordB};
|
||||
std::vector< metrics::Record > buffer2;
|
||||
RecordT buffer1[] = {recordA, recordB};
|
||||
std::vector< RecordT > buffer2;
|
||||
buffer2.push_back(recordC);
|
||||
|
||||
metrics::Sample sample;
|
||||
|
@ -163,17 +166,23 @@ TEST(MetricsTypes, Sample)
|
|||
ASSERT_EQ(timeStamp, sample.sampleTime());
|
||||
ASSERT_EQ(2u, sample.groupCount());
|
||||
ASSERT_EQ(3u, sample.recordCount());
|
||||
ASSERT_EQ(absl::Seconds(1), sample.group(0).samplePeriod());
|
||||
ASSERT_EQ(buffer1, sample.group(0).records().data());
|
||||
ASSERT_EQ(2, sample.group(0).size());
|
||||
ASSERT_EQ(absl::Seconds(2), sample.group(1).samplePeriod());
|
||||
ASSERT_EQ(buffer2.data(), sample.group(1).records().data());
|
||||
ASSERT_EQ(1, sample.group(1).size());
|
||||
ASSERT_TRUE(absl::holds_alternative< SampleGroupT >(sample.group(0)));
|
||||
ASSERT_TRUE(absl::holds_alternative< SampleGroupT >(sample.group(1)));
|
||||
|
||||
const SampleGroupT s0 = absl::get< SampleGroupT >(sample.group(0));
|
||||
const SampleGroupT s1 = absl::get< SampleGroupT >(sample.group(1));
|
||||
ASSERT_EQ(absl::Seconds(1), s0.samplePeriod());
|
||||
ASSERT_EQ(buffer1, s0.records().data());
|
||||
ASSERT_EQ(2, s0.size());
|
||||
|
||||
ASSERT_EQ(absl::Seconds(2), s1.samplePeriod());
|
||||
ASSERT_EQ(buffer2.data(), s1.records().data());
|
||||
ASSERT_EQ(1, s1.size());
|
||||
|
||||
for(auto sampleIt = sample.begin(); sampleIt != sample.end(); ++sampleIt)
|
||||
{
|
||||
;
|
||||
for(auto groupIt = sampleIt->begin(); groupIt != sampleIt->end(); ++groupIt)
|
||||
const auto &s = absl::get< SampleGroupT >(*sampleIt);
|
||||
for(auto groupIt = s.begin(); groupIt != s.end(); ++groupIt)
|
||||
{
|
||||
std::cout << *groupIt << std::endl;
|
||||
}
|
||||
|
@ -200,7 +209,7 @@ struct SampleTest
|
|||
metrics::Id id_F;
|
||||
metrics::Id id_G;
|
||||
|
||||
std::vector< metrics::Record > recordBuffer;
|
||||
std::vector< RecordT > recordBuffer;
|
||||
|
||||
SampleTest()
|
||||
: cat_A("A", true)
|
||||
|
@ -231,17 +240,17 @@ struct SampleTest
|
|||
}
|
||||
};
|
||||
|
||||
std::pair< std::vector< metrics::SampleGroup >, size_t >
|
||||
std::pair< std::vector< metrics::SampleGroup< double > >, size_t >
|
||||
generate(const std::string &specification,
|
||||
const std::vector< metrics::Record > &recordBuffer)
|
||||
const std::vector< RecordT > &recordBuffer)
|
||||
{
|
||||
const char *c = specification.c_str();
|
||||
|
||||
std::vector< metrics::SampleGroup > groups;
|
||||
std::vector< metrics::SampleGroup< double > > groups;
|
||||
size_t size = 0;
|
||||
|
||||
const metrics::Record *head = recordBuffer.data();
|
||||
const metrics::Record *current = head;
|
||||
const RecordT *head = recordBuffer.data();
|
||||
const RecordT *current = head;
|
||||
while(*c)
|
||||
{
|
||||
int numRecords = *(c + 1) - '0';
|
||||
|
@ -268,7 +277,7 @@ TEST_P(SampleTest, basics)
|
|||
|
||||
std::tie(timestamp, spec) = GetParam();
|
||||
|
||||
std::vector< metrics::SampleGroup > groups;
|
||||
std::vector< metrics::SampleGroup< double > > groups;
|
||||
size_t size;
|
||||
std::tie(groups, size) = generate(spec, recordBuffer);
|
||||
|
||||
|
@ -286,7 +295,8 @@ TEST_P(SampleTest, basics)
|
|||
ASSERT_EQ(size, sample.recordCount());
|
||||
for(size_t j = 0; j < sample.groupCount(); ++j)
|
||||
{
|
||||
ASSERT_EQ(groups[j], sample.group(j));
|
||||
ASSERT_EQ(groups[j],
|
||||
absl::get< metrics::SampleGroup< double > >(sample.group(j)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,7 +307,7 @@ TEST_P(SampleTest, append)
|
|||
|
||||
std::tie(timestamp, spec) = GetParam();
|
||||
|
||||
std::vector< metrics::SampleGroup > groups;
|
||||
std::vector< metrics::SampleGroup< double > > groups;
|
||||
size_t size;
|
||||
std::tie(groups, size) = generate(spec, recordBuffer);
|
||||
|
||||
|
@ -316,7 +326,8 @@ TEST_P(SampleTest, append)
|
|||
|
||||
for(size_t j = 0; j < sample.groupCount(); ++j)
|
||||
{
|
||||
ASSERT_EQ(groups[j], sample.group(j));
|
||||
ASSERT_EQ(groups[j],
|
||||
absl::get< metrics::SampleGroup< double > >(sample.group(j)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue