1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
# Field Stat 2简介
Field Stat是一个运行状态输出与统计库。
## 本地显示风格(style)
本地显示会输出到屏幕或文件,可选择输出瞬时值 `FS_CALC_SPEED`或累计值`FS_CALC_CURRENT`。
允许在`FS_start`启动后注册非Column的统计域。
### 域(Field )
`FS_STYLE_FIELD` 同时输出累计值(sum)和瞬时值(speed/s,1秒内的变化值)。
```
field_00 field_01
sum 0 184300
speed/s 0 92150
```
函数接口
```c
field_ids[i]=FS_register(handle, FS_STYLE_FIELD, FS_CALC_CURRENT, "field_01");
```
### 状态(Status)
`FS_STYLE_STATUS` ,可以输出当前值(FS_CALC_CURRENT)或速度值(FS_CALC_SPEED)。
```c
status_00: 100 status_01: 10
```
输出前值(FS_CALC_CURRENT)时,StatsD输出会采用Histogram类型,以便telegraf对其进行聚合。例如下面的grafana查询语句:
`SELECT sum("value_sum") / 5 FROM "[tango_cache]SESSION_REDIS" WHERE $timeFilter GROUP BY time(10s) fill(linear)`
该语句在聚合多个节点上SESSION_REDIS的总数,group by 的时间为10s,因为FieldStat的输出间隔为2秒(初始化时由`STAT_CYCLE`参数设置,默认2s),所以sum("value_sum") 的值要再除以5。
注意:在使用多个FieldStat实例时,`STAT_CYCLE`必须设定为相同的值。
函数接口
```
status_ids[i]=FS_register(handle, FS_STYLE_STATUS, FS_CALC_CURRENT, "status_01");
```
### 表格 (Line&Column)
`FS_STYLE_LINE`和`FS_STYLE_COLUMN `输出当前值或速度值。
```
___________________________________________________________________________________________________
column_0 column_1 column_3 column_4 column_5 c0/c1
line_0 2.76e+04 5.53e+04 1.11e+05 1.38e+05 1.66e+05 5.00e-01
line_1 2.76e+04 5.53e+04 1.11e+05 1.38e+05 1.66e+05 5.00e-01
line_2 2.76e+04 5.53e+04 1.11e+05 1.38e+05 1.66e+05 5.00e-01
line_3 2.76e+04 5.53e+04 1.11e+05 1.38e+05 1.66e+05 5.00e-01
line_4 2.76e+04 5.53e+04 1.11e+05 1.38e+05 1.66e+05 5.00e-01
line_5 2.76e+04 5.53e+04 1.11e+05 1.38e+05 1.66e+05 5.00e-01
line_6 2.76e+04 5.53e+04 1.11e+05 1.38e+05 1.66e+05 5.00e-01
```
函数接口 API
```
line_ids[i]=FS_register(handle, FS_STYLE_LINE, FS_CALC_CURRENT, "line_0");
column_ids[i]=FS_register(handle, FS_STYLE_COLUMN, FS_CALC_SPEED,"column_0");
```
### 分布图 (Histogram)
`FS_STYLE_HISTOGRAM` 输出事件的数值分布,如延迟,文件长度等。
```
histogram 50% 80% 95% MAX MIN AVG STDDEV CNT
ssl_up(ms) 0 0 0 0 0 0.00 0.00 0
peek_sni(ms) 0 0 0 0 0 0.00 0.00 0
ssl_down(ms) 0 0 0 0 0 0.00 0.00 0
ask_kyr(ms) 0 0 0 0 0 0.00 0.00 0
```
默认输出 50%,80.00%,90%,95%和99%的比例, 可以通过 `FS_set_para` 函数的`HISTOGRAM_GLOBAL_BINS`选项修改。
缩写定义:
- MAX 最大值
- MIN 最小值
- AVG 平均值
- STDDEV 标准差
- CNT 计数
函数接口
```
fs_metric_sql_exec=FS_register_histogram(g_info.fs_handle, //Field Stat句柄
FS_CALC_CURRENT, //输出累计值或瞬时值
"sql_exec(us)", //统计项名称,字符串
1, //可追踪的最小值
1000000, //可追踪的最大值
2); //精度,即小数点后几位,范围1~4
```
## 远程输出
可以输出为[StatsD](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/statsd)格式或 [InfluxDB Inline Protocol](https://docs.influxdata.com/influxdb/v1.7/write_protocols/line_protocol_tutorial/)格式,通过UDP协议发送给聚合器,如telegraf。 聚合器接收并聚合后,写入时序数据库,如InfluxDB,然后通过图形界面展示,如Grafana。
StatsD 输出counter和histogram两种metric,metric name命名遵循
- Field和Status: ` [APP_NAME]field_name:value`
- Column和Line:`[APP_NAME]line#column:value`
Influx Line命名规则为
```
measurement, tag, key1=value1, key2=value2
line,app_name=APPNAME column1=value,column2=value
```
可以通过 `FS_set_para`函数 的`STATS_SERVER_IP ` 、`STATS_SERVER_PORT`选项,设置服务器的IP和端口。通过`STATS_FORMAT`选项设置输出格式为`FS_OUTPUT_STATSD`或`FS_OUTPUT_INFLUX_LINE`。
服务端搭建流程参见[《【StatsD监控】基于Telegraf+InfluxDB+grafana展示(非Docker方案)》](https://blog.csdn.net/littlefang/article/details/78473161)。聚合Histogram建议修改telegraf.conf的以下配置项:
```
[[inputs.statsd]]
protocol = "udp4"
service_address = ":8125"
percentiles = [20,30,40,50,60,70,80,90,95,99]
percentile_limit = 100000000
```
## 统计
### 记录统计值
通过`FS_operate`函数操作统计域,函数内部使用原子变量,无锁且线程安全。
```
//handle: FieldStat句柄
//id: FS_register_**返回的ID
//column_id: 列ID,非column类型填0
//filed_op: FS_OP_ADD: + value
// FS_OP_SUB: - value
// FS_OP_SET: = value
int FS_operate(screen_stat_handle_t handle,int id,int column_id,enum field_op op,long long value);
```
### 记录事件耗时
应使用clock_gettime函数获得事件的耗时,[永远不要用gettimeofday计算时间](https://blog.habets.se/2010/09/gettimeofday-should-never-be-used-to-measure-time.html)。
也可使用field_stat2.h中提供的简单封装。
```
struct timespec start;
record_time_start(&start);
//do something
long eplapses=record_time_elapse_us(&start);
FS_operate(fs_handle, histogram_id, 0, FS_OP_SET, eplapsed);
```
## 使用建议
### 命名建议
在命名时,遵循按照以下规则:
1. 带上单位,如bytes或kb,微秒us或毫秒ms等。
2. 除若干单词首字母组成的缩写外,不要大写。如Kernel Network Interface 可以缩写为KNI,packet缩写为pkt,而不是PKT
3. 一般不要超过10个字节,不然本地刷新不美观。
- htable->htab, read->rd,write->wr,send ->tx,receive->rx
- send packets,可缩写为tx_pkts,send bytes可缩写为tx_bytes
禁止注册名称包含 `|:\n\r. \t<>[]#!@`的统计域。
### 显示字段数量
Status和Field每行固定展示8个统计值。Column和Histogram取决于注册数量,建议Column一般不超过8个,Histogram的bins不超过5个。
通过`FS_set_para`函数的 `ID_INVISBLE`不显示的字段,可以节约屏幕空间;通过 `FS_register_ratio`计算两个统计字段的比值。
### 本地结果查看
在shell执行`watch -d cat 日志文件`,观察实时的输出结果。
|