Skip to content

Commit

Permalink
Sys info metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
ErakhtinB committed Nov 26, 2024
1 parent a68a08a commit 3922c02
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 1 deletion.
91 changes: 91 additions & 0 deletions core/application/impl/kagome_application_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <soralog/macro.hpp>
#include <thread>

#include <sys/sysinfo.h>
#include <sys/utsname.h>
#include "application/app_state_manager.hpp"
#include "application/impl/util.hpp"
#include "application/modes/precompile_wasm.hpp"
Expand Down Expand Up @@ -120,6 +122,8 @@ namespace kagome::application {
{{"name", app_config_->nodeName()},
{"version", app_config_->nodeVersion()}});
metric_build_info->set(1);

// setupSystemMetrics(metrics_registry);
}

#ifdef __linux__
Expand Down Expand Up @@ -157,4 +161,91 @@ namespace kagome::application {
watchdog->stop();
return r;
}

void KagomeApplicationImpl::setupSystemMetrics(
kagome::metrics::RegistryPtr &metrics_registry) {
constexpr auto cpu_cores_metric_name = "cpu_cores_total";
metrics_registry->registerGaugeFamily(
cpu_cores_metric_name, "Total number of CPU cores available");
auto cpu_cores =
metrics_registry->registerGaugeMetric(cpu_cores_metric_name);
const auto cpu_cores_count = std::thread::hardware_concurrency();
logger_->info("Number of CPU cores: {}", cpu_cores_count);
cpu_cores->set(std::thread::hardware_concurrency());

struct sysinfo sys_info;
if (sysinfo(&sys_info) == 0) {
logger_->info("System uptime: {} seconds", sys_info.uptime);
logger_->info("Total RAM: {} bytes", sys_info.totalram);
logger_->info("Free RAM: {} bytes", sys_info.freeram);
logger_->info("Shared RAM: {} bytes", sys_info.sharedram);
logger_->info("Buffer RAM: {} bytes", sys_info.bufferram);
logger_->info("Total swap: {} bytes", sys_info.totalswap);
logger_->info("Free swap: {} bytes", sys_info.freeswap);
logger_->info("Number of processes: {}", sys_info.procs);
constexpr auto memory_total_metric_name = "memory_total_bytes";
metrics_registry->registerGaugeFamily(memory_total_metric_name,
"Total system memory in bytes");
auto memory_total =
metrics_registry->registerGaugeMetric(memory_total_metric_name);
memory_total->set(sys_info.totalram);

constexpr auto memory_free_metric_name = "memory_free_bytes";
metrics_registry->registerGaugeFamily(memory_free_metric_name,
"Free system memory in bytes");
auto memory_free =
metrics_registry->registerGaugeMetric(memory_free_metric_name);
memory_free->set(sys_info.freeram);
} else {
logger_->error("Failed to get system information: {}", strerror(errno));
}

struct utsname uname_info;
if (uname(&uname_info) == 0) {
logger_->info("System name: {}, release: {}, version: {}, machine: {}",
uname_info.sysname,
uname_info.release,
uname_info.version,
uname_info.machine);
constexpr auto os_info_metric_name = "os_info";
metrics_registry->registerGaugeFamily(os_info_metric_name,
"Operating System information");
auto os_info = metrics_registry->registerGaugeMetric(
os_info_metric_name,
{{"sysname", uname_info.sysname},
{"release", uname_info.release},
{"version", uname_info.version},
{"machine", uname_info.machine}});
os_info->set(1);
} else {
logger_->error("Failed to get system information: {}", strerror(errno));
}

constexpr auto cpu_architecture_metric_name = "cpu_architecture";
metrics_registry->registerGaugeFamily(cpu_architecture_metric_name,
"CPU Architecture information");
auto cpu_arch = metrics_registry->registerGaugeMetric(
cpu_architecture_metric_name, {{"architecture", uname_info.machine}});
cpu_arch->set(1);

constexpr auto is_virtual_machine_metric_name = "is_virtual_machine";
metrics_registry->registerGaugeFamily(
is_virtual_machine_metric_name,
"Detects if the system is a virtual machine (1 if true, 0 otherwise)");
auto vm_detected =
metrics_registry->registerGaugeMetric(is_virtual_machine_metric_name);
std::ifstream dmi("/sys/class/dmi/id/product_name");
auto is_virtual = dmi.is_open();
if (is_virtual) {
std::string product_name;
std::getline(dmi, product_name);
is_virtual = not(product_name.find("Virtual") == std::string::npos);
logger_->info("Product name: {}", product_name);
} else {
logger_->info(
"There is no product name file, so it is not a virtual "
"machine or it is not supported");
}
vm_detected->set(is_virtual);
}
} // namespace kagome::application
2 changes: 2 additions & 0 deletions core/application/impl/kagome_application_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "application/app_configuration.hpp"
#include "application/chain_spec.hpp"
#include "metrics/metrics.hpp"

