Skip to content

Commit

Permalink
[metric][fix]System metric (#733)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Aug 5, 2024
1 parent 999bb72 commit a0bd54c
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 33 deletions.
29 changes: 24 additions & 5 deletions include/ylt/metric/counter.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <atomic>
#include <chrono>
#include <variant>

#include "metric.hpp"
#include "thread_local_value.hpp"
Expand All @@ -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<std::string, std::string> labels;
int64_t value;
std::variant<int64_t, double> value;
};
REFLECTION(json_counter_metric_t, labels, value);
struct json_counter_t {
Expand All @@ -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++;
}
Expand Down Expand Up @@ -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<std::string> &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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
}
Expand All @@ -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_) {
Expand Down Expand Up @@ -358,7 +377,7 @@ class basic_counter : public metric_t {
}

metric_hash_map<thread_local_value<value_type>> atomic_value_map_;
thread_local_value<value_type> default_label_value_ = {10};
thread_local_value<value_type> default_label_value_;

std::mutex mtx_;
metric_hash_map<thread_local_value<value_type>> value_map_;
Expand Down
4 changes: 4 additions & 0 deletions include/ylt/metric/gauge.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class basic_gauge : public basic_counter<value_type> {
using basic_counter<value_type>::validate;
using metric_t::use_atomic_;
using basic_counter<value_type>::default_label_value_;
using metric_t::labels_name_;
using metric_t::labels_value_;
using basic_counter<value_type>::atomic_value_map_;
using basic_counter<value_type>::value_map_;
Expand Down Expand Up @@ -40,6 +41,9 @@ class basic_gauge : public basic_counter<value_type> {
}

void dec(value_type value = 1) {
if (!labels_name_.empty()) {
throw std::bad_function_call();
}
#ifdef __APPLE__
if constexpr (std::is_floating_point_v<value_type>) {
mac_os_atomic_fetch_sub(&default_label_value_.local_value(), value);
Expand Down
5 changes: 5 additions & 0 deletions include/ylt/metric/metric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,11 @@ struct metric_manager_t {
if (str.size() > start)
str.append(",");
}

if (str.size() == 1) {
return "";
}

str.back() = ']';
return str;
}
Expand Down
132 changes: 114 additions & 18 deletions include/ylt/metric/system_metric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -138,6 +196,9 @@ inline void stat_io() {
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);
Expand All @@ -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);
Expand All @@ -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<gauge_t>(
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_t>(
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_t>(
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;
}

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 {
Expand Down Expand Up @@ -224,15 +300,16 @@ inline void process_status() {
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) {
std::shared_ptr<FILE>(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 "
Expand All @@ -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);
Expand Down Expand Up @@ -329,11 +425,11 @@ inline bool start_system_metric() {
system_metric_manager::instance().create_metric_static<gauge_t>(
"ylt_summary_failed_count", "");

system_metric_manager::instance().create_metric_static<gauge_t>(
system_metric_manager::instance().create_metric_static<gauge_d>(
"ylt_system_loadavg_1m", "");
system_metric_manager::instance().create_metric_static<gauge_t>(
system_metric_manager::instance().create_metric_static<gauge_d>(
"ylt_system_loadavg_5m", "");
system_metric_manager::instance().create_metric_static<gauge_t>(
system_metric_manager::instance().create_metric_static<gauge_d>(
"ylt_system_loadavg_15m", "");

system_metric_manager::instance().create_metric_static<gauge_t>(
Expand Down
21 changes: 11 additions & 10 deletions include/ylt/metric/thread_local_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class thread_local_value {
duplicates_[i] = ptr;
}
}
return *this;
}

thread_local_value(thread_local_value &&other) {
Expand All @@ -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<value_type>(0);

Expand Down

0 comments on commit a0bd54c

Please sign in to comment.