diff --git a/lib/api/CMakeLists.txt b/lib/api/CMakeLists.txt index b52e3eee1..70974bdeb 100644 --- a/lib/api/CMakeLists.txt +++ b/lib/api/CMakeLists.txt @@ -26,6 +26,7 @@ set(API_SRC requests/node_stats.cpp requests/node_stats_reset.cpp requests/node_file.cpp + requests/metrics.cpp requests/paths.cpp requests/path_info.cpp requests/path_action.cpp diff --git a/lib/api/requests/metrics.cpp b/lib/api/requests/metrics.cpp new file mode 100644 index 000000000..66aa2575d --- /dev/null +++ b/lib/api/requests/metrics.cpp @@ -0,0 +1,77 @@ +/* The Prometheus metrics endpoint. + * + * Author: Youssef Nakti + * SPDX-FileCopyrightText: 2025 Institute for Automation of Complex Power Systems, RWTH Aachen University + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace villas { +namespace node { +namespace api { + +class MetricsRequest : public Request { +private: + std::unordered_map metrics_subset = { + {Stats::Metric::SMPS_SKIPPED, "skipped"}, + {Stats::Metric::OWD, "owd"}, + {Stats::Metric::AGE, "age"}, + {Stats::Metric::SIGNAL_COUNT, "signalcnt"}, + {Stats::Metric::RTP_PKTS_LOST, "rtp_pkts_lost"}}; + +public: + using Request::Request; + + virtual Response *execute() { + if (method != Session::Method::GET) + throw InvalidMethod(this); + + if (body != nullptr) + throw BadRequest("Nodes endpoint does not accept any body data"); + + std::string text_res = ""; + NodeList node_list = session->getSuperNode()->getNodes(); + for (Node *node : node_list) { + auto stats = node->getStats(); + if (!stats) + continue; + std::string node_name = node->getNameShort(); + for (auto &metric : metrics_subset) { + Hist histogram = stats->getHistogram(metric.first); + std::string t = std::to_string( + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count()); + + text_res += metric.second + " {node=\"" + node_name + + "\" acc=\"last\"} " + std::to_string(histogram.getLast()) + + " " + t + "\n"; + text_res += metric.second + " {node=\"" + node_name + + "\" acc=\"total\"} " + + std::to_string(histogram.getTotal()) + " " + t + "\n"; + } + } + + return new Response(session, HTTP_STATUS_OK, "text/plain; charset=UTF-8", + Buffer(text_res.c_str(), text_res.size())); + } +}; + +// Register API request +static char n[] = "metrics"; +static char r[] = "/metrics"; +static char d[] = "Get Prometheus metrics from all nodes"; +static RequestPlugin p; + +} // namespace api +} // namespace node +} // namespace villas diff --git a/tests/integration/api-metrics.sh b/tests/integration/api-metrics.sh new file mode 100755 index 000000000..84d673887 --- /dev/null +++ b/tests/integration/api-metrics.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# +# Integration test for remote API +# +# Author: Steffen Vogel +# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University +# SPDX-License-Identifier: Apache-2.0 + +set -e + +DIR=$(mktemp -d) +pushd ${DIR} + +function finish { + popd + rm -rf ${DIR} +} +trap finish EXIT + +cat > config.json < metrics + +# Shutdown VILLASnode +kill $! + +cat metrics