namespace kagome::injector {
class KagomeNodeInjector;
Expand Down Expand Up @@ -40,6 +41,7 @@ namespace kagome::application {

private:
int runMode(Mode &mode);
void setupSystemMetrics(kagome::metrics::RegistryPtr &metrics_registry);

injector::KagomeNodeInjector &injector_;

Expand Down
128 changes: 127 additions & 1 deletion core/telemetry/impl/service_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "telemetry/impl/service_impl.hpp"

#include <sys/utsname.h>
#include <regex>

#include <fmt/core.h>
Expand Down Expand Up @@ -37,6 +38,91 @@ namespace {
document.Accept(writer);
return buffer.GetString();
}
struct SysInfo {
std::optional<std::string> cpu;
std::optional<bool> is_virtual_machine;
std::optional<size_t> core_count;
std::optional<uint64_t> memory;
std::optional<std::string> linux_distro;
};

// Function to read file content into a string
std::optional<std::string> read_file(const std::string &filepath) {
std::ifstream file(filepath);
if (not file.is_open()) {
return std::nullopt;
}
return {std::string((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>())};
}

// Function to extract a single match using regex
template <typename T>
std::optional<T> extract(const std::string &data, const std::regex &pattern) {
std::smatch match;
if (std::regex_search(data, match, pattern)) {
if constexpr (std::is_same<T, std::string>::value) {
return match[1].str();
} else if constexpr (std::is_integral<T>::value) {
return static_cast<T>(std::stoull(match[1].str()));
}
}
return std::nullopt;
}

SysInfo gather_linux_sysinfo() {
const std::regex LINUX_REGEX_CPU(R"(^model name\s*:\s*([^\n]+))",
std::regex_constants::multiline);
const std::regex LINUX_REGEX_PHYSICAL_ID(R"(^physical id\s*:\s*(\d+))",
std::regex_constants::multiline);
const std::regex LINUX_REGEX_CORE_ID(R"(^core id\s*:\s*(\d+))",
std::regex_constants::multiline);
const std::regex LINUX_REGEX_HYPERVISOR(R"(^flags\s*:.+?\bhypervisor\b)",
std::regex_constants::multiline);
const std::regex LINUX_REGEX_MEMORY(R"(^MemTotal:\s*(\d+) kB)",
std::regex_constants::multiline);
const std::regex LINUX_REGEX_DISTRO(R"(PRETTY_NAME\s*=\s*\"([^\"]+)\")",
std::regex_constants::multiline);

SysInfo sysinfo;

if (auto cpuinfo = read_file("/proc/cpuinfo")) {
sysinfo.cpu = extract<std::string>(*cpuinfo, LINUX_REGEX_CPU);
sysinfo.is_virtual_machine =
std::regex_search(*cpuinfo, LINUX_REGEX_HYPERVISOR);

// Extract unique {physical_id, core_id} pairs
std::set<std::pair<uint32_t, uint32_t>> cores;
std::regex section_split("\n\n");
std::sregex_token_iterator sections(
cpuinfo->begin(), cpuinfo->end(), section_split, -1);
std::sregex_token_iterator end;
for (; sections != end; ++sections) {
std::optional<uint32_t> pid =
extract<uint32_t>(*sections, LINUX_REGEX_PHYSICAL_ID);
std::optional<uint32_t> cid =
extract<uint32_t>(*sections, LINUX_REGEX_CORE_ID);
if (pid && cid) {
cores.emplace(*pid, *cid);
}
}
if (not cores.empty()) {
sysinfo.core_count = static_cast<uint32_t>(cores.size());
}
}

if (auto meminfo = read_file("/proc/meminfo")) {
sysinfo.memory =
extract<uint64_t>(*meminfo, LINUX_REGEX_MEMORY).value_or(0) * 1024;
}

if (auto os_release = read_file("/etc/os-release")) {
sysinfo.linux_distro =
extract<std::string>(*os_release, LINUX_REGEX_DISTRO);
}

return sysinfo;
}
} // namespace

namespace kagome::telemetry {
Expand Down Expand Up @@ -251,13 +337,52 @@ namespace kagome::telemetry {
allocator);
return val;
};
auto u64_val = [&allocator](uint64_t val) -> rapidjson::Value & {
static rapidjson::Value v;
v.SetUint64(val);
return v;
};

auto u32_val = [&allocator](uint32_t val) -> rapidjson::Value & {
static rapidjson::Value v;
v.SetUint(val);
return v;
};

auto startup_time =
std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());

rapidjson::Value payload(rapidjson::kObjectType);
rapidjson::Value sys_info_json(rapidjson::kObjectType);
struct utsname utsmame_info;
if (uname(&utsmame_info) == 0) {
payload.AddMember(
"target_arch", str_val(utsmame_info.machine), allocator);
payload.AddMember("target_os", str_val(utsmame_info.sysname), allocator);
sys_info_json.AddMember(
"linux_kernel", str_val(utsmame_info.release), allocator);
}
const auto sys_info = gather_linux_sysinfo();
if (const auto &memory = sys_info.memory) {
sys_info_json.AddMember("memory", u64_val(*memory), allocator);
}
if (const auto &cpu = sys_info.cpu) {
sys_info_json.AddMember("cpu", str_val(*cpu), allocator);
}
if (const auto &core_count = sys_info.core_count) {
sys_info_json.AddMember("core_count", u32_val(*core_count), allocator);
}
if (const auto &linux_distro = sys_info.linux_distro) {
sys_info_json.AddMember(
"linux_distro", str_val(*linux_distro), allocator);
}
if (const auto &is_virtual = sys_info.is_virtual_machine) {
sys_info_json.AddMember(
"is_virtual", rapidjson::Value{}.SetBool(*is_virtual), allocator);
}

payload
.AddMember(
"authority", app_configuration_.roles().isAuthority(), allocator)
Expand All @@ -270,7 +395,8 @@ namespace kagome::telemetry {
.AddMember("network_id", str_val(host_.getId().toBase58()), allocator)
.AddMember("startup_time", str_val(startup_time), allocator)
.AddMember(
"version", str_val(app_configuration_.nodeVersion()), allocator);
"version", str_val(app_configuration_.nodeVersion()), allocator)
.AddMember("sysinfo", sys_info_json, allocator);

greeting_json_.AddMember("id", 1, allocator)
.AddMember("payload", payload, allocator)
Expand Down

0 comments on commit 3922c02

Please sign in to comment.