Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions common/include/villas/table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <string>
#include <vector>

#include <fmt/printf.h>

#include <villas/log.hpp>

namespace villas {
Expand All @@ -26,12 +28,14 @@ class TableColumn {
protected:
int _width; // The real width of this column. Calculated by Table::resize().

int width; // Width of the column.
int width; // Width of the column.
int precision; // Precision of the column, used for floating point values.

public:
TableColumn(int w, enum Alignment a, const std::string &t,
TableColumn(int w, int p, enum Alignment a, const std::string &t,
const std::string &f, const std::string &u = "")
: _width(0), width(w), title(t), format(f), unit(u), align(a) {}
: _width(0), width(w), precision(p), title(t), format(f), unit(u),
align(a) {}

std::string title; // The title as shown in the table header.
std::string format; // The format which is used to print the table rows.
Expand All @@ -46,10 +50,11 @@ class Table {

protected:
int resize(int w);
void updateRowFormat();

int width;

std::vector<TableColumn> columns;
std::string rowFormat;

Logger logger;

Expand All @@ -61,7 +66,15 @@ class Table {
void header();

// Print table rows.
void row(int count, ...);
template <class... Args> void row(const Args &...args) {
auto logWidth = Log::getInstance().getWidth();
if (width != logWidth) {
resize(logWidth);
header();
}

logger->info(fmt::runtime(rowFormat), args...);
}

int getWidth() const { return width; }
};
Expand Down
8 changes: 4 additions & 4 deletions common/lib/hist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ void Hist::plot(Logger logger) const {
Hist::cnt_t max = *std::max_element(data.begin(), data.end());

std::vector<TableColumn> cols = {
{-9, TableColumn::Alignment::RIGHT, "Value", "%+9.3g"},
{-6, TableColumn::Alignment::RIGHT, "Count", "%6ju"},
{0, TableColumn::Alignment::LEFT, "Plot", "%s", "occurrences"}};
{-9, 3, TableColumn::Alignment::RIGHT, "Value", "g"},
{-6, -1, TableColumn::Alignment::RIGHT, "Count", "d"},
{0, -1, TableColumn::Alignment::LEFT, "Plot", "s", "occurrences"}};

Table table = Table(logger, cols);

Expand All @@ -147,7 +147,7 @@ void Hist::plot(Logger logger) const {
for (int i = 0; i < bar; i++)
buf = strcatf(&buf, "\u2588");

table.row(3, value, cnt, buf);
table.row(value, cnt, buf);

free(buf);
}
Expand Down
13 changes: 9 additions & 4 deletions common/lib/log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,15 @@ Log::Log(Level lvl) : level(lvl), pattern("%H:%M:%S %^%-4t%$ %-16n %v") {
}

int Log::getWidth() {
int width = Terminal::getCols() - 50;

if (!prefix.empty())
width -= prefix.length();
int width = Terminal::getCols();

width -= 8; // Timestamp
width -= 1; // Space
width -= 4; // Level
width -= 1; // Space
width -= 16; // Name
width -= 1; // Space
width -= prefix.length();

return width;
}
Expand Down
170 changes: 84 additions & 86 deletions common/lib/table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,118 +25,116 @@ using namespace villas::utils;
#endif

int Table::resize(int w) {
int norm, flex, fixed, total;

width = w;

norm = 0;
flex = 0;
fixed = 0;
total = width - columns.size() * 2;
float norm = 0;
float flex = 0;
float fixed = 0;
float total = width - columns.size() * 3; // Column separators and whitespace

// Normalize width
for (unsigned i = 0; i < columns.size(); i++) {
if (columns[i].width > 0)
norm += columns[i].width;
if (columns[i].width == 0)
for (auto &column : columns) {
if (column.width > 0) {
norm += column.width;
} else if (column.width == 0) {
flex++;
if (columns[i].width < 0)
fixed += -1 * columns[i].width;
} else if (column.width < 0) {
fixed += -1 * column.width;
}
}

for (unsigned i = 0; i < columns.size(); i++) {
if (columns[i].width > 0)
columns[i]._width = columns[i].width * (float)(total - fixed) / norm;
if (columns[i].width == 0)
columns[i]._width = (float)(total - fixed) / flex;
if (columns[i].width < 0)
columns[i]._width = -1 * columns[i].width;
int total_used = 0;

for (auto &column : columns) {
if (column.width > 0) {
column._width = column.width * (total - fixed) / norm;
} else if (column.width == 0) {
column._width = (total - fixed) / flex;
} else if (column.width < 0) {
column._width = -1 * column.width;
}

total_used += column._width;
}

// Distribute remaining space over flex columns
for (auto &column : columns) {
if (total_used >= total) {
break;
}

if (column.width >= 0) {
column._width++;
total_used++;
}
}

updateRowFormat();

return 0;
}

void Table::header() {
if (width != Log::getInstance().getWidth())
resize(Log::getInstance().getWidth());
void Table::updateRowFormat() {
rowFormat.clear();

char *line1 = nullptr;
char *line2 = nullptr;
char *line3 = nullptr;
for (unsigned i = 0; i < columns.size(); ++i) {
auto &column = columns[i];

for (unsigned i = 0; i < columns.size(); i++) {
int w, u;
char *col, *unit;

col = strf(CLR_BLD("%s"), columns[i].title.c_str());
unit = columns[i].unit.size() ? strf(CLR_YEL("%s"), columns[i].unit.c_str())
: strf("");

w = columns[i]._width + strlen(col) - strlenp(col);
u = columns[i]._width + strlen(unit) - strlenp(unit);

if (columns[i].align == TableColumn::Alignment::LEFT) {
strcatf(&line1, " %-*.*s" ANSI_RESET, w, w, col);
strcatf(&line2, " %-*.*s" ANSI_RESET, u, u, unit);
} else {
strcatf(&line1, " %*.*s" ANSI_RESET, w, w, col);
strcatf(&line2, " %*.*s" ANSI_RESET, u, u, unit);
}
rowFormat += " {:";
rowFormat += column.align == TableColumn::Alignment::LEFT ? "<" : ">";
rowFormat += std::to_string(column._width);

for (int j = 0; j < columns[i]._width + 2; j++) {
strcatf(&line3, "%s", BOX_LR);
if (column.precision >= 0) {
rowFormat += fmt::format(".{}", column.precision);
} else if (column.format == "s") {
rowFormat += fmt::format(".{}", column._width);
}

rowFormat += column.format;
rowFormat += "}";

if (i != columns.size() - 1) {
strcatf(&line1, " %s", BOX_UD);
strcatf(&line2, " %s", BOX_UD);
strcatf(&line3, "%s", BOX_UDLR);
rowFormat += BOX_UD;
}

free(col);
free(unit);
}

logger->info("{}", line1);
logger->info("{}", line2);
logger->info("{}", line3);

free(line1);
free(line2);
free(line3);
}

void Table::row(int count, ...) {
if (width != Log::getInstance().getWidth()) {
resize(Log::getInstance().getWidth());
header();
void Table::header() {
auto logWidth = Log::getInstance().getWidth();
if (width != logWidth) {
resize(logWidth);
}

va_list args;
va_start(args, count);

char *line = nullptr;

for (unsigned i = 0; i < columns.size(); ++i) {
char *col = vstrf(columns[i].format.c_str(), args);

int l = strlenp(col);
int r = strlen(col);
int w = columns[i]._width + r - l;
std::string line1;
std::string line2;
std::string line3;
line1.reserve(width);
line2.reserve(width);
line3.reserve(width);

Comment thread
n-eiling marked this conversation as resolved.
if (columns[i].align == TableColumn::Alignment::LEFT)
strcatf(&line, " %-*.*s " ANSI_RESET, w, w, col);
else
strcatf(&line, " %*.*s " ANSI_RESET, w, w, col);

if (i != columns.size() - 1)
strcatf(&line, BOX_UD);
for (unsigned i = 0; i < columns.size(); i++) {
auto &column = columns[i];

auto leftAligned = column.align == TableColumn::Alignment::LEFT;
line1 += fmt::format(leftAligned ? CLR_BLD(" {0:<{1}.{1}s}")
: CLR_BLD(" {0:>{1}.{1}s}"),
column.title, column._width);
line2 += fmt::format(leftAligned ? CLR_YEL(" {0:<{1}.{1}s}")
: CLR_YEL(" {0:>{1}.{1}s}"),
column.unit, column._width);

for (int j = 0; j < column._width + 2; j++) {
line3 += BOX_LR;
}

free(col);
if (i != columns.size() - 1) {
line1 += " " BOX_UD;
line2 += " " BOX_UD;
line3 += BOX_UDLR;
}
}

va_end(args);

logger->info("{}", line);
free(line);
logger->info("{}", line1);
logger->info("{}", line2);
logger->info("{}", line3);
}
25 changes: 14 additions & 11 deletions etc/examples/hooks/stats.conf
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University
# SPDX-License-Identifier: Apache-2.0

stats = 1

nodes = {
udp_node = {
type = "socket"
signal_node = {
type = "signal"
signal = "mixed"
values = 5
rate = 50

in = {
address = "*:12000"

hooks = (
{
type = "stats"

verbose = true
warmup = 100
warmup = 10
buckets = 25

output = "stats.log"
format = "json"
}
)
}
out = {
address = "127.0.0.1:12000"
}
}
}

paths = (
{
in = "signal_node"
}
)
26 changes: 13 additions & 13 deletions lib/stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,18 @@ std::unordered_map<Stats::Type, Stats::TypeDescription> Stats::types = {
{Stats::Type::TOTAL, {"total", SignalType::INTEGER}}};

std::vector<TableColumn> Stats::columns = {
{10, TableColumn::Alignment::LEFT, "Node", "%s"},
{10, TableColumn::Alignment::RIGHT, "Recv", "%ju", "pkts"},
{10, TableColumn::Alignment::RIGHT, "Sent", "%ju", "pkts"},
{10, TableColumn::Alignment::RIGHT, "Drop", "%ju", "pkts"},
{10, TableColumn::Alignment::RIGHT, "Skip", "%ju", "pkts"},
{10, TableColumn::Alignment::RIGHT, "OWD last", "%lf", "secs"},
{10, TableColumn::Alignment::RIGHT, "OWD mean", "%lf", "secs"},
{10, TableColumn::Alignment::RIGHT, "Rate last", "%lf", "pkt/sec"},
{10, TableColumn::Alignment::RIGHT, "Rate mean", "%lf", "pkt/sec"},
{10, TableColumn::Alignment::RIGHT, "Age mean", "%lf", "secs"},
{10, TableColumn::Alignment::RIGHT, "Age Max", "%lf", "sec"},
{8, TableColumn::Alignment::RIGHT, "Signals", "%ju", "signals"}};
{10, -1, TableColumn::Alignment::LEFT, "Node", "s"},
{10, -1, TableColumn::Alignment::RIGHT, "Recv", "d", "pkts"},
{10, -1, TableColumn::Alignment::RIGHT, "Sent", "d", "pkts"},
{10, -1, TableColumn::Alignment::RIGHT, "Drop", "d", "pkts"},
{10, -1, TableColumn::Alignment::RIGHT, "Skip", "d", "pkts"},
{10, -1, TableColumn::Alignment::RIGHT, "OWD last", "f", "secs"},
{10, -1, TableColumn::Alignment::RIGHT, "OWD mean", "f", "secs"},
{10, -1, TableColumn::Alignment::RIGHT, "Rate last", "f", "pkt/sec"},
{10, -1, TableColumn::Alignment::RIGHT, "Rate mean", "f", "pkt/sec"},
{10, -1, TableColumn::Alignment::RIGHT, "Age mean", "f", "secs"},
{10, -1, TableColumn::Alignment::RIGHT, "Age Max", "f", "sec"},
{-7, -1, TableColumn::Alignment::RIGHT, "Signals", "d", "signals"}};

enum Stats::Format Stats::lookupFormat(const std::string &str) {
if (str == "human")
Expand Down Expand Up @@ -142,7 +142,7 @@ void Stats::printPeriodic(FILE *f, enum Format fmt, node::Node *n) const {
switch (fmt) {
case Format::HUMAN:
setupTable();
table->row(11, n->getNameShort().c_str(),
table->row(n->getNameShort(),
(uintmax_t)histograms.at(Metric::OWD).getTotal(),
(uintmax_t)histograms.at(Metric::AGE).getTotal(),
(uintmax_t)histograms.at(Metric::SMPS_REORDERED).getTotal(),
Expand Down