include/ylt/metric/system_metric.hpp (404 lines of code) (raw):

#pragma once #if defined(__GNUC__) #include <sys/resource.h> #include <sys/time.h> #include <chrono> #include <cstdint> #include <cstdio> #include <fstream> #include <memory> #include <system_error> #if __has_include("ylt/coro_io/coro_io.hpp") #include "ylt/coro_io/coro_io.hpp" #include "ylt/coro_io/io_context_pool.hpp" #include "ylt/metric/counter.hpp" #include "ylt/metric/gauge.hpp" #include "ylt/metric/metric.hpp" #include "ylt/metric/metric_manager.hpp" #else #include "cinatra/ylt/coro_io/coro_io.hpp" #include "cinatra/ylt/coro_io/io_context_pool.hpp" #include "cinatra/ylt/metric/counter.hpp" #include "cinatra/ylt/metric/gauge.hpp" #include "cinatra/ylt/metric/metric.hpp" #include "cinatra/ylt/metric/metric_manager.hpp" #endif // modified based on: brpc/src/bvar/default_variables.cpp namespace ylt::metric { namespace detail { #if defined(__APPLE__) #include <stdio.h> inline int read_command_output_through_popen(std::ostream& os, const char* cmd) { FILE* pipe = popen(cmd, "r"); if (pipe == NULL) { return -1; } char buffer[1024]; for (;;) { size_t nr = fread(buffer, 1, sizeof(buffer), pipe); if (nr != 0) { os.write(buffer, nr); } if (nr != sizeof(buffer)) { if (feof(pipe)) { break; } else if (ferror(pipe)) { break; } // retry; } } const int wstatus = pclose(pipe); if (wstatus < 0) { return wstatus; } if (WIFEXITED(wstatus)) { return WEXITSTATUS(wstatus); } if (WIFSIGNALED(wstatus)) { os << "Child process was killed by signal " << WTERMSIG(wstatus); } errno = ECHILD; return -1; } #endif inline int64_t last_time_us = 0; inline int64_t last_sys_time_us = 0; inline int64_t last_user_time_us = 0; inline int64_t gettimeofday_us() { timeval now; gettimeofday(&now, NULL); return now.tv_sec * 1000000L + now.tv_usec; } inline int64_t timeval_to_microseconds(const timeval& tv) { return tv.tv_sec * 1000000L + tv.tv_usec; } inline void stat_cpu() { static auto process_cpu_usage = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_cpu_usage"); static auto process_cpu_usage_system = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_cpu_usage_system"); static auto process_cpu_usage_user = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_cpu_usage_user"); rusage usage{}; getrusage(RUSAGE_SELF, &usage); int64_t utime = timeval_to_microseconds(usage.ru_utime); int64_t stime = timeval_to_microseconds(usage.ru_stime); int64_t time_total = utime + stime; int64_t now = gettimeofday_us(); if (last_time_us == 0) { last_time_us = now; last_sys_time_us = stime; last_user_time_us = utime; return; } int64_t elapsed = now - last_time_us; if (elapsed == 0) { return; } double cpu_usage = double(time_total - (last_sys_time_us + last_user_time_us)) / (now - last_time_us); double sys_cpu_usage = double(stime - last_sys_time_us) / (now - last_time_us); double usr_cpu_usage = double(utime - last_user_time_us) / (now - last_time_us); process_cpu_usage->update(cpu_usage); process_cpu_usage_system->update(sys_cpu_usage); process_cpu_usage_user->update(usr_cpu_usage); last_time_us = now; last_sys_time_us = stime; last_user_time_us = utime; } inline void stat_memory() { static auto process_memory_virtual = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_memory_virtual"); static auto process_memory_resident = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_memory_resident"); static auto process_memory_shared = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_memory_shared"); long virtual_size = 0; long resident = 0; long share = 0; static long page_size = sysconf(_SC_PAGE_SIZE); #if defined(__APPLE__) static pid_t pid = getpid(); static int64_t pagesize = getpagesize(); std::ostringstream oss; char cmdbuf[128]; snprintf(cmdbuf, sizeof(cmdbuf), "ps -p %ld -o rss=,vsz=", (long)pid); if (read_command_output_through_popen(oss, cmdbuf) != 0) { return; } const std::string& result = oss.str(); if (sscanf(result.c_str(), "%ld %ld", &resident, &virtual_size) != 2) { return; } #else std::ifstream file("/proc/self/statm"); if (!file) { return; } file >> virtual_size >> resident >> share; #endif process_memory_virtual->update(virtual_size * page_size); process_memory_resident->update(resident * page_size); process_memory_shared->update(share * page_size); } struct ProcIO { size_t rchar; size_t wchar; size_t syscr; size_t syscw; size_t read_bytes; size_t write_bytes; size_t cancelled_write_bytes; }; inline void stat_io() { static auto process_io_read_bytes_second = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_io_read_bytes_second"); static auto process_io_write_bytes_second = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_io_write_bytes_second"); static auto process_io_read_second = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_io_read_second"); static auto process_io_write_second = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_io_write_second"); ProcIO s{}; #if defined(__APPLE__) #else auto stream_file = std::shared_ptr<FILE>(fopen("/proc/self/io", "r"), [](FILE *ptr) { fclose(ptr); }); if (stream_file == nullptr) { return; } if (fscanf(stream_file.get(), "%*s %lu %*s %lu %*s %lu %*s %lu %*s %lu %*s %lu %*s %lu", &s.rchar, &s.wchar, &s.syscr, &s.syscw, &s.read_bytes, &s.write_bytes, &s.cancelled_write_bytes) != 7) { return; } #endif process_io_read_bytes_second->update(s.rchar); process_io_write_bytes_second->update(s.wchar); process_io_read_second->update(s.syscr); process_io_write_second->update(s.syscw); } inline void stat_avg_load() { static auto system_loadavg_1m = system_metric_manager::instance().get_metric_static<gauge_d>( "ylt_system_loadavg_1m"); static auto system_loadavg_5m = system_metric_manager::instance().get_metric_static<gauge_d>( "ylt_system_loadavg_5m"); static auto system_loadavg_15m = system_metric_manager::instance().get_metric_static<gauge_d>( "ylt_system_loadavg_15m"); double loadavg_1m = 0; double loadavg_5m = 0; double loadavg_15m = 0; #if defined(__APPLE__) std::ostringstream oss; if (read_command_output_through_popen(oss, "sysctl -n vm.loadavg") != 0) { return; } const std::string& result = oss.str(); if (sscanf(result.c_str(), "{ %lf %lf %lf }", &loadavg_1m, &loadavg_5m, &loadavg_15m) != 3) { return; } #else std::ifstream file("/proc/loadavg"); if (!file) { return; } file >> loadavg_1m >> loadavg_5m >> loadavg_15m; #endif system_loadavg_1m->update(loadavg_1m); system_loadavg_5m->update(loadavg_5m); system_loadavg_15m->update(loadavg_15m); } struct ProcStat { int pid; // std::string comm; char state; int ppid; int pgrp; int session; int tty_nr; int tpgid; unsigned flags; unsigned long minflt; unsigned long cminflt; unsigned long majflt; unsigned long cmajflt; unsigned long utime; unsigned long stime; unsigned long cutime; unsigned long cstime; long priority; long nice; long num_threads; }; inline void process_status() { static auto process_uptime = system_metric_manager::instance().get_metric_static<counter_t>( "ylt_process_uptime"); static auto process_priority = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_process_priority"); static auto pid = system_metric_manager::instance().get_metric_static<gauge_t>("ylt_pid"); static auto ppid = system_metric_manager::instance().get_metric_static<gauge_t>("ylt_ppid"); static auto pgrp = system_metric_manager::instance().get_metric_static<gauge_t>("ylt_pgrp"); static auto thread_count = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_thread_count"); ProcStat stat{}; #if defined(__linux__) auto stream_file = std::shared_ptr<FILE>(fopen("/proc/self/stat", "r"), [](FILE* ptr) { fclose(ptr); }); if (stream_file == nullptr) { return; } if (fscanf(stream_file.get(), "%d %*s %c " "%d %d %d %d %d " "%u %lu %lu %lu " "%lu %lu %lu %lu %lu " "%ld %ld %ld", &stat.pid, &stat.state, &stat.ppid, &stat.pgrp, &stat.session, &stat.tty_nr, &stat.tpgid, &stat.flags, &stat.minflt, &stat.cminflt, &stat.majflt, &stat.cmajflt, &stat.utime, &stat.stime, &stat.cutime, &stat.cstime, &stat.priority, &stat.nice, &stat.num_threads) != 19) { return; } #elif defined(__APPLE__) static pid_t proc_id = getpid(); std::ostringstream oss; char cmdbuf[128]; snprintf(cmdbuf, sizeof(cmdbuf), "ps -p %ld -o pid,ppid,pgid,sess" ",tpgid,flags,pri,nice | tail -n1", (long)proc_id); if (read_command_output_through_popen(oss, cmdbuf) != 0) { return; } const std::string &result = oss.str(); if (sscanf(result.c_str(), "%d %d %d %d" "%d %u %ld %ld", &stat.pid, &stat.ppid, &stat.pgrp, &stat.session, &stat.tpgid, &stat.flags, &stat.priority, &stat.nice) != 8) { return; } #endif process_uptime->inc(); process_priority->update(stat.priority); pid->update(stat.pid); ppid->update(stat.ppid); pgrp->update(stat.pgrp); thread_count->update(stat.num_threads); } inline void stat_metric() { static auto user_metric_count = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_user_metric_count"); user_metric_count->update(metric::metric_t::g_user_metric_count); static auto user_metric_label_count = system_metric_manager::instance().get_metric_static<gauge_t>( "ylt_user_metric_labels"); user_metric_label_count->update( dynamic_metric::g_user_metric_label_count->value()); } inline void ylt_stat() { stat_cpu(); stat_memory(); stat_io(); stat_avg_load(); process_status(); stat_metric(); } inline void start_stat(std::weak_ptr<coro_io::period_timer> weak) { auto timer = weak.lock(); if (timer == nullptr) { return; } ylt_stat(); timer->expires_after(std::chrono::seconds(1)); timer->async_wait([timer](std::error_code ec) { if (ec) { return; } start_stat(timer); }); } } // namespace detail inline bool start_system_metric() { system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_cpu_usage", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_cpu_usage_system", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_cpu_usage_user", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_memory_virtual", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_memory_resident", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_memory_shared", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_uptime", ""); system_metric_manager::instance().create_metric_static<gauge_t>("ylt_pid", ""); system_metric_manager::instance().create_metric_static<gauge_t>("ylt_ppid", ""); system_metric_manager::instance().create_metric_static<gauge_t>("ylt_pgrp", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_thread_count", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_priority", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_user_metric_count", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_user_metric_labels", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_summary_failed_count", ""); system_metric_manager::instance().create_metric_static<gauge_d>( "ylt_system_loadavg_1m", ""); system_metric_manager::instance().create_metric_static<gauge_d>( "ylt_system_loadavg_5m", ""); system_metric_manager::instance().create_metric_static<gauge_d>( "ylt_system_loadavg_15m", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_io_read_bytes_second", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_io_write_bytes_second", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_io_read_second", ""); system_metric_manager::instance().create_metric_static<gauge_t>( "ylt_process_io_write_second", ""); static auto exucutor = coro_io::create_io_context_pool(1); auto timer = std::make_shared<coro_io::period_timer>(exucutor->get_executor()); detail::start_stat(timer); return true; } } // namespace ylt::metric #endif