指标
本节介绍可收集prometheus可收集监控指标,Counter,Gauge,histogram。
tally::Counter
顾名思义,用于累加,Op为+。
tally::Counter<int> value;
value << 1 << 2 << 3 << -4;
CHECK_EQ(2, value.get_value());
tally::Counter<double> fp_value; // 可能有warning
fp_value << 1.0 << 2.0 << 3.0 << -4.0;
CHECK_DOUBLE_EQ(2.0, fp_value.get_value());
Counter<>可用于非基本类型,对应的类型至少要重载T operator+(T, T)。一个已经存在的例子是std::string,下面的代码会把string拼接起来:
// This is just proof-of-concept, don't use it for production code because it makes a
// bunch of temporary strings which is not efficient, use std::ostringstream instead.
tally::Counter<std::string> concater;
std::string str1 = "world";
concater << "hello " << str1;
CHECK_EQ("hello world", concater.get_value());
tally::MaxerGauge
用于取最大值,运算符为std::max。
tally::MaxerGauge<int> value;
value << 1 << 2 << 3 << -4;
CHECK_EQ(3, value.get_value());
Since MaxerGauge<> use std::numeric_limits<T>::min() as the identity, it cannot be applied to generic types unless you specialized std::numeric_limits<> (and overloaded operator<, yes, not operator>).
tally::MinerGauge
用于取最小值,运算符为std::min。
tally::MaxerGauge<int> value;
value << 1 << 2 << 3 << -4;
CHECK_EQ(-4, value.get_value());
Since MinerGauge<> use std::numeric_limits<T>::max() as the identity, it cannot be applied to generic types unless you specialized std::numeric_limits<> (and overloaded operator<).
tally::AverageGauge
用于计算平均值。
// For calculating average of numbers.
// Example:
// AverageGauge latency;
// latency << 1 << 3 << 5;
// CHECK_EQ(3, latency.average());
class AverageGauge : public Variable;
tally::LatencyRecorder
专用于计算latency和qps的计数器。只需填入latency数据,就能获得latency / max_latency / qps / count。统计窗口是最后一个参数,不填为tally_dump_interval(这里没填)。
注意:LatencyRecorder没有继承Variable,而是多个tally的组合。
LatencyRecorder write_latency("table2_my_table_write"); // produces 4 variables:
// table2_my_table_write_latency
// table2_my_table_write_max_latency
// table2_my_table_write_qps
// table2_my_table_write_count
// In your write function
write_latency << the_latency_of_write;
tally::Window
获得之前一段时间内的统计值。Window不能独立存在,必须依赖于一个已有的计数器。Window会自动更新,不用给它发送数据。出于性能考虑,Window的数据来自于每秒一次对原计数器的采样,在最差情况下,Window的返回值有1秒的延时。
// Get data within a time window.
// The time unit is 1 second fixed.
// Window relies on other tally which should be constructed before this window and destructs after this window.
// R must:
// - have get_sampler() (not require thread-safe)
// - defined value_type and sampler_type
template <typename R>
class Window : public Variable;
How to use tally::Window
tally::Counter<int> sum;
tally::MaxerGauge<int> max_value;
tally::IntRecorder avg_value;
// sum_minute.get_value()是sum在之前60秒内的累加值。
tally::Window<tally::Counter<int> > sum_minute(&sum, 60);
// max_value_minute.get_value()是max_value在之前60秒内的最大值。
tally::Window<tally::MaxerGauge<int> > max_value_minute(&max_value, 60);
// avg_value_minute.get_value()是avg_value在之前60秒内的平均值。
tally::Window<IntRecorder> avg_value_minute(&avg_value, 60);
tally::PerSecond
获得之前一段时间内平均每秒的统计值。它和Window基本相同,除了返回值会除以时间窗口之外。
tally::Counter<int> sum;
// sum_per_second.get_value()是sum在之前60秒内*平均每秒*的累加值,省略最后一个时间窗口的话默认为tally_dump_interval。
tally::PerSecond<tally::Counter<int> > sum_per_second(&sum, 60);
PerSecond并不总是有意义
上面的代码中没有MaxerGauge,因为一段时间内的最大值除以时间窗口是没有意义的。
tally::MaxerGauge<int> max_value;
// 错误!最大值除以时间是没有意义的
tally::PerSecond<tally::MaxerGauge<int> > max_value_per_second_wrong(&max_value);
// 正确,把Window的时间窗口设为1秒才是正确的做法
tally::Window<tally::MaxerGauge<int> > max_value_per_second(&max_value, 1);
Difference with Window
比如要统计内存在上一分钟内的变化,用Window<>的话,返回值的含义是”上一分钟内存增加了18M”,用PerSecond<>的话,返回值的含义是“上一分钟平均每秒增加了0.3M”。
Window的优点是精确值,适合一些比较小的量,比如“上一分钟的错误数“,如果这用PerSecond的话,得到可能是”上一分钟平均每秒产生了0.0167个错误",这相比于”上一分钟有1个错误“显然不够清晰。另外一些和时间无关的量也要用Window,比如统计上一分钟cpu占用率的方法是用一个Counter同时累加cpu时间和真实时间,然后用Window获得上一分钟的cpu时间和真实时间,两者相除就得到了上一分钟的cpu占用率,这和时间无关,用PerSecond会产生错误的结果。
tally::WindowEx
获得之前一段时间内的统计值。WindowEx是独立存在的,不依赖其他的计数器,需要给它发送数据。出于性能考虑,WindowEx每秒对数据做一次统计,在最差情况下,WindowEx的返回值有1秒的延时。
// Get data within a time window.
// The time unit is 1 second fixed.
// Window not relies on other tally.
// R must:
// - window_size must be a constant
template <typename R, time_t window_size = 0>
class WindowEx : public adapter::WindowExAdapter<R, adapter::WindowExType<R> > {
public:
typedef adapter::WindowExAdapter<R, adapter::WindowExType<R> > Base;
WindowEx() : Base(window_size) {}
WindowEx(const base::StringPiece& name) : Base(window_size) {
this->expose(name);
}
WindowEx(const base::StringPiece& prefix,
const base::StringPiece& name)
: Base(window_size) {
this->expose_as(prefix, name);
}
};
How to use tally::WindowEx
const int window_size = 60;
// sum_minute.get_value()是60秒内的累加值,省略最后一个window_size(时间窗口)的话默认为tally_dump_interval。
tally::WindowEx<tally::Counter<int>, window_size> sum_minute("sum_minute");
sum_minute << 1 << 2 << 3;
// max_minute.get_value()是60秒内的最大值,省略最后一个window_size(时间窗口)的话默认为tally_dump_interval。
tally::WindowEx<tally::MaxerGauge<int>, window_size> max_minute("max_minute");
max_minute << 1 << 2 << 3;
// min_minute.get_value()是60秒内的最小值,省略最后一个window_size(时间窗口)的话默认为tally_dump_interval。
tally::WindowEx<tally::MinerGauge<int>, window_size> min_minute("min_minute");
min_minute << 1 << 2 << 3;
// avg_minute.get_value是60秒内的平均值(返回值是tally::Stat),省略最后一个window_size(时间窗口)的话默认为tally_dump_interval。
tally::WindowEx<tally::IntRecorder, window_size> avg_minute("avg_minute");
avg_minute << 1 << 2 << 3;
// 获得avg_minuter 60秒内的平均值stat
tally::Stat avg_stat = avg_minute.get_value();
// 获得整型平均值
int64_t avg_int = avg_stat.get_average_int();
// 获得double类型平均值
double avg_double = avg_stat.get_average_double();
Difference between tally::WindowEx and tally::Window
-
tally::Window 不能独立存在,必须依赖于一个已有的计数器。Window会自动更新,不用给它发送数据;window_size是通过构造函数参数传递的。
-
tally::WindowEx 是独立存在的,不依赖其他的计数器,需要给它发送数据。使用起来比较方便;window_size是通过模板参数传递的,省略最后一个window_size(时间窗口)的话默认为tally_dump_interval。
tally::PerSecondEx
获得之前一段时间内平均每秒的统计值。它和WindowEx基本相 同,除了返回值会除以时间窗口之外。
// Get data per second within a time window.
// The only difference between PerSecondEx and WindowEx is that PerSecondEx divides
// the data by time duration.
// R must:
// - window_size must be a constant
template <typename R, time_t window_size = 0>
class PerSecondEx : public adapter::WindowExAdapter<R, adapter::PerSecondExType<R> > {
public:
typedef adapter::WindowExAdapter<R, adapter::PerSecondExType<R> > Base;
PerSecondEx() : Base(window_size) {}
PerSecondEx(const base::StringPiece& name) : Base(window_size) {
this->expose(name);
}
PerSecondEx(const base::StringPiece& prefix,
const base::StringPiece& name)
: Base(window_size) {
this->expose_as(prefix, name);
}
};
How to use tally::PerSecondEx
const int window_size = 60;
// sum_per_second.get_value()是60秒内*平均每秒*的累加值,省略最后一个window_size(时间窗口)的话默认为tally_dump_interval。
tally::PerSecondEx<tally::Counter<int>, window_size> sum_per_second("sum_per_second");
sum_per_second << 1 << 2 << 3;
Difference between tally::PerSecondEx and tally::WindowEx
- tally::PerSecondEx 获得之前一段时间内平均每秒的统计值。它和WindowEx基本相同,除了返回值会除以时间窗口之外。
Difference between tally::PerSecondEx and tally::PerSecond
- tally::PerSecond 不能独立存在,必须依赖于一个已有的计数器。PerSecond会自动更新,不用给它发送数据;window_size是通过构造函数参数传递的。
- tally::PerSecondEx 是独立存在的,不依赖其他的计数器,需要给它发送数据。使用起来比较方便;window_size是通过模板参数传递的,省略最后一个window_size(时间窗口)的话默认为tally_dump_interval。
tally::Status
记录和显示一个值,拥有额外的set_value函数。
// Display a rarely or periodically updated value.
// Usage:
// tally::Status<int> foo_count1(17);
// foo_count1.expose("my_value");
//
// tally::Status<int> foo_count2;
// foo_count2.set_value(17);
//
// tally::Status<int> foo_count3("my_value", 17);
//
// Notice that Tp needs to be std::string or acceptable by boost::atomic<Tp>.
template <typename Tp>
class Status : public Variable;
tally::FuncGauge
按需显示值。在一些场合中,我们无法set_value或不知道以何种频率set_value,更适合的方式也许是当需要显示时才打印。用户传入打印回调函数实现这个目的。
// Display a updated-by-need value. This is done by passing in an user callback
// which is called to produce the value.
// Example:
// int print_number(void* arg) {
// ...
// return 5;
// }
//
// // number1 : 5
// tally::FuncGauge status1("number1", print_number, arg);
//
// // foo_number2 : 5
// tally::FuncGauge status2(typeid(Foo), "number2", print_number, arg);
template <typename Tp>
class FuncGauge : public Variable;
虽然很简单,但FuncGauges是最有用的tally之一,因为很多统计量已经存在,我们不需要再次存储它们,而只要按需获取。比如下面的代码声明了一个在linux下显示进程用户名的tally:
static void get_username(std::ostream& os, void*) {
char buf[32];
if (getlogin_r(buf, sizeof(buf)) == 0) {
buf[sizeof(buf)-1] = '\0';
os << buf;
} else {
os << "unknown";
}
}
PassiveStatus<std::string> g_username("process_username", get_username, NULL);