| - [mbvar Introduction](#mbvar-introduction) |
| - [bvar::MVariables](#bvarmvariables) |
| - [expose](#expose) |
| - [expose](#expose-1) |
| - [expose_as](#expose_as) |
| - [Export all MVariable](#export-all-mvariable) |
| - [count](#count) |
| - [count_exposed](#count_exposed) |
| - [list](#list) |
| - [list_exposed](#list_exposed) |
| - [bvar::MultiDimension](#bvarmultidimension) |
| - [constructor](#constructor) |
| - [stats](#stats) |
| - [get_stats](#get_stats) |
| - [count](#count-1) |
| - [count_labels](#count_labels) |
| - [count_stats](#count_stats) |
| - [list](#list-1) |
| - [list_stats](#list_stats) |
| - [template](#template) |
| - [bvar::Adder](#bvaradder) |
| - [bvar::Maxer](#bvarmaxer) |
| - [bvar::Miner](#bvarminer) |
| - [bvar::IntRecorder](#bvarintrecorder) |
| - [bvar::LatencyRecorder](#bvarlatencyrecorder) |
| - [bvar::Status](#bvarstatus) |
| - [bvar::WindowEx](#bvarwindowex) |
| - [bvar::PerSecondEx](#bvarpersecondex) |
| |
| # mbvar Introduction |
| |
| 多维度mbvar使用文档 |
| |
| mbvar中有两个类,分别是MVariable和MultiDimension,MVariable是多维度统计的基类,MultiDimension是派生模板类,目前支持如下几种类型: |
| |
| | bvar类型 | 说明 | |
| | ------ | ------ | |
| | bvar::Adder<T> | 计数器,默认0,varname << N相当于varname += N。 | |
| | bvar::Maxer<T> | 求最大值,默认std::numeric_limits<T>::min(),varname << N相当于varname = max(varname, N)。 | |
| | bvar::Miner<T> | 求最小值,默认std::numeric_limits<T>::max(),varname << N相当于varname = min(varname, N)。 | |
| | bvar::IntRecorder | 求自使用以来的平均值。注意这里的定语不是“一段时间内”。一般要通过Window衍生出时间窗口内的平均值。 | |
| | bvar::LatencyRecorder | 专用于记录延时和qps的变量。输入延时,平均延时/最大延时/qps/总次数 都有了。 | |
| | bvar::Status<T> | 记录和显示一个值,拥有额外的set_value函数。 | |
| | bvar::WindowEx<R, T> | 获得之前一段时间内的统计值。WindowEx是独立存在的,不依赖其他的计数器,需要给它发送数据。 | |
| | bvar::PerSecondEx<T> | 获得之前一段时间内平均每秒的统计值。PerSecondEx是独立存在的,不依赖其他的计数器,需要给它发送数据。 | |
| |
| 例子: |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| // bvar::MultiDimension<bvar::Adder<int> > g_request_count("foo_bar", "request_count", {"idc", "method", "status"}); |
| |
| int process_request(const std::list<std::string>& request_label) { |
| // 获取request_label对应的单维度bvar指针,比如:request_label = {"tc", "get", "200"} |
| bvar::Adder<int>* adder = g_request_count.get_stats(request_label); |
| // 判断指针非空 |
| if (!adder) { |
| return -1; |
| } |
| // adder只能在g_request_count的生命周期内访问,否则行为未定义,可能会出core |
| // 给adder输入一些值 |
| *adder << 1 << 2 <<3; |
| LOG(INFO) << "adder=" << *adder; // adder add up to 6 |
| ... |
| return 0; |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| # bvar::MVariables |
| MVariale是MultiDimension(多维度统计)的基类,主要提供全局注册、列举、查询和dump等功能。 |
| |
| ## expose |
| |
| ### expose |
| |
| 用户在创建mbvar变量(bvar::MultiDimension)的时候,如果使用一个参数的构造函数(共有三个构造函数),这个mbvar并未注册到任何全局结构中(当然也不会dump到本地文件),在这种情况下,mbvar纯粹是一个更快的多维度计数器。我们称把一个mbvar注册到全局表中的行为为“曝光”,可以通过expose函数曝光: |
| |
| ```c++ |
| class MVariable { |
| public |
| ... |
| // Expose this mvariable globally so that it's counted in following |
| // functions: |
| // list_exposed |
| // count_exposed |
| // Return 0 on success, -1 otherwise. |
| int expose(const base::StringPiece& name); |
| int expose_as(const base::StringPiece& prefix, const base::StringPiece& name); |
| }; |
| ``` |
| |
| 全局曝光后的mbvar名字便为name或者prefix+name,可通过以_exposed为后缀的static函数查询。比如MVariable::describe_exposed(name)会返回名为name的mbvar的描述。 |
| |
| 当相同名字的mbvar已存在时,expose会打印FATAL日志并返回-1。如果选项-bvar_abort_on_same_name设为true (默认是false),程序会直接abort。 |
| |
| 下面是一些曝光mbvar的例子: |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| // 换一个名字 |
| g_request_count->expose("request_count_another"); |
| |
| int process_request(const std::list<std::string>& request_label) { |
| // 获取request_label对应的单维度bvar指针,比如:request_label = {"tc", "get", "200"} |
| bvar::Adder<int>* adder = g_request_count.get_stats(labels_value); |
| // 判断指针非空 |
| if (!adder) { |
| return -1; |
| } |
| |
| //adder只能在g_request_count的生命周期内访问,否则行为未定义,可能会出core |
| *adder << 10 << 20 << 30; // adder add up to 60 |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### expose_as |
| |
| 为了避免重名,mbvar的名字应加上前缀,建议为\<namespace\>\_\<module\>\_\<name\>。为了方便使用,我们提供了expose_as函数,接收一个前缀。 |
| ```c++ |
| class MVariable { |
| public |
| ... |
| // Expose this mvariable with a prefix. |
| // Example: |
| // namespace foo { |
| // namespace bar { |
| // |
| // bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| // g_request_count.expose_as("foo_bar", "request_count"); |
| // ... |
| // |
| // } // foo |
| // } // bar |
| int expose_as(const base::StringPiece& prefix, const base::StringPiece& name); |
| }; |
| ``` |
| |
| ## Export all MVariable |
| 提供dump_exposed函数导出进程中所有已曝光的mbvar: |
| |
| ```c++ |
| // Implement this class to write mvariables into different places. |
| // If dump() returns false, MVariable::dump_exposed() skip and continue dump. |
| class Dumper { |
| public: |
| virtual bool dump(const std::string& name, const base::StringPiece& description) = 0; |
| }; |
| |
| // Options for MVariable::dump_exposed(). |
| struct DumpOptions { |
| // Contructed with default options. |
| DumpOptions(); |
| // If this is true, string-type values will be quoted. |
| bool quote_string; |
| // The ? in wildcards. Wildcards in URL need to use another character |
| // because ? is reserved. |
| char question_mark; // 目前不支持 |
| // Separator for white_wildcards and black_wildcards. |
| char wildcard_separator; // 目前不支持 |
| // Name matched by these wildcards (or exact names) are kept. |
| std::string white_wildcards; // 目前不支持 |
| // Name matched by these wildcards (or exact names) are skipped. |
| std::string black_wildcards; // 目前不支持 |
| }; |
| |
| class MVariable { |
| ... |
| ... |
| // Find all exposed mvariables and send them to `dumper'. |
| // Use default options when `options' is NULL. |
| // Return number of dumped mvariables, -1 on error. |
| static size_t dump_exposed(Dumper* dumper, const DumpOptions* options); |
| }; |
| ``` |
| |
| 最常见的导出需求是通过HTTP接口查询和写入本地文件,多维度统计支持通过内置服务`/brpc_metrics`接口方式查询。也支持写入本地文件,该功能由下面5个gflags控制,你的程序需要使用gflags。 |
| |
| | 名称 | 默认值 | 描述 | |
| | ------ | ------ | ------ | |
| | mbvar_dump |false | Create a background thread dumping(shares the same thread as bvar_dump) all mbvar periodically, all bvar_dump_* flags are not effective when this flag is off | |
| | mbvar_dump_file | monitor/mbvar.\<app\>.data | Dump mbvar into this file | |
| | mbvar_dump_format | common | Dump mbvar write format <br> common:文本格式,Key和Value用冒号分割(和目前的单维度dump文件格式一致) <br><br> prometheus:文本格式,Key和Value用空格分开protobuf:二进制格式,暂时不支持| |
| | bvar_dump_interval | 10 |Seconds between consecutive dump | |
| | mbvar_dump_prefix | \<app\> | Every dumped name starts with this prefix | |
| | bvar_max_dump_multi_dimension_metric_number | 0 | 最多导出的mbvar的bvar个数,默认是0,即不导出任何mbvar | |
| |
| 用户可在程序启动前加上对应的gflags。 |
| |
| >当mbvar_dump=true并且mbvar_dump_file不为空时,程序会启动一个后台导出线程以bvar_dump_interval指定的间隔更新mbvar_dump_file,其中包含所有的多维统计项mbvar。 |
| |
| 比如我们把所有的gflags修改为下表: |
| | 名称 | 默认值 | 描述 | |
| | ------ | ------ | ------ | |
| | mbvar_dump |true | Create a background thread dumping(shares the same thread as bvar_dump) all mbvar periodically, all bvar_dump_* flags are not effective when this flag is off | |
| | mbvar_dump_file | monitor/mbvar.\<app\>.data | Dump mbvar into this file | |
| | mbvar_dump_format | common | Dump mbvar write format <br> common:文本格式,Key和Value用冒号分割(和目前的单维度dump文件格式一致) <br><br> prometheus:文本格式,Key和Value用空格分开protobuf:二进制格式,暂时不支持| |
| | bvar_dump_interval | 10 |Seconds between consecutive dump | |
| | mbvar_dump_prefix | mbvar | Every dumped name starts with this prefix | |
| | bvar_max_dump_multi_dimension_metric_number | 2000 | 最多导出的mbvar的bvar个数,默认是0,即不导出任何mbvar | |
| |
| 导出的本地文件为monitor/mbvar.\<app\>.data: |
| ``` |
| mbvar_test_concurrent_write_and_read{idc=idc3,method=method6,status=status40} : 76896 |
| mbvar_test_concurrent_write_and_read{idc=idc5,method=method6,status=status36} : 147910 |
| mbvar_test_concurrent_write_and_read{idc=idc5,method=method12,status=status23} : 209270 |
| mbvar_test_concurrent_write_and_read{idc=idc3,method=method1,status=status6} : 116325 |
| mbvar_test_concurrent_write_and_read{idc=idc5,method=method10,status=status29} : 193536 |
| mbvar_test_concurrent_write_and_read{idc=idc5,method=method15,status=status6} : 294726 |
| mbvar_test_concurrent_write_and_read{idc=idc3,method=method2,status=status13} : 136676 |
| mbvar_test_concurrent_write_and_read{idc=idc2,method=method5,status=status49} : 43203 |
| mbvar_test_concurrent_write_and_read{idc=idc5,method=method10,status=status1} : 312499 |
| mbvar_test_concurrent_write_and_read{idc=idc1,method=method10,status=status35} : 35698 |
| ``` |
| |
| 如果你的程序没有使用brpc,仍需要动态修改gflags(一般不需要),可以调用google::SetCommandLineOption(),如下所示: |
| |
| ```c++ |
| #include <gflags/gflags.h> |
| ... |
| if (google::SetCommandLineOption("mbvar_dump_format", "prometheus").empty()) { |
| LOG(ERROR) << "Fail to set mbvar_dump_format"; |
| return -1; |
| } |
| LOG(INFO) << "Successfully set mbvar_dump_format to prometheus"; |
| ``` |
| |
| >请勿直接设置 FLAGS_mbvar_dump_file / FLAGS_mbvar_dump_format / FLAGS_bvar_dump_prefix,如果有需求可以调用google::SetCommandLineOption()方法进行修改。 |
| |
| 一方面这些gflag类型都是std::string,直接覆盖是线程不安全的;另一方面不会触发validator(检查正确性的回调),所以也不会启动后台导出线程。 |
| |
| |
| ## count |
| 统计相关函数 |
| ```c++ |
| class MVariable { |
| public: |
| ... |
| // Get number of exposed mvariables |
| static size_t count_exposed(); |
| }; |
| ``` |
| |
| ### count_exposed |
| |
| 获取目前已经曝光的多维度统计项mbvar的个数,注意:这里是多维度统计项(多维度mbvar变量),而不是维度数。 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| // 定义另一个全局多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_psmi_count("psmi_count", {"product", "system", "module", "interface"}); |
| |
| size_t count_exposed() { |
| size_t mbvar_count_exposed = bvar::MVariable::count_exposed(); |
| CHECK_EQ(2, mbvar_count_exposed); |
| return mbvar_count_exposed; |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| 使用说明 |
| > 一般情况下用不到count_系列统计函数,如果有特殊需求,也不建议频繁调用。 |
| |
| |
| ## list |
| ```c++ |
| class MVariable { |
| public: |
| ... |
| // Put names of all exposed mbvariable into `names' |
| static size_t list_exposed(std::vector<std::string>* names); |
| }; |
| ``` |
| |
| ### list_exposed |
| 获取所有曝光的多维度统计项mbvar名称 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| // 定义另一个全局多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_psmi_count("psmi_count", {"product", "system", "module", "interface"}); |
| |
| size_t mbvar_list_exposed(std::vector<std::string>* names) { |
| if (!names) { |
| return -1; |
| } |
| |
| // clear |
| names.clear(); |
| bvar::MVariable::list_exposed(names); |
| // names:[ "request_count", "psmi_count" ] |
| CHECK_EQ(2, names->size()); |
| return names->size(); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| # bvar::MultiDimension |
| |
| 多维度统计的实现,主要提供bvar的获取、列举等功能。 |
| |
| 为了兼容旧的用法,KeyType默认类型是std::list<std::string>。KeyType必须是(STL或者自定义)容器,value_type必须是std::string。 |
| |
| ## constructor |
| |
| 有三个构造函数: |
| ```c++ |
| template <typename T, typename KeyType = std::list<std::string>> |
| class MultiDimension : public MVariable { |
| public: |
| // 不建议使用 |
| explicit MultiDimension(const key_type& labels); |
| |
| // 推荐使用 |
| MultiDimension(const base::StringPiece& name, |
| const key_type& labels); |
| // 推荐使用 |
| MultiDimension(const base::StringPiece& prefix, |
| const base::StringPiece& name, |
| const key_type& labels); |
| ... |
| }; |
| ``` |
| |
| **explicit MultiDimension(const key_type& labels)** |
| |
| * ~~不建议使用~~ |
| * 不会“曝光”多维度统计变量(mbvar),即没有注册到任何全局结构* 中 |
| * 不会dump到本地文件,即使-bvar_dump=true、-mbvar_dump_file不为空 |
| * mbvar纯粹是一个更快的多维度计数器 |
| |
| **MultiDimension(const base::StringPiece& name, const key_type& labels)** |
| |
| * **推荐使用** |
| * 会曝光(调用MVariable::expose(name)),也会注册到全局结构中 |
| * -bvar_dump=true时,会启动一个后台导出线程以bvar_dump_interval指定的时间间隔更新mbvar_dump_file文件 |
| |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| **MultiDimension(const base::StringPiece& prefix, const base::StringPiece& name, const key_type& labels)** |
| * **推荐使用** |
| * 会曝光(调用MVariable::expose_as(prefix, name)),也会注册到全局结构中 |
| * -bvar_dump=true时,会启动一个后台导出线程以bvar_dump_interval指定的时间间隔更新mbvar_dump_file文件 |
| |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("foo_bar", "request_count", {"idc", "method", "status"}); |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ## stats |
| ```c++ |
| template <typename T, typename KeyType = std::list<std::string>> |
| class MultiDimension : public MVariable { |
| public: |
| ... |
| |
| // Get real bvar pointer object |
| // Return real bvar pointer(Not NULL) on success, NULL otherwise. |
| T* get_stats(const std::list<std::string>& labels_value); |
| }; |
| ``` |
| |
| ### get_stats |
| |
| 根据指定label获取对应的单维度统计项bvar。 |
| |
| get_stats除了支持(默认)std::list<std::string>参数类型,也支持自定义参数类型,满足以下条件: |
| 1. (STL或者自定义)容器。 |
| 2. K::value_type支持通过operator std::string()转换为std::string和通过operator butil::StringPiece()转换为butil::StringPiece。 |
| 3. K::value_type支持和std::string进行比较。 |
| |
| 推荐使用不需要分配内存的容器(例如,std::array、absl::InlinedVector)和不需要拷贝字符串的数据结构(例如,const char*、std::string_view、butil::StringPieces),可以提高性能。 |
| |
| bvar::MultiDimension的模板参数Shared,默认为false: |
| 1. 如果Shared等于false,get_stats返回模板参数T的指针,例如bvar::Adder<int>*。 |
| 2. 如果Shared等于true,get_stats返回模板参数T的shared_ptr,例如std::shared_ptr\<bvar::Adder<int>\>。 |
| |
| **注意**:因为shared_ptr的开销,Shared等于true的性能会比Shared等于false的性能差一些。 |
| |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| template <typename K> |
| int get_request_count(const K& request_label) { |
| // 获取request_label对应的单维度bvar指针,比如:request_label = {"tc", "get", "200"} |
| bvar::Adder<int> *request_adder = g_request_count.get_stats(request_label); |
| // 判断指针非空 |
| if (!request_adder) { |
| return -1; |
| } |
| |
| // request_adder只能在g_request_count的生命周期内访问,否则行为未定义,可能会出core |
| *request_adder << 1; |
| return request_adder->get_value(); |
| } |
| |
| std::list<std::string> request_label_list = {"tc", "get", "200"}; |
| int request_count = get_request_count(request_label_list); |
| |
| std::vector<std::string_view> request_label_list = {"tc", "get", "200"}; |
| int request_count = get_request_count(request_label_list); |
| |
| std::vector<butil::StringPiece> request_label_list = {"tc", "get", "200"}; |
| int request_count = get_request_count(request_label_list); |
| |
| class MyStringView { |
| public: |
| MyStringView() : _ptr(NULL), _len(0) {} |
| MyStringView(const char* str) |
| : _ptr(str), |
| _len(str == NULL ? 0 : strlen(str)) {} |
| #if __cplusplus >= 201703L |
| MyStringView(const std::string_view& str) |
| : _ptr(str.data()), _len(str.size()) {} |
| #endif // __cplusplus >= 201703L |
| MyStringView(const std::string& str) |
| : _ptr(str.data()), _len(str.size()) {} |
| MyStringView(const char* offset, size_t len) |
| : _ptr(offset), _len(len) {} |
| |
| const char* data() const { return _ptr; } |
| size_t size() const { return _len; } |
| |
| // Converts to `std::basic_string`. |
| explicit operator std::string() const { |
| if (NULL == _ptr) { |
| return {}; |
| } |
| return {_ptr, size()}; |
| } |
| |
| // Converts to butil::StringPiece. |
| explicit operator butil::StringPiece() const { |
| if (NULL == _ptr) { |
| return {}; |
| } |
| return {_ptr, size()}; |
| } |
| |
| private: |
| const char* _ptr; |
| size_t _len; |
| }; |
| |
| bool operator==(const MyStringView& x, const std::string& y) { |
| if (x.size() != y.size()) { |
| return false; |
| } |
| return butil::StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; |
| } |
| bool operator==(const std::string& x, const MyStringView& y) { |
| if (x.size() != y.size()) { |
| return false; |
| } |
| return butil::StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; |
| } |
| |
| std::vector<MyStringView> request_label_list = {"tc", "get", "200"}; |
| int request_count = get_request_count(request_label_list); |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| **内部实现逻辑** |
| |
| 判断该label是否已经存在对应的单维度统计项bvar: |
| |
| * 存在 |
| * return bvar |
| * 不存在 |
| * new bvar() |
| * store(bvar) |
| * return bvar |
| |
| ### delete_stats |
| |
| 根据指定label删除对应的单维度统计项bvar。 |
| |
| bvar::MultiDimension的模板参数Shared,默认为false: |
| 1. 如果Shared等于false,get_stats返回的是模板参数T的指针,delete_stats无法保证没有使用者,所以无法安全删除bvar。 |
| 2. 如果Shared等于true,get_stats返回的是模板参数T的shared_ptr,delete_stats可以安全删除bvar。 |
| |
| ### clear_stats |
| |
| 清理所有单维度统计项bvar。 |
| |
| 安全性同样受bvar::MultiDimension的模板参数Shared的影响,见delete_stats一节说明。 |
| |
| **bvar的生命周期** |
| |
| label对应的单维度统计项bvar存储在多维度统计项(mbvar)中,当mbvar析构的时候会释放自身所有bvar,所以用户必须保证在mbvar的生命周期之内操作bvar,在mbvar生命周期外访问bvar的行为未定义,极有可能出core。 |
| |
| ## count |
| ```c++ |
| class MVariable { |
| public: |
| ... |
| |
| // Get number of mvariable labels |
| size_t count_labels() const; |
| }; |
| |
| template <typename T, typename KeyType = std::list<std::string>> |
| class MultiDimension : public MVariable { |
| public: |
| ... |
| |
| // Get number of stats |
| size_t count_stats(); |
| }; |
| ``` |
| |
| ### count_labels |
| |
| 获取多维度统计项的labels个数,用户在创建多维度(bvar::MultiDimension)统计项的时候,需要提供类型为std::list\<std::string\>的labels变量,我们提供了count_labels函数,返回labels的长度。 |
| |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| size_t count_labels() { |
| size_t mbvar_count_labels = g_request_count.count_labels(); |
| CHECK_EQ(3, mbvar_count_labels); |
| return mbvar_count_labels; |
| } |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### count_stats |
| |
| 获取多维度(bvar::MultiDimension)统计项的维度(stats)数 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| size_t count_stats() { |
| // 获取request1对应的单维度mbvar指针,假设request1_labels = {"tc", "get", "200"} |
| bvar::Adder<int> *request1_adder = g_request_count.get_stats(request1_labels); |
| // 判断指针非空 |
| if (!request1_adder) { |
| return -1; |
| } |
| // request1_adder只能在g_request_count生命周期内访问,否则行为未定义,可能会出core |
| *request1_adder << 1; |
| |
| // 获取request2对应的单维度mbvar指针,假设request2_labels = {"nj", "get", "200"} |
| bvar::Adder<int> *request2_adder = g_request_count.get_stats(request2_labels); |
| // 判断指针非空 |
| if (!request2_adder) { |
| return -1; |
| } |
| // request2_adder只能在g_request_count生命周期内访问,否则行为未定义,可能会出core |
| *request2_adder << 1; |
| |
| |
| size_t mbvar_count_stats = g_request_count.count_stats(); |
| CHECK_EQ(2, mbvar_count_stats); |
| return mbvar_count_stats; |
| } |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ## list |
| ```c++ |
| template <typename T, typename KeyType = std::list<std::string>> |
| class MultiDimension : public MVariable { |
| public: |
| ... |
| // Put all stats labels into `names' |
| void list_stats(std::vector<std::list<std::string> >* names); |
| }; |
| ``` |
| |
| ### list_stats |
| 获取一个多维度统计项下所有labels组合列表 |
| |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_count("request_count", {"idc", "method", "status"}); |
| |
| size_t list_stats(std::vector<std::list<std::string> > *stats_names) { |
| if (!stats_names) { |
| return -1; |
| } |
| |
| // clear |
| stats_names.clear(); |
| |
| // 获取request1对应的单维度mbvar指针,假设request1_labels = {"tc", "get", "200"} |
| bvar::Adder<int> *request1_adder = g_request_count.get_stats(request1_labels); |
| // 判断指针非空 |
| if (!request1_adder) { |
| return -1; |
| } |
| |
| // 获取request2对应的单维度mbvar指针,假设request2_labels = {"nj", "get", "200"} |
| bvar::Adder<int> *request2_adder = g_request_count.get_stats(request2_labels); |
| // 判断指针非空 |
| if (!request2_adder) { |
| return -1; |
| } |
| |
| g_request_count.list_stats(stats_names); |
| // labels_names: |
| // [ |
| // {"tc", "get", "200"}, |
| // {"nj", "get", "200"} |
| // ] |
| |
| CHECK_EQ(2, stats_names.size()); |
| return stats_names.size(); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| **使用说明** |
| |
| 一般情况下用户不需要获取labels组合列表,如果有特殊需求,也不建议频繁调用,否则可能影响get_stats的写入性能。 |
| |
| ## template |
| |
| ### bvar::Adder |
| 顾名思义,用于累加 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Adder<int> > g_request_cost("request_count", {"idc", "method", "status"}); |
| |
| int request_cost_total(const std::list<std::string>& request_labels) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::Adder<int>* cost_add = g_request_cost.get_stats(request_labels); |
| // 判断指针非空 |
| if (!cost_add) { |
| return -1; |
| } |
| // cost_add只能在g_request_cost生命周期内访问,否则行为未定义,可能会出core |
| *cost_add << 1 << 2 << 3 << 4; |
| CHECK_EQ(10, cost_add->get_value()); |
| return cost_add->get_value(); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### bvar::Maxer |
| 用于取最大值,运算符为std::max |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Maxer<int> > g_request_cost("request_cost", {"idc", "method", "status"}); |
| |
| int request_cost_max(const std::list<std::string>& request_labels) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::Maxer<int>* cost_max = g_request_cost.get_stats(request_labels); |
| // 判断指针非空 |
| if (!cost_max) { |
| return -1; |
| } |
| |
| // cost_max只能在g_request_cost生命周期内访问,否则行为未定义,可能会出core |
| *cost_max << 1 << 2 << 3 << 4; |
| CHECK_EQ(4, cost_max->get_value()); |
| return cost_max->get_value(); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### bvar::Miner |
| 用于取最小值,运算符为std::min |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Miner<int> > g_request_cost("request_cost", {"idc", "method", "status"}); |
| |
| int request_cost_min(const std::list<std::string>& request_labels) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::Miner<int>* cost_min = g_request_cost.get_stats(request_labels); |
| // 判断指针非空 |
| if (!cost_min) { |
| return -1; |
| } |
| |
| // cost_min只能在g_request_cost生命周期内访问,否则行为未定义,可能会出core |
| *cost_min << 1 << 2 << 3 << 4; |
| CHECK_EQ(1, cost_min->get_value()); |
| return cost_min->get_value(); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### bvar::IntRecorder |
| 用于计算平均值。 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::IntRecorder> g_request_cost("request_cost", {"idc", "method", "status"}); |
| |
| int request_cost_avg(const std::list<std::string>& request_labels) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::IntRecorder* cost_avg = g_request_cost.get_stats(request_labels); |
| // 判断指针非空 |
| if (!cost_avg) { |
| return -1; |
| } |
| |
| // cost_avg只能在g_request_cost生命周期内访问,否则行为未定义,可能会出core |
| *cost_avg << 1 << 3 << 5; |
| CHECK_EQ(3, cost_avg->get_value()); |
| return cost_avg->get_value(); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### bvar::LatencyRecorder |
| 专用于计算latency和qps的计数器。只需填入latency数据,就能获取latency / max_latency / qps / count,统计窗口是bvar_dump_interval。 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::LatencyRecorder> g_request_cost("request_cost", {"idc", "method", "status"}); |
| |
| void request_cost_latency(const std::list<std::string>& request_labels) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::LatencyRecorder* cost_latency = g_request_cost.get_stats(request_labels); |
| // 判断指针非空 |
| if (!cost_latency) { |
| return -1; |
| } |
| |
| // cost_latency只能在g_request_cost生命周期内访问,否则行为未定义,可能会出core |
| *cost_latency << 1 << 2 << 3 << 4 << 5 << 6 << 7; |
| |
| // 获取latency |
| int64_t request_cost_latency = cost_latency->latency(); |
| // 获取max_latency |
| int64_t request_cost_max_latency = cost_latency->max_latency(); |
| // 获取qps |
| int64_t request_cost_qps = cost_latency->qps(); |
| // 获取count |
| int64_t request_cost_count = cost_latency->count(); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### bvar::Status |
| 记录和显示一个值,拥有额外的set_value函数。 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::Status<int> > g_request_cost("request_cost", {"idc", "method", "status"}); |
| |
| void request_cost(const std::list<std::string>& request_labels) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::Status<int>* cost_status = g_request_cost.get_stats(request_labels); |
| // 判断指针非空 |
| if (!cost_status) { |
| return -1; |
| } |
| |
| // cost_status只能在g_request_cost生命周期内访问,否则行为未定义,可能会出core |
| cost_status->set_value(5); |
| CHECK_EQ(5, cost_status->get_value()); |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### bvar::WindowEx |
| 获得之前一段时间内的统计值。 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/window.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::WindowEx<bvar::Adder<int>, 60>> sum_minute("sum_minute", {"idc", "method", "status"}); |
| |
| void Record(const std::list<std::string>& request_labels, int num) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::WindowEx<bvar::Adder<int>, 60>* status = sum_minute.get_stats(request_labels); |
| // status只能在sum_minute生命周期内访问,否则行为未定义,可能会出core |
| *status << num; |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |
| |
| ### bvar::PerSecondEx |
| 获得之前一段时间内平均每秒的统计值。 |
| ```c++ |
| #include <bvar/bvar.h> |
| #include <bvar/window.h> |
| #include <bvar/multi_dimension.h> |
| |
| namespace foo { |
| namespace bar { |
| // 定义一个全局的多维度mbvar变量 |
| bvar::MultiDimension<bvar::PerSecondEx<bvar::Adder<int>>> sum_per_second("sum_per_second", {"idc", "method", "status"}); |
| |
| void Record(const std::list<std::string>& request_labels, int num) { |
| // 获取request对应的单维度mbvar指针,假设request_labels = {"tc", "get", "200"} |
| bvar::PerSecondEx<bvar::Adder<int>>* status = sum_per_second.get_stats(request_labels); |
| // status只能在sum_per_second生命周期内访问,否则行为未定义,可能会出core |
| *status << num; |
| } |
| |
| } // namespace bar |
| } // namespace foo |
| ``` |