mirror of https://github.com/oxen-io/lokinet
Merge remote-tracking branch 'origin/master' into ipv6-tun
This commit is contained in:
commit
227f561ffc
|
@ -18,11 +18,13 @@ set(LIB_UTIL_SRC
|
|||
util/android_logger.cpp
|
||||
util/file_logger.cpp
|
||||
util/logic.cpp
|
||||
util/loglevel.cpp
|
||||
util/mem.cpp
|
||||
util/memfn_traits.cpp
|
||||
util/memfn.cpp
|
||||
util/metrics_core.cpp
|
||||
util/metrics_types.cpp
|
||||
util/json_logger.cpp
|
||||
util/ostream_logger.cpp
|
||||
util/syslog_logger.cpp
|
||||
util/win32_logger.cpp
|
||||
|
@ -49,7 +51,7 @@ set(LIB_UTIL_SRC
|
|||
|
||||
add_library(${UTIL_LIB} STATIC ${LIB_UTIL_SRC})
|
||||
target_include_directories(${UTIL_LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include)
|
||||
target_link_libraries_system(${UTIL_LIB} absl::synchronization absl::hash nlohmann_json::nlohmann_json)
|
||||
target_link_libraries_system(${UTIL_LIB} absl::synchronization absl::hash absl::container nlohmann_json::nlohmann_json)
|
||||
|
||||
# cut back on fluff
|
||||
if (NOT WIN32)
|
||||
|
|
|
@ -77,7 +77,8 @@ namespace llarp
|
|||
|
||||
std::for_each(logging.begin(), logging.end(),
|
||||
std::bind(visitor, "logging", _1));
|
||||
|
||||
// end of logging section commit settings and go
|
||||
functor("logging", "", "");
|
||||
std::for_each(lokid.begin(), lokid.end(), std::bind(visitor, "lokid", _1));
|
||||
std::for_each(router.begin(), router.end(),
|
||||
std::bind(visitor, "router", _1));
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#include <algorithm> // for std::find_if
|
||||
#include <stdio.h> // sprintf
|
||||
|
||||
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||
|
||||
dns_tracker dns_udp_tracker;
|
||||
|
||||
/*
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace llarp
|
|||
, m_Resolver(std::make_shared< dns::Proxy >(
|
||||
r->netloop(), r->logic(), r->netloop(), r->logic(), this))
|
||||
, m_Name(name)
|
||||
, m_Tun{{0}, 0, {0}, 0, 0, 0, 0, 0, 0, 0}
|
||||
, m_Tun{{0}, 0, {0}, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
, m_LocalResolverAddr("127.0.0.1", 53)
|
||||
, m_InetToNetwork(name + "_exit_rx", r->netloop(), r->netloop())
|
||||
|
||||
|
|
|
@ -95,8 +95,8 @@ namespace llarp
|
|||
|
||||
if(!isLIM)
|
||||
{
|
||||
const std::string host = "RX_" + RouterID(from->GetPubKey()).ToString();
|
||||
METRICS_DYNAMIC_INCREMENT(msg->Name(), host.c_str());
|
||||
metrics::integerTick(msg->Name(), "RX", 1, "id",
|
||||
RouterID(from->GetPubKey()).ToString());
|
||||
}
|
||||
|
||||
msg->session = from;
|
||||
|
|
|
@ -110,50 +110,88 @@ namespace llarp
|
|||
}
|
||||
|
||||
std::string
|
||||
addName(string_view id, string_view name, string_view suffix)
|
||||
makeTagStr(const Tags &tags)
|
||||
{
|
||||
return absl::StrCat(id, ".", name, suffix);
|
||||
std::string tagStr;
|
||||
|
||||
auto overloaded = util::overloaded(
|
||||
[](const std::string &str) { return str; },
|
||||
[](double d) { return std::to_string(d); },
|
||||
[](const std::int64_t i) { return std::to_string(i); });
|
||||
|
||||
for(const auto &tag : tags)
|
||||
{
|
||||
absl::StrAppend(&tagStr, ";", tag.first, "=",
|
||||
absl::visit(overloaded, tag.second));
|
||||
}
|
||||
return tagStr;
|
||||
}
|
||||
|
||||
std::string
|
||||
addName(string_view id, string_view name, const Tags &tags,
|
||||
string_view suffix)
|
||||
{
|
||||
return absl::StrCat(id, ".", name, makeTagStr(tags), suffix);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
isValid(int val)
|
||||
{
|
||||
return val != std::numeric_limits< int >::min()
|
||||
&& val != std::numeric_limits< int >::max();
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
isValid(double val)
|
||||
{
|
||||
return Record< double >::DEFAULT_MIN() != val
|
||||
&& Record< double >::DEFAULT_MAX() != val && !std::isnan(val)
|
||||
&& !std::isinf(val);
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
std::vector< MetricTankPublisherInterface::PublishData >
|
||||
recordToData(const Record< Value > &record, absl::Time time,
|
||||
recordToData(const TaggedRecords< Value > &taggedRecords, absl::Time time,
|
||||
double elapsedTime, string_view suffix)
|
||||
{
|
||||
std::vector< MetricTankPublisherInterface::PublishData > result;
|
||||
|
||||
std::string id = record.id().toString();
|
||||
std::string id = taggedRecords.id.toString();
|
||||
|
||||
auto publicationType = record.id().description()->type();
|
||||
if(publicationType != Publication::Type::Unspecified)
|
||||
auto publicationType = taggedRecords.id.description()->type();
|
||||
|
||||
for(const auto &record : taggedRecords.data)
|
||||
{
|
||||
auto val = formatValue(record, elapsedTime, publicationType);
|
||||
const auto &tags = record.first;
|
||||
const auto &rec = record.second;
|
||||
if(publicationType != Publication::Type::Unspecified)
|
||||
{
|
||||
auto val = formatValue(rec, elapsedTime, publicationType);
|
||||
|
||||
if(val)
|
||||
{
|
||||
result.emplace_back(
|
||||
addName(id, Publication::repr(publicationType), suffix),
|
||||
val.value(), time);
|
||||
if(val)
|
||||
{
|
||||
result.emplace_back(
|
||||
addName(id, Publication::repr(publicationType), tags, suffix),
|
||||
val.value(), time);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.emplace_back(addName(id, "count", suffix),
|
||||
std::to_string(record.count()), time);
|
||||
result.emplace_back(addName(id, "total", suffix),
|
||||
std::to_string(record.total()), time);
|
||||
else
|
||||
{
|
||||
result.emplace_back(addName(id, "count", tags, suffix),
|
||||
std::to_string(rec.count()), time);
|
||||
result.emplace_back(addName(id, "total", tags, suffix),
|
||||
std::to_string(rec.total()), time);
|
||||
|
||||
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< 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);
|
||||
if(isValid(rec.min()))
|
||||
{
|
||||
result.emplace_back(addName(id, "min", tags, suffix),
|
||||
std::to_string(rec.min()), time);
|
||||
}
|
||||
if(isValid(rec.max()))
|
||||
{
|
||||
result.emplace_back(addName(id, "max", tags, suffix),
|
||||
std::to_string(rec.max()), time);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -325,12 +363,7 @@ namespace llarp
|
|||
std::string
|
||||
MetricTankPublisherInterface::makeSuffix(const Tags &tags)
|
||||
{
|
||||
std::string result;
|
||||
for(const auto &tag : updateTags(tags))
|
||||
{
|
||||
absl::StrAppend(&result, ";", tag.first, "=", tag.second);
|
||||
}
|
||||
return result;
|
||||
return absl::StrJoin(updateTags(tags), ";", absl::PairFormatter("="));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -353,14 +386,16 @@ namespace llarp
|
|||
{
|
||||
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());
|
||||
}
|
||||
});
|
||||
absl::visit(
|
||||
[&](const auto &d) {
|
||||
for(const auto &record : d)
|
||||
{
|
||||
auto partial =
|
||||
recordToData(record, sampleTime, elapsedTime, m_suffix);
|
||||
result.insert(result.end(), partial.begin(), partial.end());
|
||||
}
|
||||
},
|
||||
*gIt);
|
||||
|
||||
prev = gIt;
|
||||
}
|
||||
|
|
|
@ -78,66 +78,100 @@ namespace llarp
|
|||
|
||||
template < typename Value >
|
||||
void
|
||||
publishRecord(std::ostream &stream, const Record< Value > &record,
|
||||
publishRecord(std::ostream &stream,
|
||||
const TaggedRecords< Value > &taggedRecords,
|
||||
double elapsedTime)
|
||||
{
|
||||
auto publicationType = record.id().description()->type();
|
||||
auto publicationType = taggedRecords.id.description()->type();
|
||||
std::shared_ptr< const Format > format =
|
||||
record.id().description()->format();
|
||||
taggedRecords.id.description()->format();
|
||||
|
||||
stream << "\t\t" << record.id() << " [ ";
|
||||
|
||||
if(publicationType != Publication::Type::Unspecified)
|
||||
if(taggedRecords.data.empty())
|
||||
{
|
||||
stream << Publication::repr(publicationType) << " = ";
|
||||
const FormatSpec *formatSpec =
|
||||
format ? format->specFor(publicationType) : nullptr;
|
||||
|
||||
formatValue(stream, record, elapsedTime, publicationType, formatSpec);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const FormatSpec *countSpec = nullptr;
|
||||
const FormatSpec *totalSpec = nullptr;
|
||||
const FormatSpec *minSpec = nullptr;
|
||||
const FormatSpec *maxSpec = nullptr;
|
||||
|
||||
if(format)
|
||||
stream << "\t\t" << taggedRecords.id << " [";
|
||||
|
||||
for(const auto &rec : taggedRecords.data)
|
||||
{
|
||||
stream << "\n\t\t\t";
|
||||
const auto &tags = rec.first;
|
||||
const auto &record = rec.second;
|
||||
|
||||
{
|
||||
countSpec = format->specFor(Publication::Type::Count);
|
||||
totalSpec = format->specFor(Publication::Type::Total);
|
||||
minSpec = format->specFor(Publication::Type::Min);
|
||||
maxSpec = format->specFor(Publication::Type::Max);
|
||||
Printer printer(stream, -1, -1);
|
||||
printer.printValue(tags);
|
||||
}
|
||||
stream << "count = ";
|
||||
formatValue(stream, record.count(), countSpec);
|
||||
stream << ", total = ";
|
||||
formatValue(stream, record.total(), totalSpec);
|
||||
if(Record< Value >::DEFAULT_MIN() == record.min())
|
||||
|
||||
stream << " ";
|
||||
|
||||
if(publicationType != Publication::Type::Unspecified)
|
||||
{
|
||||
stream << ", min = undefined";
|
||||
stream << Publication::repr(publicationType) << " = ";
|
||||
const FormatSpec *formatSpec =
|
||||
format ? format->specFor(publicationType) : nullptr;
|
||||
|
||||
formatValue(stream, record, elapsedTime, publicationType,
|
||||
formatSpec);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << ", min = ";
|
||||
formatValue(stream, record.min(), minSpec);
|
||||
}
|
||||
if(Record< Value >::DEFAULT_MAX() == record.max())
|
||||
{
|
||||
stream << ", max = undefined";
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << ", max = ";
|
||||
formatValue(stream, record.max(), maxSpec);
|
||||
const FormatSpec *countSpec = nullptr;
|
||||
const FormatSpec *totalSpec = nullptr;
|
||||
const FormatSpec *minSpec = nullptr;
|
||||
const FormatSpec *maxSpec = nullptr;
|
||||
|
||||
if(format)
|
||||
{
|
||||
countSpec = format->specFor(Publication::Type::Count);
|
||||
totalSpec = format->specFor(Publication::Type::Total);
|
||||
minSpec = format->specFor(Publication::Type::Min);
|
||||
maxSpec = format->specFor(Publication::Type::Max);
|
||||
}
|
||||
stream << "count = ";
|
||||
formatValue(stream, record.count(), countSpec);
|
||||
stream << ", total = ";
|
||||
formatValue(stream, record.total(), totalSpec);
|
||||
if(Record< Value >::DEFAULT_MIN() == record.min())
|
||||
{
|
||||
stream << ", min = undefined";
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << ", min = ";
|
||||
formatValue(stream, record.min(), minSpec);
|
||||
}
|
||||
if(Record< Value >::DEFAULT_MAX() == record.max())
|
||||
{
|
||||
stream << ", max = undefined";
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << ", max = ";
|
||||
formatValue(stream, record.max(), maxSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
stream << " ]\n";
|
||||
stream << "\n\t\t]\n";
|
||||
}
|
||||
|
||||
nlohmann::json
|
||||
tagsToJson(const Tags &tags)
|
||||
{
|
||||
nlohmann::json result;
|
||||
|
||||
std::for_each(tags.begin(), tags.end(), [&](const auto &tag) {
|
||||
absl::visit([&](const auto &t) { result[tag.first] = t; },
|
||||
tag.second);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
void
|
||||
formatValue(nlohmann::json &result, const Record< Value > &record,
|
||||
nlohmann::json
|
||||
formatValue(const Record< Value > &record, const Tags &tags,
|
||||
double elapsedTime, Publication::Type publicationType)
|
||||
{
|
||||
switch(publicationType)
|
||||
|
@ -149,37 +183,40 @@ namespace llarp
|
|||
break;
|
||||
case Publication::Type::Total:
|
||||
{
|
||||
result["total"] = record.total();
|
||||
return {{"tags", tagsToJson(tags)}, {"total", record.total()}};
|
||||
}
|
||||
break;
|
||||
case Publication::Type::Count:
|
||||
{
|
||||
result["count"] = record.count();
|
||||
return {{"tags", tagsToJson(tags)}, {"count", record.count()}};
|
||||
}
|
||||
break;
|
||||
case Publication::Type::Min:
|
||||
{
|
||||
result["min"] = record.min();
|
||||
return {{"tags", tagsToJson(tags)}, {"min", record.min()}};
|
||||
}
|
||||
break;
|
||||
case Publication::Type::Max:
|
||||
{
|
||||
result["max"] = record.max();
|
||||
return {{"tags", tagsToJson(tags)}, {"max", record.max()}};
|
||||
}
|
||||
break;
|
||||
case Publication::Type::Avg:
|
||||
{
|
||||
result["avg"] = record.total() / record.count();
|
||||
return {{"tags", tagsToJson(tags)},
|
||||
{"avg", record.total() / record.count()}};
|
||||
}
|
||||
break;
|
||||
case Publication::Type::Rate:
|
||||
{
|
||||
result["rate"] = record.total() / elapsedTime;
|
||||
return {{"tags", tagsToJson(tags)},
|
||||
{"rate", record.total() / elapsedTime}};
|
||||
}
|
||||
break;
|
||||
case Publication::Type::RateCount:
|
||||
{
|
||||
result["rateCount"] = record.count() / elapsedTime;
|
||||
return {{"tags", tagsToJson(tags)},
|
||||
{"rateCount", record.count() / elapsedTime}};
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -187,30 +224,41 @@ namespace llarp
|
|||
|
||||
template < typename Value >
|
||||
nlohmann::json
|
||||
recordToJson(const Record< Value > &record, double elapsedTime)
|
||||
recordToJson(const TaggedRecords< Value > &taggedRecord,
|
||||
double elapsedTime)
|
||||
{
|
||||
nlohmann::json result;
|
||||
result["id"] = record.id().toString();
|
||||
result["id"] = taggedRecord.id.toString();
|
||||
|
||||
auto publicationType = record.id().description()->type();
|
||||
if(publicationType != Publication::Type::Unspecified)
|
||||
auto publicationType = taggedRecord.id.description()->type();
|
||||
|
||||
for(const auto &rec : taggedRecord.data)
|
||||
{
|
||||
result["publicationType"] = Publication::repr(publicationType);
|
||||
|
||||
formatValue(result, record, elapsedTime, publicationType);
|
||||
}
|
||||
else
|
||||
{
|
||||
result["count"] = record.count();
|
||||
result["total"] = record.total();
|
||||
|
||||
if(Record< Value >::DEFAULT_MIN() != record.min())
|
||||
const auto &record = rec.second;
|
||||
if(publicationType != Publication::Type::Unspecified)
|
||||
{
|
||||
result["min"] = record.min();
|
||||
result["publicationType"] = Publication::repr(publicationType);
|
||||
|
||||
result["metrics"].push_back(
|
||||
formatValue(record, rec.first, elapsedTime, publicationType));
|
||||
}
|
||||
if(Record< Value >::DEFAULT_MAX() == record.max())
|
||||
else
|
||||
{
|
||||
result["max"] = record.max();
|
||||
nlohmann::json tmp;
|
||||
tmp["tags"] = tagsToJson(rec.first);
|
||||
tmp["count"] = record.count();
|
||||
tmp["total"] = record.total();
|
||||
|
||||
if(Record< Value >::DEFAULT_MIN() != record.min())
|
||||
{
|
||||
tmp["min"] = record.min();
|
||||
}
|
||||
if(Record< Value >::DEFAULT_MAX() == record.max())
|
||||
{
|
||||
tmp["max"] = record.max();
|
||||
}
|
||||
|
||||
result["metrics"].push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,12 +289,14 @@ namespace llarp
|
|||
m_stream << "\tElapsed Time: " << elapsedTime << "s\n";
|
||||
}
|
||||
|
||||
forSampleGroup(*gIt, [&](const auto &x) {
|
||||
for(const auto &record : x)
|
||||
{
|
||||
publishRecord(m_stream, record, elapsedTime);
|
||||
}
|
||||
});
|
||||
absl::visit(
|
||||
[&](const auto &x) {
|
||||
for(const auto &record : x)
|
||||
{
|
||||
publishRecord(m_stream, record, elapsedTime);
|
||||
}
|
||||
},
|
||||
*gIt);
|
||||
|
||||
prev = gIt;
|
||||
}
|
||||
|
@ -275,12 +325,15 @@ namespace llarp
|
|||
result["elapsedTime"] = elapsedTime;
|
||||
}
|
||||
|
||||
forSampleGroup(*gIt, [&](const auto &x) {
|
||||
for(const auto &record : x)
|
||||
{
|
||||
result["record"].emplace_back(recordToJson(record, elapsedTime));
|
||||
}
|
||||
});
|
||||
absl::visit(
|
||||
[&](const auto &x) -> void {
|
||||
for(const auto &record : x)
|
||||
{
|
||||
result["record"].emplace_back(
|
||||
recordToJson(record, elapsedTime));
|
||||
}
|
||||
},
|
||||
*gIt);
|
||||
|
||||
prev = gIt;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <util/logger.hpp>
|
||||
#include <util/memfn.hpp>
|
||||
#include <util/file_logger.hpp>
|
||||
#include <util/json_logger.hpp>
|
||||
#include <util/logger_syslog.hpp>
|
||||
#include <util/metrics.hpp>
|
||||
#include <util/str.hpp>
|
||||
|
@ -923,6 +924,19 @@ namespace llarp
|
|||
}
|
||||
else if(StrEq(section, "logging"))
|
||||
{
|
||||
if(strlen(key) == 0 && strlen(val) == 0)
|
||||
{
|
||||
if(m_LogJSON)
|
||||
{
|
||||
LogContext::Instance().logStream = std::make_unique< JSONLogStream >(
|
||||
diskworker(), m_LogFile, 100, m_LogFile != stdout);
|
||||
}
|
||||
else if(m_LogFile != stdout)
|
||||
{
|
||||
LogContext::Instance().logStream = std::make_unique< FileLogStream >(
|
||||
diskworker(), m_LogFile, 100, true);
|
||||
}
|
||||
}
|
||||
if(StrEq(key, "type") && StrEq(val, "syslog"))
|
||||
{
|
||||
// TODO(despair): write event log syslog class
|
||||
|
@ -933,15 +947,18 @@ namespace llarp
|
|||
LogContext::Instance().logStream = std::make_unique< SysLogStream >();
|
||||
#endif
|
||||
}
|
||||
if(StrEq(key, "type") && StrEq(val, "json"))
|
||||
{
|
||||
m_LogJSON = true;
|
||||
}
|
||||
if(StrEq(key, "file"))
|
||||
{
|
||||
LogInfo("open log file: ", val);
|
||||
FILE *const logfile = ::fopen(val, "a");
|
||||
if(logfile)
|
||||
{
|
||||
LogContext::Instance().logStream =
|
||||
std::make_unique< FileLogStream >(diskworker(), logfile, 500);
|
||||
LogInfo("started logging to ", val);
|
||||
m_LogFile = logfile;
|
||||
LogInfo("will log to file ", val);
|
||||
}
|
||||
else if(errno)
|
||||
{
|
||||
|
@ -1376,15 +1393,14 @@ namespace llarp
|
|||
bool
|
||||
Router::Sign(Signature &sig, const llarp_buffer_t &buf) const
|
||||
{
|
||||
METRICS_TIME_BLOCK("Router", "Sign");
|
||||
metrics::TimerGuard t("Router", "Sign");
|
||||
return CryptoManager::instance()->sign(sig, identity(), buf);
|
||||
}
|
||||
|
||||
void
|
||||
Router::SendTo(RouterID remote, const ILinkMessage *msg, ILinkLayer *selected)
|
||||
{
|
||||
const std::string remoteName = "TX_" + remote.ToString();
|
||||
METRICS_DYNAMIC_INCREMENT(msg->Name(), remoteName.c_str());
|
||||
metrics::integerTick(msg->Name(), "to", 1, "tx", remote.ToString());
|
||||
llarp_buffer_t buf(linkmsg_buffer);
|
||||
|
||||
if(!msg->BEncode(&buf))
|
||||
|
|
|
@ -305,6 +305,11 @@ namespace llarp
|
|||
// set to max value right now
|
||||
std::unordered_map< RouterID, llarp_time_t, PubKey::Hash > lokinetRouters;
|
||||
|
||||
// set to true if we are configured to run with json logging
|
||||
bool m_LogJSON = false;
|
||||
// the file we are logging to
|
||||
FILE *m_LogFile = stdout;
|
||||
|
||||
Router(struct llarp_threadpool *tp, llarp_ev_loop_ptr __netloop,
|
||||
std::shared_ptr< Logic > logic);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace llarp
|
|||
namespace
|
||||
{
|
||||
static void
|
||||
Flush(const std::deque< std::string > &lines, FILE *const f)
|
||||
Flush(std::deque< std::string > lines, FILE *const f)
|
||||
{
|
||||
for(const auto &line : lines)
|
||||
fprintf(f, "%s\n", line.c_str());
|
||||
|
@ -14,15 +14,19 @@ namespace llarp
|
|||
}
|
||||
} // namespace
|
||||
FileLogStream::FileLogStream(thread::ThreadPool *disk, FILE *f,
|
||||
llarp_time_t flushInterval)
|
||||
: m_Disk(disk), m_File(f), m_FlushInterval(flushInterval)
|
||||
llarp_time_t flushInterval, bool closeFile)
|
||||
: m_Disk(disk)
|
||||
, m_File(f)
|
||||
, m_FlushInterval(flushInterval)
|
||||
, m_Close(closeFile)
|
||||
{
|
||||
}
|
||||
|
||||
FileLogStream::~FileLogStream()
|
||||
{
|
||||
fflush(m_File);
|
||||
fclose(m_File);
|
||||
if(m_Close)
|
||||
fclose(m_File);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -36,27 +40,11 @@ namespace llarp
|
|||
|
||||
void
|
||||
FileLogStream::PreLog(std::stringstream &ss, LogLevel lvl, const char *fname,
|
||||
int lineno) const
|
||||
int lineno, const std::string &nodename) const
|
||||
{
|
||||
switch(lvl)
|
||||
{
|
||||
case eLogNone:
|
||||
break;
|
||||
case eLogDebug:
|
||||
ss << "[DBG] ";
|
||||
break;
|
||||
case eLogInfo:
|
||||
ss << "[NFO] ";
|
||||
break;
|
||||
case eLogWarn:
|
||||
|
||||
ss << "[WRN] ";
|
||||
break;
|
||||
case eLogError:
|
||||
ss << "[ERR] ";
|
||||
break;
|
||||
}
|
||||
ss << "(" << thread_id_string() << ") " << log_timestamp() << " " << fname
|
||||
ss << "[" << LogLevelToString(lvl) << "] ";
|
||||
ss << "[" << nodename << "]"
|
||||
<< "(" << thread_id_string() << ") " << log_timestamp() << " " << fname
|
||||
<< ":" << lineno << "\t";
|
||||
}
|
||||
|
||||
|
@ -76,7 +64,10 @@ namespace llarp
|
|||
void
|
||||
FileLogStream::FlushLinesToDisk(llarp_time_t now)
|
||||
{
|
||||
m_Disk->addJob(std::bind(&Flush, std::move(m_Lines), m_File));
|
||||
FILE *const f = m_File;
|
||||
std::deque< std::string > lines(m_Lines);
|
||||
m_Disk->addJob([=]() { Flush(lines, f); });
|
||||
m_Lines.clear();
|
||||
m_LastFlush = now;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
|
@ -12,14 +12,14 @@ namespace llarp
|
|||
/// flushable file based log stream
|
||||
struct FileLogStream : public ILogStream
|
||||
{
|
||||
FileLogStream(thread::ThreadPool* disk, FILE* f,
|
||||
llarp_time_t flushInterval);
|
||||
FileLogStream(thread::ThreadPool* disk, FILE* f, llarp_time_t flushInterval,
|
||||
bool closefile = true);
|
||||
|
||||
~FileLogStream();
|
||||
|
||||
void
|
||||
PreLog(std::stringstream& out, LogLevel lvl, const char* fname,
|
||||
int lineno) const override;
|
||||
PreLog(std::stringstream& out, LogLevel lvl, const char* fname, int lineno,
|
||||
const std::string& nodename) const override;
|
||||
|
||||
void
|
||||
Print(LogLevel, const char*, const std::string& msg) override;
|
||||
|
@ -32,6 +32,9 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
std::deque< std::string > m_Lines;
|
||||
|
||||
private:
|
||||
bool
|
||||
ShouldFlush(llarp_time_t now) const;
|
||||
|
@ -40,10 +43,10 @@ namespace llarp
|
|||
FlushLinesToDisk(llarp_time_t now);
|
||||
|
||||
thread::ThreadPool* m_Disk;
|
||||
FILE* m_File;
|
||||
FILE* const m_File;
|
||||
const llarp_time_t m_FlushInterval;
|
||||
llarp_time_t m_LastFlush = 0;
|
||||
std::deque< std::string > m_Lines;
|
||||
const bool m_Close;
|
||||
};
|
||||
} // namespace llarp
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace llarp
|
|||
{
|
||||
namespace json
|
||||
{
|
||||
using Object = nlohmann::json;
|
||||
|
||||
struct IParser
|
||||
{
|
||||
virtual ~IParser()
|
||||
|
@ -34,7 +36,7 @@ namespace llarp
|
|||
FeedData(const char* buf, size_t sz) = 0;
|
||||
/// parse internal buffer
|
||||
virtual Result
|
||||
Parse(nlohmann::json& obj) const = 0;
|
||||
Parse(Object& obj) const = 0;
|
||||
};
|
||||
|
||||
/// create new parser
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#include <util/json_logger.hpp>
|
||||
#include <util/json.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
void
|
||||
JSONLogStream::AppendLog(LogLevel lvl, const char* fname, int lineno,
|
||||
const std::string& nodename, const std::string msg)
|
||||
{
|
||||
json::Object obj;
|
||||
obj["time"] = llarp::time_now_ms();
|
||||
obj["nickname"] = nodename;
|
||||
obj["file"] = std::string(fname);
|
||||
obj["line"] = lineno;
|
||||
obj["level"] = LogLevelToString(lvl);
|
||||
obj["message"] = msg;
|
||||
m_Lines.emplace_back(obj.dump());
|
||||
}
|
||||
|
||||
} // namespace llarp
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef LLARP_UTIL_JSON_LOGGER
|
||||
#define LLARP_UTIL_JSON_LOGGER
|
||||
|
||||
#include <util/file_logger.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct JSONLogStream : public FileLogStream
|
||||
{
|
||||
JSONLogStream(thread::ThreadPool* disk, FILE* f, llarp_time_t flushInterval,
|
||||
bool closeFile)
|
||||
: FileLogStream(disk, f, flushInterval, closeFile)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AppendLog(LogLevel lvl, const char* fname, int lineno,
|
||||
const std::string& nodename, const std::string msg) override;
|
||||
};
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
|
@ -85,7 +85,7 @@ namespace llarp
|
|||
LogContext();
|
||||
LogLevel minLevel = eLogInfo;
|
||||
ILogStream_ptr logStream;
|
||||
std::string nodeName;
|
||||
std::string nodeName = "lokinet";
|
||||
|
||||
const llarp_time_t started;
|
||||
|
||||
|
@ -106,12 +106,8 @@ namespace llarp
|
|||
return;
|
||||
|
||||
std::stringstream ss;
|
||||
log.logStream->PreLog(ss, lvl, fname, lineno);
|
||||
if(log.nodeName.size())
|
||||
LogAppend(ss, "[", log.nodeName, "] ");
|
||||
LogAppend(ss, std::forward< TArgs >(args)...);
|
||||
log.logStream->PostLog(ss);
|
||||
log.logStream->Print(lvl, fname, ss.str());
|
||||
log.logStream->AppendLog(lvl, fname, lineno, log.nodeName, ss.str());
|
||||
}
|
||||
/*
|
||||
std::stringstream ss;
|
||||
|
|
|
@ -8,8 +8,8 @@ namespace llarp
|
|||
struct SysLogStream : public ILogStream
|
||||
{
|
||||
void
|
||||
PreLog(std::stringstream& s, LogLevel lvl, const char* fname,
|
||||
int lineno) const override;
|
||||
PreLog(std::stringstream& s, LogLevel lvl, const char* fname, int lineno,
|
||||
const std::string& nodename) const override;
|
||||
|
||||
void
|
||||
Print(LogLevel lvl, const char* tag, const std::string& msg) override;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#include <util/loglevel.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
std::string
|
||||
LogLevelToString(LogLevel lvl)
|
||||
{
|
||||
switch(lvl)
|
||||
{
|
||||
case eLogDebug:
|
||||
return "DBG";
|
||||
case eLogInfo:
|
||||
return "NFO";
|
||||
case eLogWarn:
|
||||
return "WRN";
|
||||
case eLogError:
|
||||
return "ERR";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
} // namespace llarp
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef LLARP_UTIL_LOG_LEVEL_HPP
|
||||
#define LLARP_UTIL_LOG_LEVEL_HPP
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -13,6 +14,9 @@ namespace llarp
|
|||
eLogNone
|
||||
};
|
||||
|
||||
std::string
|
||||
LogLevelToString(LogLevel level);
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,14 +16,26 @@ namespace llarp
|
|||
}
|
||||
|
||||
virtual void
|
||||
PreLog(std::stringstream& out, LogLevel lvl, const char* fname,
|
||||
int lineno) const = 0;
|
||||
PreLog(std::stringstream& out, LogLevel lvl, const char* fname, int lineno,
|
||||
const std::string& nodename) const = 0;
|
||||
|
||||
virtual void
|
||||
Print(LogLevel lvl, const char* filename, const std::string& msg) = 0;
|
||||
|
||||
virtual void
|
||||
PostLog(std::stringstream& out) const = 0;
|
||||
|
||||
virtual void
|
||||
AppendLog(LogLevel lvl, const char* fname, int lineno,
|
||||
const std::string& nodename, const std::string msg)
|
||||
{
|
||||
std::stringstream ss;
|
||||
PreLog(ss, lvl, fname, lineno, nodename);
|
||||
ss << msg;
|
||||
PostLog(ss);
|
||||
Print(lvl, fname, ss.str());
|
||||
}
|
||||
|
||||
/// called every end of event loop tick
|
||||
virtual void
|
||||
Tick(llarp_time_t now) = 0;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <util/metrics_types.hpp>
|
||||
#include <util/metrics_core.hpp>
|
||||
#include <util/string_view.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -25,6 +26,23 @@ namespace llarp
|
|||
return manager->registry().publicationType(id, type);
|
||||
}
|
||||
};
|
||||
|
||||
template < typename... TagVals >
|
||||
void
|
||||
integerTick(string_view category, string_view metric, int val,
|
||||
TagVals&&... tags)
|
||||
{
|
||||
if(DefaultManager::instance())
|
||||
{
|
||||
CollectorRepo< int >& repository =
|
||||
DefaultManager::instance()->intCollectorRepo();
|
||||
IntCollector* collector = repository.defaultCollector(category, metric);
|
||||
if(collector->id().category()->enabled())
|
||||
{
|
||||
collector->tick(val, tags...);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace metrics
|
||||
} // namespace llarp
|
||||
|
||||
|
@ -41,86 +59,8 @@ 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< 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) \
|
||||
METRICS_TIME_BLOCK_IMP(CAT, METRIC, METRICS_UNIQUE_NAME(time_block))
|
||||
|
||||
#define METRICS_IF_CATEGORY_ENABLED_IMP(CAT, NAME) \
|
||||
static llarp::metrics::CategoryContainer NAME = {false, nullptr, nullptr}; \
|
||||
if(!NAME.category() && llarp::metrics::DefaultManager::instance()) \
|
||||
{ \
|
||||
llarp::metrics::MetricsHelper::initContainer(NAME, CAT); \
|
||||
} \
|
||||
if(NAME.enabled())
|
||||
|
||||
#define METRICS_IF_CATEGORY_ENABLED(CAT) \
|
||||
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< 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
|
||||
#define METRICS_INT_UPDATE(CAT, METRIC, VALUE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
static CategoryContainer container = {false, nullptr, nullptr}; \
|
||||
static IntCollector* collector = nullptr; \
|
||||
if(container.category() == nullptr && DefaultManager::instance()) \
|
||||
{ \
|
||||
collector = MetricHelper::getIntCollector(CAT, METRIC); \
|
||||
MetricHelper::initContainer(container, CAT); \
|
||||
} \
|
||||
if(container.enabled()) \
|
||||
{ \
|
||||
collector->tick(VALUE); \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#define METRICS_TYPED_INT_UPDATE(CAT, METRIC, VALUE, TYPE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
static CategoryContainer container = {false, nullptr, nullptr}; \
|
||||
static IntCollector* collector = nullptr; \
|
||||
if(container.category() == nullptr && DefaultManager::instance()) \
|
||||
{ \
|
||||
collector = MetricHelper::getIntCollector(CAT, METRIC); \
|
||||
MetricHelper::setType(collector->id(), TYPE); \
|
||||
MetricHelper::initContainer(container, CAT); \
|
||||
} \
|
||||
if(container.enabled()) \
|
||||
{ \
|
||||
collector->tick(VALUE); \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
// For when the category/metric may change during the program run
|
||||
#define METRICS_DYNAMIC_UPDATE(CAT, METRIC, VALUE) \
|
||||
#define METRICS_DYNAMIC_UPDATE(CAT, METRIC, ...) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
|
@ -132,50 +72,9 @@ namespace llarp
|
|||
repository.defaultCollector((CAT), (METRIC)); \
|
||||
if(collector->id().category()->enabled()) \
|
||||
{ \
|
||||
collector->tick((VALUE)); \
|
||||
collector->tick(__VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
// For when the category/metric remain static
|
||||
#define METRICS_UPDATE(CAT, METRIC, VALUE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
static CategoryContainer container = {false, nullptr, nullptr}; \
|
||||
static DoubleCollector* collector = nullptr; \
|
||||
if(container.category() == nullptr && DefaultManager::instance()) \
|
||||
{ \
|
||||
collector = MetricHelper::getDoubleCollector(CAT, METRIC); \
|
||||
MetricHelper::initContainer(container, CAT); \
|
||||
} \
|
||||
if(container.enabled()) \
|
||||
{ \
|
||||
collector->tick(VALUE); \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#define METRICS_TYPED_UPDATE(CAT, METRIC, VALUE, TYPE) \
|
||||
do \
|
||||
{ \
|
||||
using namespace llarp::metrics; \
|
||||
static CategoryContainer container = {false, nullptr, nullptr}; \
|
||||
static DoubleCollector* collector = nullptr; \
|
||||
if(container.category() == nullptr && DefaultManager::instance()) \
|
||||
{ \
|
||||
collector = MetricHelper::getDoubleCollector(CAT, METRIC); \
|
||||
MetricHelper::setType(collector->id(), TYPE); \
|
||||
MetricHelper::initContainer(container, CAT); \
|
||||
} \
|
||||
if(container.enabled()) \
|
||||
{ \
|
||||
collector->tick(VALUE); \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#define METRICS_DYNAMIC_INCREMENT(CAT, METRIC) \
|
||||
METRICS_DYNAMIC_INT_UPDATE(CAT, METRIC, 1)
|
||||
|
||||
#define METRICS_INCREMENT(CAT, METRIC) METRICS_INT_UPDATE(CAT, METRIC, 1)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,15 +6,12 @@ namespace llarp
|
|||
{
|
||||
namespace metrics
|
||||
{
|
||||
using DoubleRecords = std::vector< Record< double > >;
|
||||
using IntRecords = std::vector< Record< int > >;
|
||||
|
||||
std::tuple< Id, bool >
|
||||
Registry::insert(const char *category, const char *name)
|
||||
Registry::insert(string_view category, string_view name)
|
||||
{
|
||||
// avoid life time issues, putting strings in the stringmem set
|
||||
const char *cStr = m_stringmem.emplace(category).first->c_str();
|
||||
const char *nStr = m_stringmem.emplace(name).first->c_str();
|
||||
string_view cStr = m_stringmem.emplace(category).first->c_str();
|
||||
string_view nStr = m_stringmem.emplace(name).first->c_str();
|
||||
|
||||
NamedCategory namedCategory(cStr, nStr);
|
||||
const auto it = m_metrics.find(namedCategory);
|
||||
|
@ -39,7 +36,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
Id
|
||||
Registry::add(const char *category, const char *name)
|
||||
Registry::add(string_view category, string_view name)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
auto result = insert(category, name);
|
||||
|
@ -47,7 +44,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
Id
|
||||
Registry::get(const char *category, const char *name)
|
||||
Registry::get(string_view category, string_view name)
|
||||
{
|
||||
Id result = findId(category, name);
|
||||
if(result)
|
||||
|
@ -60,11 +57,11 @@ namespace llarp
|
|||
}
|
||||
|
||||
const Category *
|
||||
Registry::add(const char *category)
|
||||
Registry::add(string_view category)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
|
||||
const char *cStr = m_stringmem.emplace(category).first->c_str();
|
||||
string_view cStr = m_stringmem.emplace(category).first->c_str();
|
||||
auto it = m_categories.find(cStr);
|
||||
if(it == m_categories.end())
|
||||
{
|
||||
|
@ -76,7 +73,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
const Category *
|
||||
Registry::get(const char *category)
|
||||
Registry::get(string_view category)
|
||||
{
|
||||
const Category *cPtr = findCategory(category);
|
||||
if(cPtr)
|
||||
|
@ -85,7 +82,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
const char *cStr = m_stringmem.emplace(category).first->c_str();
|
||||
string_view cStr = m_stringmem.emplace(category).first->c_str();
|
||||
auto it = m_categories.find(cStr);
|
||||
if(it == m_categories.end())
|
||||
{
|
||||
|
@ -150,7 +147,7 @@ namespace llarp
|
|||
const FormatSpec *spec = format.specFor(type);
|
||||
if(spec != nullptr)
|
||||
{
|
||||
const char *fmt = m_stringmem.emplace(spec->m_format).first->c_str();
|
||||
string_view fmt = m_stringmem.emplace(spec->m_format).first->c_str();
|
||||
fmtPtr->setSpec(type, FormatSpec(spec->m_scale, fmt));
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +156,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
const Category *
|
||||
Registry::findCategory(const char *category) const
|
||||
Registry::findCategory(string_view category) const
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
auto it = m_categories.find(category);
|
||||
|
@ -167,7 +164,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
Id
|
||||
Registry::findId(const char *category, const char *name) const
|
||||
Registry::findId(string_view category, string_view name) const
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
auto it = m_metrics.find(std::make_tuple(category, name));
|
||||
|
@ -251,8 +248,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
template < typename Type >
|
||||
using RecordBuffer =
|
||||
std::vector< std::shared_ptr< std::vector< Record< Type > > > >;
|
||||
using RecordBuffer = std::vector<
|
||||
std::shared_ptr< std::vector< TaggedRecords< Type > > > >;
|
||||
|
||||
template < typename CategoryIterator >
|
||||
static void
|
||||
|
@ -309,12 +306,14 @@ namespace llarp
|
|||
std::make_shared< DoubleRecords >(records.doubleRecords);
|
||||
doubleRecordBuffer.push_back(dRecords);
|
||||
SampleGroup< double > doubleGroup(
|
||||
absl::Span< Record< double > >(*dRecords), result.samplePeriod);
|
||||
absl::Span< const TaggedRecords< double > >(*dRecords),
|
||||
result.samplePeriod);
|
||||
|
||||
auto iRecords = std::make_shared< IntRecords >(records.intRecords);
|
||||
intRecordBuffer.push_back(iRecords);
|
||||
SampleGroup< int > intGroup(absl::Span< Record< int > >(*iRecords),
|
||||
result.samplePeriod);
|
||||
SampleGroup< int > intGroup(
|
||||
absl::Span< const TaggedRecords< int > >(*iRecords),
|
||||
result.samplePeriod);
|
||||
|
||||
std::for_each(manager.m_publishers.globalBegin(),
|
||||
manager.m_publishers.globalEnd(),
|
||||
|
|
|
@ -14,84 +14,130 @@ namespace llarp
|
|||
{
|
||||
namespace metrics
|
||||
{
|
||||
inline void
|
||||
packToTagsImpl(Tags &)
|
||||
{
|
||||
}
|
||||
|
||||
template < typename K, typename V, typename... Args >
|
||||
inline void
|
||||
packToTagsImpl(Tags &tags, const K &k, const V &v, const Args &... args)
|
||||
{
|
||||
static_assert(std::is_convertible< K, Tag >::value, "");
|
||||
static_assert(std::is_convertible< V, TagValue >::value, "");
|
||||
|
||||
tags.emplace(k, v);
|
||||
packToTagsImpl(tags, args...);
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
inline Tags
|
||||
packToTags(const Args &... args)
|
||||
{
|
||||
static_assert(sizeof...(args) % 2 == 0, "");
|
||||
Tags tags;
|
||||
packToTagsImpl(tags, args...);
|
||||
return tags;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Tags
|
||||
packToTags< Tags >(const Tags &tags)
|
||||
{
|
||||
return tags;
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
class Collector
|
||||
{
|
||||
public:
|
||||
using RecordType = Record< Type >;
|
||||
using RecordType = Record< Type >;
|
||||
using TaggedRecordsType = TaggedRecords< Type >;
|
||||
|
||||
private:
|
||||
RecordType m_record GUARDED_BY(m_mutex);
|
||||
TaggedRecordsType m_records GUARDED_BY(m_mutex);
|
||||
mutable util::Mutex m_mutex;
|
||||
|
||||
Collector(const Collector &) = delete;
|
||||
Collector &
|
||||
operator=(const Collector &) = delete;
|
||||
|
||||
template < typename... Args >
|
||||
RecordType &
|
||||
fetch(Args... args) EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
|
||||
{
|
||||
return m_records.data[packToTags(args...)];
|
||||
}
|
||||
|
||||
public:
|
||||
Collector(const Id &id) : m_record(id)
|
||||
Collector(const Id &id) : m_records(id)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.clear();
|
||||
absl::MutexLock l(&m_mutex);
|
||||
m_records.data.clear();
|
||||
}
|
||||
|
||||
RecordType
|
||||
TaggedRecordsType
|
||||
loadAndClear()
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
RecordType rec = m_record;
|
||||
m_record.clear();
|
||||
absl::MutexLock l(&m_mutex);
|
||||
auto result = m_records;
|
||||
m_records.data.clear();
|
||||
|
||||
return rec;
|
||||
return result;
|
||||
}
|
||||
|
||||
RecordType
|
||||
TaggedRecordsType
|
||||
load()
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
return m_record;
|
||||
absl::MutexLock l(&m_mutex);
|
||||
return m_records;
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
void
|
||||
tick(Type value)
|
||||
tick(Type value, Args... args)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.count()++;
|
||||
m_record.total() += value;
|
||||
m_record.min() = std::min(m_record.min(), value);
|
||||
m_record.max() = std::max(m_record.max(), value);
|
||||
absl::MutexLock l(&m_mutex);
|
||||
RecordType &rec = fetch(args...);
|
||||
rec.count()++;
|
||||
rec.total() += value;
|
||||
rec.min() = std::min(rec.min(), value);
|
||||
rec.max() = std::max(rec.max(), value);
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
void
|
||||
accumulate(size_t count, Type total, Type min, Type max)
|
||||
accumulate(size_t count, Type total, Type min, Type max, Args... args)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.count() += count;
|
||||
m_record.total() += total;
|
||||
m_record.min() = std::min(m_record.min(), min);
|
||||
m_record.max() = std::max(m_record.max(), max);
|
||||
absl::MutexLock l(&m_mutex);
|
||||
RecordType &rec = fetch(args...);
|
||||
rec.count() += count;
|
||||
rec.total() += total;
|
||||
rec.min() = std::min(rec.min(), min);
|
||||
rec.max() = std::max(rec.max(), max);
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
void
|
||||
set(size_t count, Type total, Type min, Type max)
|
||||
set(size_t count, Type total, Type min, Type max, Args... args)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
m_record.count() = count;
|
||||
m_record.total() = total;
|
||||
m_record.min() = min;
|
||||
m_record.max() = max;
|
||||
absl::MutexLock l(&m_mutex);
|
||||
RecordType &rec = fetch(args...);
|
||||
rec.count() = count;
|
||||
rec.total() = total;
|
||||
rec.min() = min;
|
||||
rec.max() = max;
|
||||
}
|
||||
|
||||
const Id &
|
||||
id() const
|
||||
{
|
||||
absl::ReaderMutexLock l(&m_mutex);
|
||||
return m_record.id();
|
||||
return m_records.id;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -107,16 +153,36 @@ namespace llarp
|
|||
publish(const Sample &sample) = 0;
|
||||
};
|
||||
|
||||
template < typename LhsType, typename RhsType >
|
||||
template < typename Value >
|
||||
static inline void
|
||||
combine(Record< LhsType > &record, const Record< RhsType > &toAdd)
|
||||
combine(TaggedRecords< Value > &records,
|
||||
const TaggedRecords< Value > &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(), LhsType(toAdd.min()));
|
||||
record.max() = std::max(record.max(), LhsType(toAdd.max()));
|
||||
records.id = toAdd.id;
|
||||
for(auto &record : records.data)
|
||||
{
|
||||
auto it = toAdd.data.find(record.first);
|
||||
if(it == toAdd.data.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
record.second.count() += it->second.count();
|
||||
record.second.total() += it->second.total();
|
||||
record.second.min() = std::min(record.second.min(), it->second.min());
|
||||
record.second.max() = std::max(record.second.max(), it->second.max());
|
||||
}
|
||||
|
||||
for(const auto &record : toAdd.data)
|
||||
{
|
||||
auto it = records.data.find(record.first);
|
||||
if(it != records.data.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
records.data[record.first] = record.second;
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
|
@ -160,10 +226,10 @@ namespace llarp
|
|||
return count > 0;
|
||||
}
|
||||
|
||||
Record< Type >
|
||||
TaggedRecords< Type >
|
||||
combineAndClear()
|
||||
{
|
||||
Record< Type > rec = m_default.loadAndClear();
|
||||
TaggedRecords< Type > rec = m_default.loadAndClear();
|
||||
|
||||
for(auto &ptr : m_collectors)
|
||||
{
|
||||
|
@ -173,10 +239,10 @@ namespace llarp
|
|||
return rec;
|
||||
}
|
||||
|
||||
Record< Type >
|
||||
TaggedRecords< Type >
|
||||
combine()
|
||||
{
|
||||
Record< Type > rec = m_default.load();
|
||||
TaggedRecords< Type > rec = m_default.load();
|
||||
|
||||
for(auto &ptr : m_collectors)
|
||||
{
|
||||
|
@ -204,34 +270,11 @@ namespace llarp
|
|||
|
||||
class Registry
|
||||
{
|
||||
using NamedCategory = std::tuple< const char *, const char * >;
|
||||
using NamedCategory = std::tuple< string_view, string_view >;
|
||||
|
||||
struct CmpNamedCategory
|
||||
{
|
||||
bool
|
||||
operator()(const NamedCategory &lhs, const NamedCategory &rhs) const
|
||||
{
|
||||
int ret = std::strcmp(std::get< 0 >(lhs), std::get< 0 >(rhs));
|
||||
if(ret == 0)
|
||||
{
|
||||
ret = std::strcmp(std::get< 1 >(lhs), std::get< 1 >(rhs));
|
||||
}
|
||||
return ret < 0;
|
||||
}
|
||||
};
|
||||
struct StrCmp
|
||||
{
|
||||
bool
|
||||
operator()(const char *lhs, const char *rhs) const
|
||||
{
|
||||
return std::strcmp(lhs, rhs) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
using MetricMap = std::map< NamedCategory, std::shared_ptr< Description >,
|
||||
CmpNamedCategory >;
|
||||
using CategoryMap =
|
||||
std::map< const char *, std::shared_ptr< Category >, StrCmp >;
|
||||
using MetricMap =
|
||||
std::map< NamedCategory, std::shared_ptr< Description > >;
|
||||
using CategoryMap = std::map< string_view, std::shared_ptr< Category > >;
|
||||
|
||||
std::set< std::string > m_stringmem GUARDED_BY(m_mutex);
|
||||
CategoryMap m_categories GUARDED_BY(m_mutex);
|
||||
|
@ -244,7 +287,7 @@ namespace llarp
|
|||
operator=(const Registry &) = delete;
|
||||
|
||||
std::tuple< Id, bool >
|
||||
insert(const char *category, const char *name)
|
||||
insert(string_view category, string_view name)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
|
||||
|
||||
public:
|
||||
|
@ -253,14 +296,14 @@ namespace llarp
|
|||
}
|
||||
|
||||
Id
|
||||
add(const char *category, const char *name) LOCKS_EXCLUDED(m_mutex);
|
||||
add(string_view category, string_view name) LOCKS_EXCLUDED(m_mutex);
|
||||
Id
|
||||
get(const char *category, const char *name) LOCKS_EXCLUDED(m_mutex);
|
||||
get(string_view category, string_view name) LOCKS_EXCLUDED(m_mutex);
|
||||
|
||||
const Category *
|
||||
add(const char *category) LOCKS_EXCLUDED(m_mutex);
|
||||
add(string_view category) LOCKS_EXCLUDED(m_mutex);
|
||||
const Category *
|
||||
get(const char *category);
|
||||
get(string_view category);
|
||||
|
||||
void
|
||||
enable(const Category *category, bool value);
|
||||
|
@ -288,16 +331,16 @@ namespace llarp
|
|||
}
|
||||
|
||||
const Category *
|
||||
findCategory(const char *category) const;
|
||||
findCategory(string_view category) const;
|
||||
Id
|
||||
findId(const char *category, const char *name) const;
|
||||
findId(string_view category, string_view name) const;
|
||||
|
||||
std::vector< const Category * >
|
||||
getAll() const;
|
||||
};
|
||||
|
||||
using DoubleRecords = std::vector< Record< double > >;
|
||||
using IntRecords = std::vector< Record< int > >;
|
||||
using DoubleRecords = std::vector< TaggedRecords< double > >;
|
||||
using IntRecords = std::vector< TaggedRecords< int > >;
|
||||
|
||||
struct Records
|
||||
{
|
||||
|
@ -361,8 +404,8 @@ namespace llarp
|
|||
return *it->second.get();
|
||||
}
|
||||
|
||||
template < Record< Type > (Collectors< Type >::*func)() >
|
||||
std::vector< Record< Type > >
|
||||
template < TaggedRecords< Type > (Collectors< Type >::*func)() >
|
||||
std::vector< TaggedRecords< Type > >
|
||||
collectOp(const Category *category)
|
||||
{
|
||||
absl::WriterMutexLock l(&m_mutex);
|
||||
|
@ -374,7 +417,7 @@ namespace llarp
|
|||
return {};
|
||||
}
|
||||
|
||||
std::vector< Record< Type > > result;
|
||||
std::vector< TaggedRecords< Type > > result;
|
||||
auto &collectors = it->second;
|
||||
result.reserve(collectors.size());
|
||||
|
||||
|
@ -390,20 +433,20 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
std::vector< Record< Type > >
|
||||
std::vector< TaggedRecords< Type > >
|
||||
collectAndClear(const Category *category)
|
||||
{
|
||||
return collectOp< &Collectors< Type >::combineAndClear >(category);
|
||||
}
|
||||
|
||||
std::vector< Record< Type > >
|
||||
std::vector< TaggedRecords< Type > >
|
||||
collect(const Category *category)
|
||||
{
|
||||
return collectOp< &Collectors< Type >::combine >(category);
|
||||
}
|
||||
|
||||
Collector< Type > *
|
||||
defaultCollector(const char *category, const char *name)
|
||||
defaultCollector(string_view category, string_view name)
|
||||
{
|
||||
return defaultCollector(m_registry->get(category, name));
|
||||
}
|
||||
|
@ -427,7 +470,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
std::shared_ptr< Collector< Type > >
|
||||
addCollector(const char *category, const char *name)
|
||||
addCollector(string_view category, string_view name)
|
||||
{
|
||||
return addCollector(m_registry->get(category, name));
|
||||
}
|
||||
|
@ -668,7 +711,7 @@ namespace llarp
|
|||
/// Add a `publisher` which will receive events for the given
|
||||
/// `categoryName` only
|
||||
bool
|
||||
addPublisher(const char *categoryName,
|
||||
addPublisher(string_view categoryName,
|
||||
const std::shared_ptr< Publisher > &publisher)
|
||||
{
|
||||
return addPublisher(m_registry.get(categoryName), publisher);
|
||||
|
@ -763,7 +806,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
enableCategory(const char *categoryName, bool enable = true)
|
||||
enableCategory(string_view categoryName, bool enable = true)
|
||||
{
|
||||
m_registry.enable(m_registry.get(categoryName), enable);
|
||||
}
|
||||
|
@ -787,7 +830,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
std::vector< Publisher * >
|
||||
publishersForCategory(const char *categoryName) const
|
||||
publishersForCategory(string_view categoryName) const
|
||||
{
|
||||
const Category *category = m_registry.findCategory(categoryName);
|
||||
return category ? publishersForCategory(category)
|
||||
|
@ -869,7 +912,7 @@ namespace llarp
|
|||
|
||||
public:
|
||||
static Collector *
|
||||
lookup(const char *category, const char *name, Manager *manager = nullptr)
|
||||
lookup(string_view category, string_view name, Manager *manager = nullptr)
|
||||
{
|
||||
manager = DefaultManager::manager(manager);
|
||||
return manager ? (manager->*repoFunc)().defaultCollector(category, name)
|
||||
|
@ -883,7 +926,7 @@ namespace llarp
|
|||
return manager ? (manager->*repoFunc)().defaultCollector(id) : 0;
|
||||
}
|
||||
|
||||
Metric(const char *category, const char *name, Manager *manager)
|
||||
Metric(string_view category, string_view name, Manager *manager)
|
||||
: m_collector(lookup(category, name, manager))
|
||||
, m_enabled(m_collector ? &m_collector->id().category()->enabledRaw()
|
||||
: nullptr)
|
||||
|
@ -966,7 +1009,7 @@ namespace llarp
|
|||
|
||||
static void
|
||||
getCollector(Collector **collector, CategoryContainer *container,
|
||||
const char *category, const char *metric)
|
||||
string_view category, string_view metric)
|
||||
{
|
||||
Manager *manager = DefaultManager::instance();
|
||||
*collector = (manager->*repoFunc().defaultCollector)(category, metric);
|
||||
|
@ -976,7 +1019,7 @@ namespace llarp
|
|||
|
||||
static void
|
||||
getCollector(Collector **collector, CategoryContainer *container,
|
||||
const char *category, const char *metric,
|
||||
string_view category, string_view metric,
|
||||
Publication::Type type)
|
||||
{
|
||||
Manager *manager = DefaultManager::instance();
|
||||
|
@ -995,6 +1038,7 @@ namespace llarp
|
|||
class TimerGuard
|
||||
{
|
||||
private:
|
||||
Tags m_tags;
|
||||
util::Stopwatch m_stopwatch;
|
||||
DoubleCollector *m_collector;
|
||||
|
||||
|
@ -1003,8 +1047,9 @@ namespace llarp
|
|||
operator=(const TimerGuard &) = delete;
|
||||
|
||||
public:
|
||||
TimerGuard(DoubleMetric *metric)
|
||||
: m_stopwatch()
|
||||
template < typename... TagVals >
|
||||
TimerGuard(DoubleMetric *metric, TagVals &&... tags)
|
||||
: m_tags(packToTags(tags...))
|
||||
, m_collector(metric->active() ? metric->collector() : nullptr)
|
||||
{
|
||||
if(m_collector)
|
||||
|
@ -1013,8 +1058,9 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
TimerGuard(DoubleCollector *collector)
|
||||
: m_stopwatch()
|
||||
template < typename... TagVals >
|
||||
TimerGuard(DoubleCollector *collector, TagVals &&... tags)
|
||||
: m_tags(packToTags(tags...))
|
||||
, m_collector(collector && collector->id().category()->enabled()
|
||||
? collector
|
||||
: nullptr)
|
||||
|
@ -1025,8 +1071,10 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
|
||||
TimerGuard(const char *category, const char *name, Manager *manager)
|
||||
: m_stopwatch(), m_collector(nullptr)
|
||||
template < typename... TagVals >
|
||||
TimerGuard(string_view category, string_view name,
|
||||
Manager *manager = nullptr, TagVals &&... tags)
|
||||
: m_tags(packToTags(tags...)), m_collector(nullptr)
|
||||
{
|
||||
DoubleCollector *collector =
|
||||
DoubleMetric::lookup(category, name, manager);
|
||||
|
@ -1038,8 +1086,10 @@ namespace llarp
|
|||
m_stopwatch.start();
|
||||
}
|
||||
}
|
||||
TimerGuard(const Id &id, Manager *manager)
|
||||
: m_stopwatch(), m_collector(nullptr)
|
||||
|
||||
template < typename... TagVals >
|
||||
TimerGuard(const Id &id, Manager *manager = nullptr, TagVals &&... tags)
|
||||
: m_tags(packToTags(tags...)), m_collector(nullptr)
|
||||
{
|
||||
DoubleCollector *collector = DoubleMetric::lookup(id, manager);
|
||||
m_collector = (collector && collector->id().category()->enabled())
|
||||
|
@ -1056,7 +1106,7 @@ namespace llarp
|
|||
if(active())
|
||||
{
|
||||
m_stopwatch.stop();
|
||||
m_collector->tick(absl::ToDoubleSeconds(m_stopwatch.time()));
|
||||
m_collector->tick(absl::ToDoubleSeconds(m_stopwatch.time()), m_tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1107,7 +1157,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
schedule(const char *categoryName, absl::Duration interval)
|
||||
schedule(string_view categoryName, absl::Duration interval)
|
||||
{
|
||||
return schedule(m_manager->registry().get(categoryName), interval);
|
||||
}
|
||||
|
@ -1119,7 +1169,7 @@ namespace llarp
|
|||
setDefault(absl::Duration interval);
|
||||
|
||||
bool
|
||||
cancel(const char *categoryName)
|
||||
cancel(string_view categoryName)
|
||||
{
|
||||
return cancel(m_manager->registry().get(categoryName));
|
||||
}
|
||||
|
@ -1145,7 +1195,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
absl::optional< absl::Duration >
|
||||
find(const char *categoryName) const
|
||||
find(string_view categoryName) const
|
||||
{
|
||||
return find(m_manager->registry().get(categoryName));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <util/printer.hpp>
|
||||
|
||||
#include <absl/strings/str_join.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace metrics
|
||||
|
@ -13,7 +15,8 @@ namespace llarp
|
|||
static constexpr size_t INIT_SIZE = 32;
|
||||
|
||||
char buf[INIT_SIZE] = {0};
|
||||
int rc = snprintf(buf, INIT_SIZE, format.m_format, data * format.m_scale);
|
||||
int rc = snprintf(buf, INIT_SIZE, format.m_format.data(),
|
||||
data * format.m_scale);
|
||||
|
||||
if(rc < 0)
|
||||
{
|
||||
|
@ -28,7 +31,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
std::vector< char > vec(rc + 1);
|
||||
rc = snprintf(vec.data(), vec.size(), format.m_format,
|
||||
rc = snprintf(vec.data(), vec.size(), format.m_format.data(),
|
||||
data * format.m_scale);
|
||||
|
||||
if(static_cast< size_t >(rc) > vec.size())
|
||||
|
@ -127,7 +130,7 @@ namespace llarp
|
|||
Description::toString() const
|
||||
{
|
||||
util::Lock l(&m_mutex);
|
||||
return m_category->name() + std::string(".") + m_name;
|
||||
return absl::StrCat(m_category->name(), ".", m_name);
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
#include <util/types.hpp>
|
||||
#include <util/variant.hpp>
|
||||
|
||||
#include <absl/types/span.h>
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
#include <absl/container/flat_hash_set.h>
|
||||
#include <absl/hash/hash.h>
|
||||
#include <absl/types/optional.h>
|
||||
#include <absl/types/span.h>
|
||||
#include <absl/types/variant.h>
|
||||
#include <cstring>
|
||||
#include <iosfwd>
|
||||
|
@ -49,7 +52,7 @@ namespace llarp
|
|||
struct FormatSpec
|
||||
{
|
||||
float m_scale;
|
||||
const char *m_format;
|
||||
string_view m_format;
|
||||
|
||||
static constexpr char DEFAULT_FORMAT[] = "%f";
|
||||
|
||||
|
@ -57,7 +60,7 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
constexpr FormatSpec(float scale, const char *format)
|
||||
constexpr FormatSpec(float scale, string_view format)
|
||||
: m_scale(scale), m_format(format)
|
||||
{
|
||||
}
|
||||
|
@ -69,8 +72,8 @@ namespace llarp
|
|||
inline bool
|
||||
operator==(const FormatSpec &lhs, const FormatSpec &rhs)
|
||||
{
|
||||
return lhs.m_scale == rhs.m_scale
|
||||
&& std::strcmp(lhs.m_format, rhs.m_format) == 0;
|
||||
return std::make_tuple(lhs.m_scale, lhs.m_format)
|
||||
== std::make_tuple(rhs.m_scale, rhs.m_format);
|
||||
}
|
||||
|
||||
struct Format
|
||||
|
@ -114,12 +117,12 @@ namespace llarp
|
|||
/// Represents a category of grouped metrics
|
||||
class Category
|
||||
{
|
||||
const char *m_name;
|
||||
string_view m_name;
|
||||
std::atomic_bool m_enabled;
|
||||
CategoryContainer *m_container;
|
||||
|
||||
public:
|
||||
Category(const char *name, bool enabled = true)
|
||||
Category(string_view name, bool enabled = true)
|
||||
: m_name(name), m_enabled(enabled), m_container(nullptr)
|
||||
{
|
||||
}
|
||||
|
@ -138,7 +141,7 @@ namespace llarp
|
|||
return m_enabled;
|
||||
}
|
||||
|
||||
const char *
|
||||
string_view
|
||||
name() const
|
||||
{
|
||||
return m_name;
|
||||
|
@ -180,7 +183,7 @@ namespace llarp
|
|||
mutable util::Mutex m_mutex;
|
||||
|
||||
const Category *m_category GUARDED_BY(m_mutex);
|
||||
const char *m_name GUARDED_BY(m_mutex);
|
||||
string_view m_name GUARDED_BY(m_mutex);
|
||||
Publication::Type m_type GUARDED_BY(m_mutex);
|
||||
std::shared_ptr< Format > m_format GUARDED_BY(m_mutex);
|
||||
|
||||
|
@ -189,7 +192,7 @@ namespace llarp
|
|||
operator=(const Description &) = delete;
|
||||
|
||||
public:
|
||||
Description(const Category *category, const char *name)
|
||||
Description(const Category *category, string_view name)
|
||||
: m_category(category)
|
||||
, m_name(name)
|
||||
, m_type(Publication::Type::Unspecified)
|
||||
|
@ -211,13 +214,13 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
name(const char *n)
|
||||
name(string_view n)
|
||||
{
|
||||
util::Lock l(&m_mutex);
|
||||
m_name = n;
|
||||
}
|
||||
|
||||
const char *
|
||||
string_view
|
||||
name() const
|
||||
{
|
||||
util::Lock l(&m_mutex);
|
||||
|
@ -310,14 +313,14 @@ namespace llarp
|
|||
return m_description->category();
|
||||
}
|
||||
|
||||
const char *
|
||||
string_view
|
||||
categoryName() const
|
||||
{
|
||||
assert(valid());
|
||||
return m_description->category()->name();
|
||||
}
|
||||
|
||||
const char *
|
||||
string_view
|
||||
metricName() const
|
||||
{
|
||||
assert(valid());
|
||||
|
@ -394,7 +397,6 @@ namespace llarp
|
|||
template < typename Type >
|
||||
class Record
|
||||
{
|
||||
Id m_id;
|
||||
size_t m_count;
|
||||
Type m_total;
|
||||
Type m_min;
|
||||
|
@ -407,32 +409,16 @@ namespace llarp
|
|||
// clang-format on
|
||||
|
||||
Record()
|
||||
: m_id()
|
||||
, m_count(0)
|
||||
, m_total(0.0)
|
||||
, m_min(DEFAULT_MIN())
|
||||
, m_max(DEFAULT_MAX())
|
||||
: m_count(0), m_total(0.0), m_min(DEFAULT_MIN()), m_max(DEFAULT_MAX())
|
||||
{
|
||||
}
|
||||
|
||||
explicit Record(const Id &id)
|
||||
: m_id(id)
|
||||
, m_count(0)
|
||||
, m_total()
|
||||
, m_min(DEFAULT_MIN())
|
||||
, m_max(DEFAULT_MAX())
|
||||
{
|
||||
}
|
||||
|
||||
Record(const Id &id, size_t count, double total, double min, double max)
|
||||
: m_id(id), m_count(count), m_total(total), m_min(min), m_max(max)
|
||||
Record(size_t count, double total, double min, double max)
|
||||
: m_count(count), m_total(total), m_min(min), m_max(max)
|
||||
{
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
const Id& id() const { return m_id; }
|
||||
Id& id() { return m_id; }
|
||||
|
||||
size_t count() const { return m_count; }
|
||||
size_t& count() { return m_count; }
|
||||
|
||||
|
@ -459,7 +445,6 @@ namespace llarp
|
|||
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);
|
||||
|
@ -480,9 +465,8 @@ namespace llarp
|
|||
inline bool
|
||||
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());
|
||||
return std::make_tuple(lhs.count(), lhs.total(), lhs.min(), lhs.max())
|
||||
== std::make_tuple(rhs.count(), rhs.total(), rhs.min(), rhs.max());
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
|
@ -492,17 +476,67 @@ namespace llarp
|
|||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
using Tag = std::string;
|
||||
using TagValue = absl::variant< std::string, double, std::int64_t >;
|
||||
using Tags = std::set< std::pair< Tag, TagValue > >;
|
||||
|
||||
template < typename Type >
|
||||
using TaggedRecordsData = absl::flat_hash_map< Tags, Record< Type > >;
|
||||
|
||||
template < typename Type >
|
||||
struct TaggedRecords
|
||||
{
|
||||
Id id;
|
||||
TaggedRecordsData< Type > data;
|
||||
|
||||
explicit TaggedRecords(const Id &_id) : id(_id)
|
||||
{
|
||||
}
|
||||
|
||||
TaggedRecords(const Id &_id, const TaggedRecordsData< Type > &_data)
|
||||
: id(_id), data(_data)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
print(std::ostream &stream, int level, int spaces) const
|
||||
{
|
||||
Printer printer(stream, level, spaces);
|
||||
printer.printAttribute("id", id);
|
||||
printer.printAttribute("data", data);
|
||||
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
template < typename Value >
|
||||
bool
|
||||
operator==(const TaggedRecords< Value > &lhs,
|
||||
const TaggedRecords< Value > &rhs)
|
||||
{
|
||||
return std::tie(lhs.id, lhs.data) == std::tie(rhs.id, rhs.data);
|
||||
}
|
||||
|
||||
template < typename Value >
|
||||
std::ostream &
|
||||
operator<<(std::ostream &stream, const TaggedRecords< Value > &rec)
|
||||
{
|
||||
return rec.print(stream, -1, -1);
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
class SampleGroup
|
||||
{
|
||||
absl::Span< const Record< Type > > m_records;
|
||||
absl::Duration m_samplePeriod;
|
||||
|
||||
public:
|
||||
using RecordType = Record< Type >;
|
||||
using RecordType = TaggedRecords< Type >;
|
||||
using const_iterator =
|
||||
typename absl::Span< const RecordType >::const_iterator;
|
||||
|
||||
private:
|
||||
absl::Span< const RecordType > m_records;
|
||||
absl::Duration m_samplePeriod;
|
||||
|
||||
public:
|
||||
SampleGroup() : m_records(), m_samplePeriod()
|
||||
{
|
||||
}
|
||||
|
@ -593,7 +627,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
template<typename Type>
|
||||
void pushGroup(const Record<Type> *records, size_t size, absl::Duration duration) {
|
||||
void pushGroup(const TaggedRecords< Type > *records, size_t size, absl::Duration duration) {
|
||||
if (size != 0) {
|
||||
m_samples.emplace_back(SampleGroup<Type>(records, size, duration));
|
||||
m_recordCount += size;
|
||||
|
@ -601,7 +635,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
template<typename Type>
|
||||
void pushGroup(const absl::Span< const Record<Type> > &records,absl::Duration duration) {
|
||||
void pushGroup(const absl::Span< const TaggedRecords< Type > > &records,absl::Duration duration) {
|
||||
if (!records.empty()) {
|
||||
m_samples.emplace_back(SampleGroup<Type>(records, duration));
|
||||
m_recordCount += records.size();
|
||||
|
@ -626,35 +660,19 @@ namespace llarp
|
|||
// 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(); });
|
||||
return absl::visit([](const auto &x) { return x.samplePeriod(); }, group);
|
||||
}
|
||||
|
||||
inline size_t
|
||||
sampleSize(
|
||||
const absl::variant< SampleGroup< double >, SampleGroup< int > > &group)
|
||||
{
|
||||
return forSampleGroup(group, [](const auto &x) { return x.size(); });
|
||||
return absl::visit([](const auto &x) { return x.size(); }, group);
|
||||
}
|
||||
|
||||
} // namespace metrics
|
||||
} // namespace llarp
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ namespace llarp
|
|||
|
||||
void
|
||||
OStreamLogStream::PreLog(std::stringstream& ss, LogLevel lvl,
|
||||
const char* fname, int lineno) const
|
||||
const char* fname, int lineno,
|
||||
const std::string& nodename) const
|
||||
{
|
||||
switch(lvl)
|
||||
{
|
||||
|
@ -17,23 +18,20 @@ namespace llarp
|
|||
break;
|
||||
case eLogDebug:
|
||||
ss << (char)27 << "[0m";
|
||||
ss << "[DBG] ";
|
||||
break;
|
||||
case eLogInfo:
|
||||
ss << (char)27 << "[1m";
|
||||
ss << "[NFO] ";
|
||||
break;
|
||||
case eLogWarn:
|
||||
ss << (char)27 << "[1;33m";
|
||||
ss << "[WRN] ";
|
||||
break;
|
||||
case eLogError:
|
||||
ss << (char)27 << "[1;31m";
|
||||
ss << "[ERR] ";
|
||||
break;
|
||||
}
|
||||
|
||||
ss << "(" << thread_id_string() << ") " << log_timestamp() << " " << fname
|
||||
ss << "[" << LogLevelToString(lvl) << "] ";
|
||||
ss << "[" << nodename << "]"
|
||||
<< "(" << thread_id_string() << ") " << log_timestamp() << " " << fname
|
||||
<< ":" << lineno << "\t";
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
virtual void
|
||||
PreLog(std::stringstream& s, LogLevel lvl, const char* fname,
|
||||
int lineno) const override;
|
||||
PreLog(std::stringstream& s, LogLevel lvl, const char* fname, int lineno,
|
||||
const std::string& nodename) const override;
|
||||
|
||||
void
|
||||
Print(LogLevel lvl, const char* tag, const std::string& msg) override;
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
|
||||
#include <util/string_view.hpp>
|
||||
#include <util/traits.hpp>
|
||||
#include <util/variant.hpp>
|
||||
|
||||
#include <absl/types/variant.h>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -195,6 +197,11 @@ namespace llarp
|
|||
printType(std::ostream& stream, const std::tuple< Types... >& value,
|
||||
int level, int spaces, traits::select::Case<>);
|
||||
|
||||
template < typename... Types >
|
||||
static void
|
||||
printType(std::ostream& stream, const absl::variant< Types... >& value,
|
||||
int level, int spaces, traits::select::Case<>);
|
||||
|
||||
// Default type
|
||||
template < typename Type >
|
||||
static void
|
||||
|
@ -486,6 +493,17 @@ namespace llarp
|
|||
[&](const auto& x) { print.printValue(x); });
|
||||
}
|
||||
|
||||
template < typename... Types >
|
||||
inline void
|
||||
PrintHelper::printType(std::ostream& stream,
|
||||
const absl::variant< Types... >& value, int level,
|
||||
int spaces, traits::select::Case<>)
|
||||
{
|
||||
Printer print(stream, level, spaces);
|
||||
|
||||
absl::visit([&](const auto& x) { print.printValue(x); }, value);
|
||||
}
|
||||
|
||||
template < typename Type >
|
||||
inline void
|
||||
PrintHelper::printType(std::ostream& stream, const Type& value, int level,
|
||||
|
|
|
@ -6,27 +6,11 @@ namespace llarp
|
|||
{
|
||||
void
|
||||
SysLogStream::PreLog(std::stringstream& ss, LogLevel lvl, const char* fname,
|
||||
int lineno) const
|
||||
int lineno, const std::string& nodename) const
|
||||
{
|
||||
switch(lvl)
|
||||
{
|
||||
case eLogNone:
|
||||
break;
|
||||
case eLogDebug:
|
||||
ss << "[DBG] ";
|
||||
break;
|
||||
case eLogInfo:
|
||||
ss << "[NFO] ";
|
||||
break;
|
||||
case eLogWarn:
|
||||
ss << "[WRN] ";
|
||||
break;
|
||||
case eLogError:
|
||||
ss << "[ERR] ";
|
||||
break;
|
||||
}
|
||||
|
||||
ss << "(" << thread_id_string() << ") " << log_timestamp() << " " << fname
|
||||
ss << "[" << LogLevelToString(lvl) << "] ";
|
||||
ss << "[" << nodename << "]"
|
||||
<< "(" << thread_id_string() << ") " << log_timestamp() << " " << fname
|
||||
<< ":" << lineno << "\t";
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,8 @@ namespace llarp
|
|||
if(s > 0)
|
||||
lastSend = parent->Now();
|
||||
|
||||
METRICS_DYNAMIC_INT_UPDATE(
|
||||
"utp.session.tx", RouterID(remoteRC.pubkey).ToString().c_str(), s);
|
||||
metrics::integerTick("utp.session.tx", "writes", s, "id",
|
||||
RouterID(remoteRC.pubkey).ToString());
|
||||
m_TXRate += s;
|
||||
size_t sz = s;
|
||||
while(vecq.size() && sz >= vecq.front().iov_len)
|
||||
|
@ -133,9 +133,8 @@ namespace llarp
|
|||
PruneInboundMessages(now);
|
||||
m_TXRate = 0;
|
||||
m_RXRate = 0;
|
||||
METRICS_DYNAMIC_UPDATE("utp.session.sendq",
|
||||
RouterID(remoteRC.pubkey).ToString().c_str(),
|
||||
sendq.size());
|
||||
metrics::integerTick("utp.session.sendq", "size", sendq.size(), "id",
|
||||
RouterID(remoteRC.pubkey).ToString());
|
||||
}
|
||||
|
||||
/// low level read
|
||||
|
@ -146,8 +145,8 @@ namespace llarp
|
|||
Alive();
|
||||
m_RXRate += sz;
|
||||
size_t s = sz;
|
||||
METRICS_DYNAMIC_INT_UPDATE(
|
||||
"utp.session.rx", RouterID(remoteRC.pubkey).ToString().c_str(), s);
|
||||
metrics::integerTick("utp.session.rx", "size", s, "id",
|
||||
RouterID(remoteRC.pubkey).ToString());
|
||||
// process leftovers
|
||||
if(recvBufOffset)
|
||||
{
|
||||
|
|
|
@ -4,25 +4,30 @@
|
|||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace llarp;
|
||||
using namespace metrics;
|
||||
|
||||
TEST(MetricsPublisher, StreamPublisher)
|
||||
{
|
||||
metrics::Category myCategory("MyCategory");
|
||||
metrics::Description descA(&myCategory, "MetricA");
|
||||
metrics::Description descB(&myCategory, "MetricB");
|
||||
Category myCategory("MyCategory");
|
||||
Description descA(&myCategory, "MetricA");
|
||||
Description descB(&myCategory, "MetricB");
|
||||
|
||||
metrics::Id metricA(&descA);
|
||||
metrics::Id metricB(&descB);
|
||||
Id metricA(&descA);
|
||||
Id metricB(&descB);
|
||||
|
||||
std::stringstream stream;
|
||||
metrics::StreamPublisher myPublisher(stream);
|
||||
StreamPublisher myPublisher(stream);
|
||||
|
||||
std::vector< metrics::Record< double > > records;
|
||||
std::vector< TaggedRecords< double > > records;
|
||||
|
||||
records.emplace_back(metricA, 5, 25.0, 6.0, 25.0);
|
||||
records.emplace_back(metricB, 2, 7.0, 3.0, 11.0);
|
||||
records.emplace_back(
|
||||
metricA,
|
||||
TaggedRecordsData< double >{{{}, Record< double >(5, 25.0, 6.0, 25.0)}});
|
||||
records.emplace_back(
|
||||
metricB,
|
||||
TaggedRecordsData< double >{{{}, Record< double >(2, 7.0, 3.0, 11.0)}});
|
||||
|
||||
metrics::Sample sample;
|
||||
Sample sample;
|
||||
sample.sampleTime(absl::Now());
|
||||
sample.pushGroup(records.data(), records.size(), absl::Seconds(5));
|
||||
|
||||
|
|
|
@ -41,66 +41,60 @@ TYPED_TEST_P(CollectorTest, Collector)
|
|||
ASSERT_EQ(METRIC_A, collector1.id().description());
|
||||
ASSERT_EQ(METRIC_B, collector2.id().description());
|
||||
|
||||
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(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
|
||||
auto record1 = collector1.load();
|
||||
ASSERT_EQ(METRIC_A, record1.id.description());
|
||||
ASSERT_THAT(record1.data, IsEmpty());
|
||||
|
||||
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(TypeParam::RecordType::DEFAULT_MIN(), record2.min());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record2.max());
|
||||
auto record2 = collector2.load();
|
||||
ASSERT_EQ(METRIC_B, record2.id.description());
|
||||
ASSERT_THAT(record2.data, IsEmpty());
|
||||
|
||||
const Tags tags;
|
||||
|
||||
collector1.tick(1);
|
||||
record1 = collector1.load();
|
||||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(1, record1.count());
|
||||
ASSERT_EQ(1, record1.total());
|
||||
ASSERT_EQ(1, record1.min());
|
||||
ASSERT_EQ(1, record1.max());
|
||||
ASSERT_EQ(METRIC_A, record1.id.description());
|
||||
ASSERT_THAT(record1.data, Contains(Key(tags)));
|
||||
ASSERT_EQ(1, record1.data.at(tags).count());
|
||||
ASSERT_EQ(1, record1.data.at(tags).total());
|
||||
ASSERT_EQ(1, record1.data.at(tags).min());
|
||||
ASSERT_EQ(1, record1.data.at(tags).max());
|
||||
|
||||
collector1.tick(2);
|
||||
record1 = collector1.load();
|
||||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(2, record1.count());
|
||||
ASSERT_EQ(3, record1.total());
|
||||
ASSERT_EQ(1, record1.min());
|
||||
ASSERT_EQ(2, record1.max());
|
||||
ASSERT_EQ(METRIC_A, record1.id.description());
|
||||
ASSERT_THAT(record1.data, Contains(Key(tags)));
|
||||
ASSERT_EQ(2, record1.data.at(tags).count());
|
||||
ASSERT_EQ(3, record1.data.at(tags).total());
|
||||
ASSERT_EQ(1, record1.data.at(tags).min());
|
||||
ASSERT_EQ(2, record1.data.at(tags).max());
|
||||
|
||||
collector1.tick(-5);
|
||||
record1 = collector1.load();
|
||||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(3, record1.count());
|
||||
ASSERT_EQ(-2, record1.total());
|
||||
ASSERT_EQ(-5, record1.min());
|
||||
ASSERT_EQ(2, record1.max());
|
||||
ASSERT_EQ(METRIC_A, record1.id.description());
|
||||
ASSERT_THAT(record1.data, Contains(Key(tags)));
|
||||
ASSERT_EQ(3, record1.data.at(tags).count());
|
||||
ASSERT_EQ(-2, record1.data.at(tags).total());
|
||||
ASSERT_EQ(-5, record1.data.at(tags).min());
|
||||
ASSERT_EQ(2, record1.data.at(tags).max());
|
||||
|
||||
collector1.clear();
|
||||
record1 = collector1.load();
|
||||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(0, record1.count());
|
||||
ASSERT_EQ(0, record1.total());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
|
||||
ASSERT_EQ(METRIC_A, record1.id.description());
|
||||
ASSERT_THAT(record1.data, IsEmpty());
|
||||
|
||||
collector1.tick(3);
|
||||
record1 = collector1.loadAndClear();
|
||||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(1, record1.count());
|
||||
ASSERT_EQ(3, record1.total());
|
||||
ASSERT_EQ(3, record1.min());
|
||||
ASSERT_EQ(3, record1.max());
|
||||
ASSERT_EQ(METRIC_A, record1.id.description());
|
||||
ASSERT_THAT(record1.data, Contains(Key(tags)));
|
||||
ASSERT_EQ(1, record1.data.at(tags).count());
|
||||
ASSERT_EQ(3, record1.data.at(tags).total());
|
||||
ASSERT_EQ(3, record1.data.at(tags).min());
|
||||
ASSERT_EQ(3, record1.data.at(tags).max());
|
||||
|
||||
record1 = collector1.load();
|
||||
ASSERT_EQ(METRIC_A, record1.id().description());
|
||||
ASSERT_EQ(0, record1.count());
|
||||
ASSERT_EQ(0, record1.total());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
|
||||
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
|
||||
ASSERT_EQ(METRIC_A, record1.id.description());
|
||||
ASSERT_THAT(record1.data, IsEmpty());
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(CollectorTest, Collector);
|
||||
|
@ -198,8 +192,8 @@ TEST(MetricsCore, RegistryOps)
|
|||
ASSERT_TRUE(id.valid()) << id;
|
||||
ASSERT_NE(nullptr, id.description());
|
||||
ASSERT_NE(nullptr, id.category());
|
||||
ASSERT_STREQ(id.metricName(), NAME);
|
||||
ASSERT_STREQ(id.categoryName(), CATEGORY);
|
||||
ASSERT_EQ(id.metricName(), NAME);
|
||||
ASSERT_EQ(id.categoryName(), CATEGORY);
|
||||
ASSERT_TRUE(id.category()->enabled());
|
||||
|
||||
// Attempt to find the id.
|
||||
|
@ -224,7 +218,7 @@ TEST(MetricsCore, RegistryOps)
|
|||
|
||||
const Category *NEW_CAT = registry.add("NewCategory");
|
||||
ASSERT_NE(nullptr, NEW_CAT);
|
||||
ASSERT_STREQ("NewCategory", NEW_CAT->name());
|
||||
ASSERT_EQ("NewCategory", NEW_CAT->name());
|
||||
ASSERT_TRUE(NEW_CAT->enabled());
|
||||
}
|
||||
|
||||
|
@ -238,7 +232,7 @@ TEST(MetricsCore, RegistryOps)
|
|||
|
||||
const Category *cat = registry.add(CATEGORY);
|
||||
ASSERT_NE(nullptr, cat);
|
||||
ASSERT_STREQ(cat->name(), CATEGORY);
|
||||
ASSERT_EQ(cat->name(), CATEGORY);
|
||||
ASSERT_TRUE(cat->enabled());
|
||||
|
||||
ASSERT_EQ(nullptr, registry.add(CATEGORY));
|
||||
|
@ -247,8 +241,8 @@ TEST(MetricsCore, RegistryOps)
|
|||
Id id = registry.add(CATEGORY, "Metric");
|
||||
ASSERT_TRUE(id.valid());
|
||||
ASSERT_EQ(cat, id.category());
|
||||
ASSERT_STREQ(id.categoryName(), CATEGORY);
|
||||
ASSERT_STREQ(id.metricName(), "Metric");
|
||||
ASSERT_EQ(id.categoryName(), CATEGORY);
|
||||
ASSERT_EQ(id.metricName(), "Metric");
|
||||
|
||||
ASSERT_EQ(i + 1, registry.metricCount());
|
||||
ASSERT_EQ(i + 1, registry.categoryCount());
|
||||
|
@ -260,12 +254,13 @@ MATCHER_P6(RecordEq, category, name, count, total, min, max, "")
|
|||
{
|
||||
// clang-format off
|
||||
return (
|
||||
arg.id().categoryName() == std::string(category) &&
|
||||
arg.id().metricName() == std::string(name) &&
|
||||
arg.count() == count &&
|
||||
arg.total() == total &&
|
||||
arg.min() == min &&
|
||||
arg.max() == max
|
||||
arg.id.categoryName() == std::string(category) &&
|
||||
arg.id.metricName() == std::string(name) &&
|
||||
arg.data.find(Tags()) != arg.data.end() &&
|
||||
arg.data.at(Tags()).count() == count &&
|
||||
arg.data.at(Tags()).total() == total &&
|
||||
arg.data.at(Tags()).min() == min &&
|
||||
arg.data.at(Tags()).max() == max
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
@ -274,11 +269,11 @@ MATCHER_P5(RecordEq, id, count, total, min, max, "")
|
|||
{
|
||||
// clang-format off
|
||||
return (
|
||||
arg.id() == id &&
|
||||
arg.count() == count &&
|
||||
arg.total() == total &&
|
||||
arg.min() == min &&
|
||||
arg.max() == max
|
||||
arg.id == id &&
|
||||
arg.data.at(Tags()).count() == count &&
|
||||
arg.data.at(Tags()).total() == total &&
|
||||
arg.data.at(Tags()).min() == min &&
|
||||
arg.data.at(Tags()).max() == max
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
@ -287,10 +282,10 @@ MATCHER_P4(RecordEq, count, total, min, max, "")
|
|||
{
|
||||
// clang-format off
|
||||
return (
|
||||
arg.count() == count &&
|
||||
arg.total() == total &&
|
||||
arg.min() == min &&
|
||||
arg.max() == max
|
||||
arg.data.at(Tags()).count() == count &&
|
||||
arg.data.at(Tags()).total() == total &&
|
||||
arg.data.at(Tags()).min() == min &&
|
||||
arg.data.at(Tags()).max() == max
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
@ -299,11 +294,11 @@ MATCHER_P5(RecordCatEq, category, count, total, min, max, "")
|
|||
{
|
||||
// clang-format off
|
||||
return (
|
||||
arg.id().categoryName() == std::string(category) &&
|
||||
arg.count() == count &&
|
||||
arg.total() == total &&
|
||||
arg.min() == min &&
|
||||
arg.max() == max
|
||||
arg.id.categoryName() == std::string(category) &&
|
||||
arg.data.at(Tags()).count() == count &&
|
||||
arg.data.at(Tags()).total() == total &&
|
||||
arg.data.at(Tags()).min() == min &&
|
||||
arg.data.at(Tags()).max() == max
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
@ -323,7 +318,7 @@ TEST(MetricsCore, RepoBasic)
|
|||
collector1->tick(2.0);
|
||||
collector2->tick(4.0);
|
||||
|
||||
std::vector< Record< double > > records =
|
||||
std::vector< TaggedRecords< double > > records =
|
||||
repo.collectAndClear(registry.get("Test"));
|
||||
EXPECT_THAT(records, SizeIs(2));
|
||||
// clang-format off
|
||||
|
@ -379,9 +374,9 @@ TEST(MetricsCore, RepoCollect)
|
|||
const char *CATEGORY = CATEGORIES[i];
|
||||
const Category *category = registry.get(CATEGORY);
|
||||
|
||||
std::vector< Record< int > > records = repo.collect(category);
|
||||
std::vector< TaggedRecords< int > > records = repo.collect(category);
|
||||
|
||||
ASSERT_THAT(records, SizeIs(static_cast< int >(METRICS.size())));
|
||||
ASSERT_THAT(records, SizeIs(METRICS.size()));
|
||||
// clang-format off
|
||||
ASSERT_THAT(
|
||||
records,
|
||||
|
@ -401,8 +396,9 @@ TEST(MetricsCore, RepoCollect)
|
|||
auto collectors = repo.allCollectors(metric);
|
||||
for(int k = 0; k < static_cast< int >(collectors.size()); ++k)
|
||||
{
|
||||
Record< int > EI(metric, j, 2 * j, -j, j);
|
||||
Record< int > record = collectors[k]->load();
|
||||
TaggedRecords< int > EI(metric);
|
||||
EI.data[Tags()] = Record< int >(j, 2 * j, -j, j);
|
||||
TaggedRecords< int > record = collectors[k]->load();
|
||||
ASSERT_EQ(record, EI);
|
||||
}
|
||||
}
|
||||
|
@ -424,7 +420,7 @@ TEST(MetricsCore, RepoCollect)
|
|||
|
||||
for(int l = 0; l < static_cast< int >(collectors.size()); ++l)
|
||||
{
|
||||
Record< int > record = collectors[k]->load();
|
||||
TaggedRecords< int > record = collectors[k]->load();
|
||||
ASSERT_THAT(record, RecordEq(metric, 100u, 100, 100, 100));
|
||||
}
|
||||
}
|
||||
|
@ -444,15 +440,17 @@ const Category *
|
|||
firstCategory(
|
||||
const absl::variant< SampleGroup< double >, SampleGroup< int > > &g)
|
||||
{
|
||||
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;
|
||||
});
|
||||
return absl::visit(
|
||||
[](const auto &group) -> const Category * {
|
||||
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;
|
||||
},
|
||||
g);
|
||||
}
|
||||
|
||||
TEST(MetricsCore, ManagerCollectSample1)
|
||||
|
@ -496,8 +494,8 @@ TEST(MetricsCore, ManagerCollectSample1)
|
|||
WithinWindow(window, absl::Milliseconds(10)))
|
||||
<< group;
|
||||
|
||||
const char *name = group.records()[0].id().categoryName();
|
||||
for(const Record< double > &record : group.records())
|
||||
string_view name = group.records()[0].id.categoryName();
|
||||
for(const auto &record : group.records())
|
||||
{
|
||||
ASSERT_THAT(record, RecordCatEq(name, 1u, 1, 1, 1));
|
||||
}
|
||||
|
@ -506,8 +504,8 @@ TEST(MetricsCore, ManagerCollectSample1)
|
|||
{
|
||||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
auto record = col->load();
|
||||
ASSERT_THAT(record, RecordEq(1u, 1, 1, 1));
|
||||
}
|
||||
}
|
||||
|
@ -524,9 +522,9 @@ TEST(MetricsCore, ManagerCollectSample1)
|
|||
{
|
||||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
ASSERT_EQ(Record< double >(record.id()), record);
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
auto record = col->load();
|
||||
ASSERT_EQ(TaggedRecords< double >(record.id), record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,7 +589,7 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
TaggedRecords< double > record = col->load();
|
||||
ASSERT_THAT(record, RecordEq(1u, 1, 1, 1));
|
||||
}
|
||||
}
|
||||
|
@ -623,10 +621,10 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
for(size_t j = 0; j < NUM_METRICS; ++j)
|
||||
{
|
||||
DoubleCollector *col = rep.defaultCollector(CATEGORIES[i], METRICS[j]);
|
||||
Record< double > record = col->load();
|
||||
TaggedRecords< double > record = col->load();
|
||||
if(combIt.includesElement(i))
|
||||
{
|
||||
ASSERT_EQ(Record< double >(record.id()), record);
|
||||
ASSERT_EQ(TaggedRecords< double >(record.id), record);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -641,8 +639,8 @@ TEST(MetricsCore, ManagerCollectSample2)
|
|||
struct MockPublisher : public Publisher
|
||||
{
|
||||
std::atomic_int invocations;
|
||||
std::vector< Record< double > > recordBuffer;
|
||||
std::vector< Record< double > > sortedRecords;
|
||||
std::vector< TaggedRecords< double > > recordBuffer;
|
||||
std::vector< TaggedRecords< double > > sortedRecords;
|
||||
Sample m_sample;
|
||||
|
||||
std::set< absl::Duration > times;
|
||||
|
@ -673,7 +671,7 @@ struct MockPublisher : public Publisher
|
|||
auto git = s.begin();
|
||||
ASSERT_NE(git, s.end());
|
||||
recordBuffer.push_back(*git);
|
||||
Record< double > *head = &recordBuffer.back();
|
||||
TaggedRecords< double > *head = &recordBuffer.back();
|
||||
for(++git; git != s.end(); ++git)
|
||||
{
|
||||
recordBuffer.push_back(*git);
|
||||
|
@ -683,9 +681,8 @@ struct MockPublisher : public Publisher
|
|||
}
|
||||
|
||||
sortedRecords = recordBuffer;
|
||||
std::sort(
|
||||
sortedRecords.begin(), sortedRecords.end(),
|
||||
[](const auto &lhs, const auto &rhs) { return lhs.id() < rhs.id(); });
|
||||
std::sort(sortedRecords.begin(), sortedRecords.end(),
|
||||
[](const auto &lhs, const auto &rhs) { return lhs.id < rhs.id; });
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -701,16 +698,16 @@ struct MockPublisher : public Publisher
|
|||
int
|
||||
indexOf(const Id &id)
|
||||
{
|
||||
Record< double > searchRecord(id);
|
||||
TaggedRecords< double > searchRecord(id);
|
||||
auto it = std::lower_bound(
|
||||
sortedRecords.begin(), sortedRecords.end(), searchRecord,
|
||||
[](const auto &lhs, const auto &rhs) { return lhs.id() < rhs.id(); });
|
||||
[](const auto &lhs, const auto &rhs) { return lhs.id < rhs.id; });
|
||||
|
||||
if(it == sortedRecords.end())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (it->id() == id) ? it - sortedRecords.begin() : -1;
|
||||
return (it->id == id) ? it - sortedRecords.begin() : -1;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
#include <gmock/gmock.h>
|
||||
|
||||
using namespace llarp;
|
||||
using namespace metrics;
|
||||
using namespace ::testing;
|
||||
|
||||
using RecordT = metrics::Record< double >;
|
||||
using TagRecordT = metrics::TaggedRecords< double >;
|
||||
using SampleGroupT = metrics::SampleGroup< double >;
|
||||
|
||||
struct MetricFormatSpecTestData
|
||||
|
@ -60,11 +62,11 @@ TEST(MetricsTypes, Format)
|
|||
ASSERT_EQ(nullptr, format.specFor(metrics::Publication::Type::Avg));
|
||||
auto ptr = format.specFor(metrics::Publication::Type::Total);
|
||||
ASSERT_NE(nullptr, ptr);
|
||||
ASSERT_STREQ("%0.3f", ptr->m_format);
|
||||
ASSERT_EQ("%0.3f", ptr->m_format);
|
||||
ASSERT_DOUBLE_EQ(2.0, ptr->m_scale);
|
||||
ptr = format.specFor(metrics::Publication::Type::Max);
|
||||
ASSERT_NE(nullptr, ptr);
|
||||
ASSERT_STREQ("%0.2f", ptr->m_format);
|
||||
ASSERT_EQ("%0.2f", ptr->m_format);
|
||||
ASSERT_DOUBLE_EQ(1.0, ptr->m_scale);
|
||||
|
||||
format.clear();
|
||||
|
@ -149,13 +151,17 @@ TEST(MetricsTypes, Sample)
|
|||
metrics::Id metricC(&descC);
|
||||
|
||||
absl::Time timeStamp = absl::Now();
|
||||
RecordT recordA(metricA, 0, 0, 0, 0);
|
||||
RecordT recordB(metricB, 1, 2, 3, 4);
|
||||
RecordT recordC(metricC, 4, 3, 2, 1);
|
||||
RecordT recordA(0, 0, 0, 0);
|
||||
RecordT recordB(1, 2, 3, 4);
|
||||
RecordT recordC(4, 3, 2, 1);
|
||||
|
||||
RecordT buffer1[] = {recordA, recordB};
|
||||
std::vector< RecordT > buffer2;
|
||||
buffer2.push_back(recordC);
|
||||
TagRecordT tagRecordA(metricA, {{{}, recordA}});
|
||||
TagRecordT tagRecordB(metricB, {{{}, recordB}});
|
||||
TagRecordT tagRecordC(metricC, {{{}, recordC}});
|
||||
|
||||
TagRecordT buffer1[] = {tagRecordA, tagRecordB};
|
||||
std::vector< TagRecordT > buffer2;
|
||||
buffer2.push_back(tagRecordC);
|
||||
|
||||
metrics::Sample sample;
|
||||
sample.sampleTime(timeStamp);
|
||||
|
@ -209,7 +215,7 @@ struct SampleTest
|
|||
metrics::Id id_F;
|
||||
metrics::Id id_G;
|
||||
|
||||
std::vector< RecordT > recordBuffer;
|
||||
std::vector< TagRecordT > recordBuffer;
|
||||
|
||||
SampleTest()
|
||||
: cat_A("A", true)
|
||||
|
@ -228,29 +234,47 @@ struct SampleTest
|
|||
, id_F(&DESC_F)
|
||||
, id_G(&DESC_G)
|
||||
{
|
||||
recordBuffer.emplace_back(metrics::Id(0), 1, 1, 1, 1);
|
||||
recordBuffer.emplace_back(id_A, 2, 2, 2, 2);
|
||||
recordBuffer.emplace_back(id_B, 3, 3, 3, 3);
|
||||
recordBuffer.emplace_back(id_C, 4, 4, 4, 4);
|
||||
recordBuffer.emplace_back(id_D, 5, 5, 5, 5);
|
||||
recordBuffer.emplace_back(id_E, 6, 6, 6, 6);
|
||||
recordBuffer.emplace_back(id_F, 7, 7, 7, 7);
|
||||
recordBuffer.emplace_back(id_G, 8, 8, 8, 8);
|
||||
recordBuffer.emplace_back(id_A, 9, 9, 9, 9);
|
||||
recordBuffer.emplace_back(
|
||||
metrics::Id(0),
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(1, 1, 1, 1)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_A,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(2, 2, 2, 2)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_B,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(3, 3, 3, 3)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_C,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(4, 4, 4, 4)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_D,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(5, 5, 5, 5)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_E,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(6, 6, 6, 6)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_F,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(7, 7, 7, 7)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_G,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(8, 8, 8, 8)}});
|
||||
recordBuffer.emplace_back(
|
||||
id_A,
|
||||
TaggedRecordsData< double >{{metrics::Tags(), RecordT(9, 9, 9, 9)}});
|
||||
}
|
||||
};
|
||||
|
||||
std::pair< std::vector< metrics::SampleGroup< double > >, size_t >
|
||||
generate(const std::string &specification,
|
||||
const std::vector< RecordT > &recordBuffer)
|
||||
const std::vector< TagRecordT > &recordBuffer)
|
||||
{
|
||||
const char *c = specification.c_str();
|
||||
|
||||
std::vector< metrics::SampleGroup< double > > groups;
|
||||
size_t size = 0;
|
||||
|
||||
const RecordT *head = recordBuffer.data();
|
||||
const RecordT *current = head;
|
||||
const TagRecordT *head = recordBuffer.data();
|
||||
const TagRecordT *current = head;
|
||||
while(*c)
|
||||
{
|
||||
int numRecords = *(c + 1) - '0';
|
||||
|
|
Loading…
Reference in New Issue