Program Listing for File prometheus_writer.cpp
↰ Return to documentation for file (monitoring/prometheus_writer.cpp)
#include "prometheus_writer.hpp"
PrometheusWriter::PrometheusWriter(int port)
: exposer{std::make_unique<prometheus::Exposer>(std::format("0.0.0.0:{}", port))},
registry{std::make_shared<prometheus::Registry>()} {
exposer->RegisterCollectable(registry);
}
void PrometheusWriter::write_message(const nlohmann::json& message) {
try {
const std::string hostname = message.at("hostname").get<std::string>();
for (const auto& device : message.at("devices")) {
const std::string app = device.at("app").get<std::string>();
const std::string device_id = std::to_string(device.at("device_id").get<int>());
for (const auto& buffer : device.at("buffers")) {
const std::string dmaid = std::to_string(buffer.at("dmaid").get<int>());
for (const auto& thread : buffer.at("threads")) {
if (app == "fromhost") {
const std::string fromhost_thread_id = std::to_string(thread.at("thread_id").get<int>());
metric_to_prometheus(app, "dma_free_MB", buffer.at("dma_free_MB").get<double>(), hostname, device_id, dmaid);
metric_to_prometheus(app, "msg_rate_Hz", buffer.at("msg_rate_Hz").get<double>(), hostname, device_id, dmaid);
metric_to_prometheus(app, "msg_rate_Mbps", buffer.at("msg_rate_Mbps").get<double>(), hostname, device_id, dmaid);
metric_to_prometheus(app, "number_of_connections", thread.at("number_of_connections").get<double>(), hostname, device_id, dmaid, fromhost_thread_id);
for (const auto& elink : thread.at("elinks")) {
const std::string fid = std::format("{:#x}", elink.at("fid").get<int>());
metric_to_prometheus(app, "msgs", elink.at("msgs").get<double>(), hostname, device_id, dmaid, fromhost_thread_id, fid);
metric_to_prometheus(app, "bytes", elink.at("bytes").get<double>(), hostname, device_id, dmaid, fromhost_thread_id, fid);
metric_to_prometheus(app, "max_msg_size", elink.at("max_msg_size").get<double>(), hostname, device_id, dmaid, fromhost_thread_id, fid);
metric_to_prometheus(app, "dropped_msgs", elink.at("dropped_msgs").get<double>(), hostname, device_id, dmaid, fromhost_thread_id, fid);
metric_to_prometheus(app, "rate_msg_Hz", elink.at("rate_msg_Hz").get<double>(), hostname, device_id, dmaid, fromhost_thread_id, fid);
metric_to_prometheus(app, "rate_msg_Mbps", elink.at("rate_msg_Mbps").get<double>(), hostname, device_id, dmaid, fromhost_thread_id, fid);
}
} else if (app == "tohost") {
const std::string tohost_thread = std::to_string(thread.at("thread_id").get<int>());
const std::string tohost_elink_type = thread.at("type");
const std::string tohost_thread_id = std::format("{}_{}", tohost_elink_type, tohost_thread);
metric_to_prometheus(app, "dma_free_MB", buffer.at("dma_free_MB").get<double>(), hostname, device_id, dmaid);
metric_to_prometheus(app, "irqs", buffer.at("irqs").get<double>(), hostname, device_id, dmaid);
metric_to_prometheus(app, "net_calls", thread.at("net_calls").get<double>(), hostname, device_id, dmaid, tohost_thread_id);
metric_to_prometheus(app, "net_resources", thread.at("net_resources").get<double>(), hostname, device_id, dmaid, tohost_thread_id);
metric_to_prometheus(app, "subscriptions", thread.at("subscriptions").get<double>(), hostname, device_id, dmaid, tohost_thread_id);
for (const auto& elink : thread.at("elinks")) {
const std::string fid = std::format("{:#x}", elink.at("fid").get<int>());
metric_to_prometheus(app, "avg_chunk_size", elink.at("avg_chunk_size").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "blocks", elink.at("blocks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "chunk_kHz", elink.at("chunk_kHz").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "chunks", elink.at("chunks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "dropped_empty_chunks", elink.at("dropped_empty_chunks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "dropped_blocks", elink.at("dropped_blocks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "fw_crc_chunks", elink.at("fw_crc_chunks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "fw_error_chunks", elink.at("fw_error_chunks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "fw_trunc_chunks", elink.at("fw_trunc_chunks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "max_chunk_size", elink.at("max_chunk_size").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "oosequence_l0id", elink.at("oosequence_l0id").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "sw_error_chunks", elink.at("sw_error_chunks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
metric_to_prometheus(app, "sw_trunc_chunks", elink.at("sw_trunc_chunks").get<double>(), hostname, device_id, dmaid, tohost_thread_id, fid);
}
}
}
}
}
} catch (const nlohmann::json::out_of_range& e) {
ers::error(monitoring_log::prometheus_issue( std::format("JSON out of range error: {}", e.what())));
} catch (const std::invalid_argument& e) {
ers::error(monitoring_log::prometheus_issue( std::format("Invalid argument error: {}", e.what())));
}
}
void PrometheusWriter::metric_to_prometheus(const std::string& app, const std::string& key, double value,
const std::string& hostname, const std::string& device,
const std::string& dma, const std::string& thread,
const std::string& fid) {
const std::string metric_name = std::format("felix_{}_{}", app, key);
prometheus::Labels labels_map;
if (not hostname.empty()) { labels_map["hostname"] = hostname; }
if (not device.empty()) { labels_map["device"] = device; }
if (not dma.empty()) { labels_map["dma"] = dma; }
if (not thread.empty()) { labels_map["thread"] = thread; }
if (not fid.empty()) { labels_map["fid"] = fid; }
std::string pkey = metric_name;
for (const auto& label : labels_map) {
pkey = std::format("{}:{}={}", pkey, label.first, label.second);
}
if (not prometheus_metrics.contains(pkey)) {
auto& gauge_family = prometheus::BuildGauge()
.Name(metric_name)
.Help("")
.Register(*registry);
prometheus_metrics[pkey] = &gauge_family.Add(labels_map);
}
auto& gauge = *prometheus_metrics[pkey];
gauge.Set(value);
}