2019-09-01 12:58:27 +00:00
|
|
|
#include <util/metrics/stream_publisher.hpp>
|
2019-02-27 21:46:23 +00:00
|
|
|
|
2019-04-07 17:54:33 +00:00
|
|
|
#include <fstream>
|
2019-02-27 21:46:23 +00:00
|
|
|
#include <iostream>
|
2019-04-08 12:05:54 +00:00
|
|
|
#include <iomanip>
|
2019-02-27 21:46:23 +00:00
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
namespace metrics
|
|
|
|
{
|
|
|
|
namespace
|
|
|
|
{
|
2019-04-10 11:53:37 +00:00
|
|
|
template < typename Value >
|
2019-02-27 21:46:23 +00:00
|
|
|
void
|
2019-04-10 11:53:37 +00:00
|
|
|
formatValue(std::ostream &stream, Value value,
|
2019-02-27 21:46:23 +00:00
|
|
|
const FormatSpec *formatSpec)
|
|
|
|
{
|
|
|
|
if(formatSpec)
|
|
|
|
{
|
2019-04-10 11:53:37 +00:00
|
|
|
FormatSpec::format(stream, static_cast< double >(value), *formatSpec);
|
2019-02-27 21:46:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stream << value;
|
|
|
|
}
|
|
|
|
}
|
2019-04-07 17:54:33 +00:00
|
|
|
|
2019-06-11 20:46:51 +00:00
|
|
|
template < typename Value >
|
2019-02-27 21:46:23 +00:00
|
|
|
void
|
2019-06-11 20:46:51 +00:00
|
|
|
formatValue(std::ostream &stream, const Record< Value > &record,
|
2019-02-27 21:46:23 +00:00
|
|
|
double elapsedTime, Publication::Type publicationType,
|
|
|
|
const FormatSpec *formatSpec)
|
|
|
|
{
|
|
|
|
switch(publicationType)
|
|
|
|
{
|
|
|
|
case Publication::Type::Unspecified:
|
|
|
|
{
|
|
|
|
assert(false && "Invalid publication type");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Publication::Type::Total:
|
|
|
|
{
|
|
|
|
formatValue(stream, record.total(), formatSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Publication::Type::Count:
|
|
|
|
{
|
|
|
|
formatValue(stream, record.count(), formatSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Publication::Type::Min:
|
|
|
|
{
|
|
|
|
formatValue(stream, record.min(), formatSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Publication::Type::Max:
|
|
|
|
{
|
|
|
|
formatValue(stream, record.max(), formatSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Publication::Type::Avg:
|
|
|
|
{
|
|
|
|
formatValue(stream, record.total() / record.count(), formatSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Publication::Type::Rate:
|
|
|
|
{
|
|
|
|
formatValue(stream, record.total() / elapsedTime, formatSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Publication::Type::RateCount:
|
|
|
|
{
|
|
|
|
formatValue(stream, record.count() / elapsedTime, formatSpec);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-11 20:46:51 +00:00
|
|
|
template < typename Value >
|
2019-02-27 21:46:23 +00:00
|
|
|
void
|
2019-06-13 21:58:17 +00:00
|
|
|
publishRecord(std::ostream &stream,
|
|
|
|
const TaggedRecords< Value > &taggedRecords,
|
2019-02-27 21:46:23 +00:00
|
|
|
double elapsedTime)
|
|
|
|
{
|
2019-06-13 21:58:17 +00:00
|
|
|
auto publicationType = taggedRecords.id.description()->type();
|
2019-02-27 21:46:23 +00:00
|
|
|
std::shared_ptr< const Format > format =
|
2019-06-13 21:58:17 +00:00
|
|
|
taggedRecords.id.description()->format();
|
2019-02-27 21:46:23 +00:00
|
|
|
|
2019-06-13 21:58:17 +00:00
|
|
|
if(taggedRecords.data.empty())
|
2019-02-27 21:46:23 +00:00
|
|
|
{
|
2019-06-13 21:58:17 +00:00
|
|
|
return;
|
2019-02-27 21:46:23 +00:00
|
|
|
}
|
2019-06-13 21:58:17 +00:00
|
|
|
|
2019-06-13 21:58:17 +00:00
|
|
|
stream << "\t\t" << taggedRecords.id << " [";
|
2019-06-13 21:58:17 +00:00
|
|
|
|
|
|
|
for(const auto &rec : taggedRecords.data)
|
2019-02-27 21:46:23 +00:00
|
|
|
{
|
2019-06-13 21:58:17 +00:00
|
|
|
stream << "\n\t\t\t";
|
2019-06-13 21:58:17 +00:00
|
|
|
const auto &tags = rec.first;
|
|
|
|
const auto &record = rec.second;
|
2019-02-27 21:46:23 +00:00
|
|
|
|
|
|
|
{
|
2019-06-13 21:58:17 +00:00
|
|
|
Printer printer(stream, -1, -1);
|
|
|
|
printer.printValue(tags);
|
2019-02-27 21:46:23 +00:00
|
|
|
}
|
2019-06-13 21:58:17 +00:00
|
|
|
|
|
|
|
stream << " ";
|
|
|
|
|
|
|
|
if(publicationType != Publication::Type::Unspecified)
|
2019-02-27 21:46:23 +00:00
|
|
|
{
|
2019-06-13 21:58:17 +00:00
|
|
|
stream << Publication::repr(publicationType) << " = ";
|
|
|
|
const FormatSpec *formatSpec =
|
|
|
|
format ? format->specFor(publicationType) : nullptr;
|
|
|
|
|
|
|
|
formatValue(stream, record, elapsedTime, publicationType,
|
|
|
|
formatSpec);
|
2019-02-27 21:46:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-06-13 21:58:17 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-02-27 21:46:23 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-13 21:58:17 +00:00
|
|
|
stream << "\n\t\t]\n";
|
|
|
|
}
|
2019-02-27 21:46:23 +00:00
|
|
|
} // namespace
|
2019-04-07 17:54:33 +00:00
|
|
|
|
2019-02-27 21:46:23 +00:00
|
|
|
void
|
2019-06-11 20:46:51 +00:00
|
|
|
StreamPublisher::publish(const Sample &values)
|
2019-02-27 21:46:23 +00:00
|
|
|
{
|
2019-06-11 20:46:51 +00:00
|
|
|
if(values.recordCount() == 0)
|
2019-04-07 17:54:33 +00:00
|
|
|
{
|
|
|
|
// nothing to publish
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-11 20:46:51 +00:00
|
|
|
m_stream << values.sampleTime() << " " << values.recordCount()
|
2019-04-07 17:54:33 +00:00
|
|
|
<< " Records\n";
|
|
|
|
|
2019-06-11 20:46:51 +00:00
|
|
|
auto gIt = values.begin();
|
|
|
|
auto prev = values.begin();
|
|
|
|
for(; gIt != values.end(); ++gIt)
|
2019-02-27 21:46:23 +00:00
|
|
|
{
|
2019-06-11 20:46:51 +00:00
|
|
|
const double elapsedTime = absl::ToDoubleSeconds(samplePeriod(*gIt));
|
2019-02-27 21:46:23 +00:00
|
|
|
|
2019-06-11 20:46:51 +00:00
|
|
|
if(gIt == prev || samplePeriod(*gIt) != samplePeriod(*prev))
|
2019-02-27 21:46:23 +00:00
|
|
|
{
|
2019-04-07 17:54:33 +00:00
|
|
|
m_stream << "\tElapsed Time: " << elapsedTime << "s\n";
|
|
|
|
}
|
2019-02-27 21:46:23 +00:00
|
|
|
|
2019-06-13 21:58:17 +00:00
|
|
|
absl::visit(
|
|
|
|
[&](const auto &x) {
|
|
|
|
for(const auto &record : x)
|
|
|
|
{
|
|
|
|
publishRecord(m_stream, record, elapsedTime);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
*gIt);
|
2019-06-11 20:46:51 +00:00
|
|
|
|
2019-04-07 17:54:33 +00:00
|
|
|
prev = gIt;
|
|
|
|
}
|
|
|
|
}
|
2019-02-27 21:46:23 +00:00
|
|
|
} // namespace metrics
|
|
|
|
} // namespace llarp
|