diff --git a/include/ylt/metric/counter.hpp b/include/ylt/metric/counter.hpp index 943cbdfbc..06415561e 100644 --- a/include/ylt/metric/counter.hpp +++ b/include/ylt/metric/counter.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "metric.hpp" #include "thread_local_value.hpp" @@ -11,7 +12,7 @@ enum class op_type_t { INC, DEC, SET }; #ifdef CINATRA_ENABLE_METRIC_JSON struct json_counter_metric_t { std::unordered_multimap labels; - int64_t value; + std::variant value; }; REFLECTION(json_counter_metric_t, labels, value); struct json_counter_t { @@ -29,7 +30,8 @@ class basic_counter : public metric_t { // default, no labels, only contains an atomic value. basic_counter(std::string name, std::string help, size_t dupli_count = 2) : metric_t(MetricType::Counter, std::move(name), std::move(help)), - dupli_count_(dupli_count) { + dupli_count_(dupli_count), + default_label_value_(dupli_count) { use_atomic_ = true; g_user_metric_count++; } @@ -58,9 +60,18 @@ class basic_counter : public metric_t { virtual ~basic_counter() { g_user_metric_count--; } - value_type value() { return default_label_value_.value(); } + value_type value() { + if (!labels_name_.empty()) { + throw std::invalid_argument("it's not a default value counter!"); + } + return default_label_value_.value(); + } value_type value(const std::vector &labels_value) { + if (labels_name_.empty()) { + throw std::invalid_argument("it is a default value counter"); + } + if (use_atomic_) { value_type val = atomic_value_map_[labels_value].value(); return val; @@ -125,7 +136,7 @@ class basic_counter : public metric_t { return; } json_counter_t counter{name_, help_, std::string(metric_name())}; - int64_t value = default_label_value_.value(); + auto value = default_label_value_.value(); counter.metrics.push_back({{}, value}); iguana::to_json(counter, str); return; @@ -157,6 +168,10 @@ class basic_counter : public metric_t { #endif void inc(value_type val = 1) { + if (!labels_name_.empty()) { + throw std::invalid_argument("it's not a default value counter!"); + } + if (val < 0) { throw std::invalid_argument("the value is less than zero"); } @@ -178,6 +193,10 @@ class basic_counter : public metric_t { return; } + if (labels_name_.empty()) { + throw std::invalid_argument("it's a default value counter!"); + } + validate(labels_value, value); if (use_atomic_) { if (labels_value != labels_value_) { @@ -358,7 +377,7 @@ class basic_counter : public metric_t { } metric_hash_map> atomic_value_map_; - thread_local_value default_label_value_ = {10}; + thread_local_value default_label_value_; std::mutex mtx_; metric_hash_map> value_map_; diff --git a/include/ylt/metric/gauge.hpp b/include/ylt/metric/gauge.hpp index 1f3a0b4ee..0d6a3e327 100644 --- a/include/ylt/metric/gauge.hpp +++ b/include/ylt/metric/gauge.hpp @@ -11,6 +11,7 @@ class basic_gauge : public basic_counter { using basic_counter::validate; using metric_t::use_atomic_; using basic_counter::default_label_value_; + using metric_t::labels_name_; using metric_t::labels_value_; using basic_counter::atomic_value_map_; using basic_counter::value_map_; @@ -40,6 +41,9 @@ class basic_gauge : public basic_counter { } void dec(value_type value = 1) { + if (!labels_name_.empty()) { + throw std::bad_function_call(); + } #ifdef __APPLE__ if constexpr (std::is_floating_point_v) { mac_os_atomic_fetch_sub(&default_label_value_.local_value(), value); diff --git a/include/ylt/metric/metric.hpp b/include/ylt/metric/metric.hpp index 7da09cdfa..b5caba8f6 100644 --- a/include/ylt/metric/metric.hpp +++ b/include/ylt/metric/metric.hpp @@ -476,6 +476,11 @@ struct metric_manager_t { if (str.size() > start) str.append(","); } + + if (str.size() == 1) { + return ""; + } + str.back() = ']'; return str; } diff --git a/include/ylt/metric/system_metric.hpp b/include/ylt/metric/system_metric.hpp index 5d1c54bf1..f224daf42 100644 --- a/include/ylt/metric/system_metric.hpp +++ b/include/ylt/metric/system_metric.hpp @@ -24,11 +24,53 @@ #include "cinatra/ylt/metric/metric.hpp" #endif -// reference: brpc/src/bvar/default_variables.cpp +// modified based on: brpc/src/bvar/default_variables.cpp namespace ylt::metric { namespace detail { +#if defined(__APPLE__) +#include + +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; @@ -39,7 +81,7 @@ inline int64_t gettimeofday_us() { return now.tv_sec * 1000000L + now.tv_usec; } -inline int64_t timeval_to_microseconds(const timeval &tv) { +inline int64_t timeval_to_microseconds(const timeval& tv) { return tv.tv_sec * 1000000L + tv.tv_usec; } @@ -101,13 +143,29 @@ inline void stat_memory() { 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; - static long page_size = sysconf(_SC_PAGE_SIZE); +#endif process_memory_virtual->update(virtual_size * page_size); process_memory_resident->update(resident * page_size); @@ -138,6 +196,9 @@ inline void stat_io() { system_metric_manager::instance().get_metric_static( "ylt_process_io_write_second"); + ProcIO s{}; +#if defined(__APPLE__) +#else auto stream_file = std::shared_ptr(fopen("/proc/self/io", "r"), [](FILE *ptr) { fclose(ptr); @@ -146,13 +207,13 @@ inline void stat_io() { return; } - ProcIO s{}; 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); @@ -162,26 +223,41 @@ inline void stat_io() { inline void stat_avg_load() { static auto system_loadavg_1m = - system_metric_manager::instance().get_metric_static( + system_metric_manager::instance().get_metric_static( "ylt_system_loadavg_1m"); static auto system_loadavg_5m = - system_metric_manager::instance().get_metric_static( + system_metric_manager::instance().get_metric_static( "ylt_system_loadavg_5m"); static auto system_loadavg_15m = - system_metric_manager::instance().get_metric_static( + system_metric_manager::instance().get_metric_static( "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; } - double loadavg_1m = 0; - double loadavg_5m = 0; - double loadavg_15m = 0; file >> loadavg_1m >> loadavg_5m >> loadavg_15m; +#endif + system_loadavg_1m->update(loadavg_1m); - system_loadavg_1m->update(loadavg_5m); - system_loadavg_1m->update(loadavg_15m); + system_loadavg_5m->update(loadavg_5m); + system_loadavg_15m->update(loadavg_15m); } struct ProcStat { @@ -224,15 +300,16 @@ inline void process_status() { system_metric_manager::instance().get_metric_static( "ylt_thread_count"); + ProcStat stat{}; +#if defined(__linux__) auto stream_file = - std::shared_ptr(fopen("/proc/self/stat", "r"), [](FILE *ptr) { + std::shared_ptr(fopen("/proc/self/stat", "r"), [](FILE* ptr) { fclose(ptr); }); if (stream_file == nullptr) { return; } - ProcStat stat{}; if (fscanf(stream_file.get(), "%d %*s %c " "%d %d %d %d %d " @@ -246,7 +323,26 @@ inline void process_status() { &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); @@ -329,11 +425,11 @@ inline bool start_system_metric() { system_metric_manager::instance().create_metric_static( "ylt_summary_failed_count", ""); - system_metric_manager::instance().create_metric_static( + system_metric_manager::instance().create_metric_static( "ylt_system_loadavg_1m", ""); - system_metric_manager::instance().create_metric_static( + system_metric_manager::instance().create_metric_static( "ylt_system_loadavg_5m", ""); - system_metric_manager::instance().create_metric_static( + system_metric_manager::instance().create_metric_static( "ylt_system_loadavg_15m", ""); system_metric_manager::instance().create_metric_static( diff --git a/include/ylt/metric/thread_local_value.hpp b/include/ylt/metric/thread_local_value.hpp index 5a920a5fd..db9b4b8aa 100644 --- a/include/ylt/metric/thread_local_value.hpp +++ b/include/ylt/metric/thread_local_value.hpp @@ -43,6 +43,7 @@ class thread_local_value { duplicates_[i] = ptr; } } + return *this; } thread_local_value(thread_local_value &&other) { @@ -58,23 +59,23 @@ class thread_local_value { void dec(value_type value = 1) { local_value() -= value; } value_type update(value_type value = 1) { - value_type val = reset(); - local_value() = value; - return val; - } - - value_type reset() { - value_type val = 0; - for (auto &t : duplicates_) { - if (t) { - val += t.load()->exchange(0); + value_type val = get_value(0).exchange(value); + for (size_t i = 1; i < duplicates_.size(); i++) { + if (duplicates_[i]) { + val += duplicates_[i].load()->exchange(0); } } return val; } + value_type reset() { return update(0); } + auto &local_value() { static thread_local auto index = get_round_index(duplicates_.size()); + return get_value(index); + } + + auto &get_value(size_t index) { if (duplicates_[index] == nullptr) { auto ptr = new std::atomic(0);