awstats作为一款日志分析软件,功能不错,但是界面过于简单,也没有图表功能,这里我采取了一种变通的方法,将awstats的分析结果(pv、hits(文件数)、bandwidth、visits(独立ip))添加到zabbix,并通过zabbix生成趋势图表。
在前两篇文章中,我们队awstats的使用及其工作方式进行了简明扼要的介绍:awstats对每个站点进行分析之后,会生成一个“awstats012016.txt”格式的“数据库”文件;awstats的展示页面便是从该文件中取数据生成的。
这篇文章的思路就是从这个文本格式的‘数据库文件’中取得我们想要的数据,然后通过自定义的脚本将其添加到zabbix中,最终满足我们生成pv趋势图表的需求。
而完成此任务的关键就是分析似‘awstats052016.txt’的数据文件的内容格式(ps:以笔者“多年”shell经验来看,”分析源文件格式“和“生成目标文件格式”这俩“格式”在日常的shell编程中占用了很大一部分时间。扯远了O(∩_∩)O~)
首先是自定义脚本作为zabbix的key,从对应的‘数据文件’中取得pv、hits、bandwidth、visits的值。用shell实现如下
cat web_pv.sh
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
|
#!/bin/sh
#从例如api/awstats052016.txt这样的awstats数据库文件里取得昨天的pv等统计(因为awstats本身就是统计到昨天的日志)
#by ljk 20160506
#blog http://kaifly.blog.51cto.com/
#shell脚本的$1 $2分别代表站点名称(格式如www或bbs)和统计项(pv 文件数 字节 独立ip)
basedir=
'/usr/local/awstats-7.4/result'
date_f1=$(
date
+%m%Y -d
'1 day ago'
)
date_f2=$(
date
+%Y%m%d -d
'1 day ago'
)
cd
$basedir/$1
#下面关于awk的用法中有一个小技巧,匹配到指定的项之后,停止继续搜索余下的内容。这对于体积较大的文件可以节约不少时间
content=`
awk
'$1 == "'
$date_f2
'" {{print} {exit}}'
awstats$date_f1\.txt`
case
$2
in
"pages"
)
echo
$content|
awk
'{print $2}'
;;
#pv
"hits"
)
echo
$content|
awk
'{print $3}'
;;
#hits/文件数
"bandwidth"
)
echo
$content|
awk
'{print $4}'
;;
#bandwidth/字节
"visits"
)
echo
$content|
awk
'{print $5}'
;;
#visits/独立ip
*)
echo
"unknow value"
;;
esac
|
然后在awstats所在的server的zabbix的‘userparameter.conf’文件中添用户自定义key,并重启zabbix_agentd
1
|
UserParameter=web_pv[*],
/bin/sh
/usr/local/zabbix/etc/zabbix_agentd
.conf.d
/web_pv
.sh $1 $2
|
接着在zabbix_server端通过zabbix_get命令尝试获取这些值,key格式为“web_pv[站点名,监控项]”,例如
能取到值,说明自定义key是ok的。
接下来就是在zabbix里添加各站点的item了,这里通过Python实现(zbx接口通过json传递数据,处理json python比shell方便太多了)
这里需要仔细阅读下zabbix的api文档https://www.zabbix.com/documentation/3.0/manual/api和查看zabbix数据库结构(确保万无一失嘛)
首先在zabbix里创建一个template,名为Template site PV,这一步手动创建即可
然后开始通过Python自动化添加items
cat shells/add_web-pv_item_to_zabbix.py
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
|
#!/bin/env python3
"""
将各站点的4种(pages,hits,bandwidth,visits)item添加/更新到zabbix的 'Template Site-PV'
by ljk 20160507
"""
import
os,requests
basedir
=
'/usr/local/services/awstats-7.4/result/'
items
=
[
'pages'
,
'hits'
,
'bandwidth'
,
'visits'
]
url
=
'http://192.168.1.199/api_jsonrpc.php'
zbx_api_headers
=
{
'Content-Type'
:
'application/json-rpc'
}
#定义通过zabbix api操作时必带的header
#取得用于zabbix api认证的token,通过用户名密码请求api生成
#生成方式请参考api文档,有个这个token,可以省去账号密码认证
api_auth
=
"738024dfda33cc6020fb1f5e3617"
#这里我在前期实验的时候,手动添加了几个item了,所以这里先取出template里已经存在的item,以便后期创建时过滤掉这些item
exist_items_filter
=
{
#通过zabbix api查询已经存在的web_pv[*,*]的item,这里是json格式的过滤条件
"jsonrpc"
:
"2.0"
,
"method"
:
"item.get"
,
"params"
: {
"output"
:[
"name"
,
],
"search"
: {
"key_"
:
"web_pv"
}
},
"auth"
:api_auth,
"id"
:
0
}
exist_items
=
requests.post(url,headers
=
zbx_api_headers,json
=
exist_items_filter)
os.chdir(basedir)
sites
=
os.listdir(path
=
'.'
)
def
create_item():
for
site
in
sites:
for
item
in
items:
if
site
+
'-'
+
item
not
in
exist_items.text:
#先给不同情况下的units和multiplier赋值
if
item
=
=
'pages'
or
item
=
=
'hits'
:
units
=
'万'
multiplier
=
0.0001
elif
item
=
=
'bandwidth'
:
units
=
'B'
multiplier
=
1
else
:
units
=
''
multiplier
=
1
#定义创建item的json数据格式
num
=
10
create_item_post
=
{
"jsonrpc"
:
"2.0"
,
"method"
:
"item.create"
,
"params"
: {
"name"
: site
+
','
+
item,
"key_"
:
"www_pv["
+
site
+
','
+
item
+
"]"
,
"hostid"
:
"10134"
,
"type"
:
0
,
"value_type"
:
3
,
"history"
:
7
,
"delay"
:
28800
,
"units"
: units,
"applications"
: [
774
],
"interfaceid"
:
"0"
,
"formula"
: multiplier
},
"auth"
: api_auth,
"id"
: num
}
try
:
create_item_result
=
requests.post(url,headers
=
zbx_api_headers,json
=
create_item_post)
#打印处理每个条目的结果
print
(
'{}-{}: return_code {} details {}'
.
format
(site,item,create_item_result.status_code,create_item_result.json))
num
+
=
1
except
:
print
(
'{}-{}: error'
.
format
(site,item))
import
sys
sys.exit(
255
)
#create_item()
#update函数,其实是我在执行create_item()的时候将key的名字写错了,无奈在写一个update_item()吧
def
update_item():
num
=
100
#对应zbx api中的id字段,随意指定,确保每次调用api时该值不同即可(这里用自增的方式)
#定义更新item的json数据格式
update
=
{
"jsonrpc"
:
"2.0"
,
"method"
:
"item.update"
,
"params"
: {
"itemid"
: "",
"key_"
: ""
},
"auth"
: api_auth,
"id"
: num
}
#取得site pv模板下所有错误的item(key以www_py开头的),hostid的值实际为template site PV模板的templateid
wrong_items_filter
=
{
"jsonrpc"
:
"2.0"
,
"method"
:
"item.get"
,
"params"
: {
"output"
:[
"key_"
,
"hostid"
],
"search"
: {
"hostid"
:
"10134"
,
"key_"
:
"www_pv"
}
},
"auth"
: api_auth,
"id"
:
0
}
wrong_items
=
requests.post(url,headers
=
zbx_api_headers,json
=
wrong_items_filter).json()[
'result'
]
#wrong_items为list
for
wrong_item
in
wrong_items:
if
wrong_item[
'hostid'
] !
=
'10119'
:
#img2从template site pv继承而来 所以这里每个item对应两条记录对应template site pv的hostid:10134和img2的hostid:10119,所以不需要修改img2的
update[
'params'
][
'itemid'
]
=
wrong_item[
'itemid'
]
update[
'params'
][
'key_'
]
=
wrong_item[
'key_'
].replace(
'www'
,
'web'
,
1
)
try
:
update_item_result
=
requests.post(url,headers
=
zbx_api_headers,json
=
update)
print
(
'{} ---- details {}'
.
format
(wrong_item[
'key_'
],update_item_result.json()))
num
+
=
1
except
:
print
(
'{}-{}: error'
.
format
(site,item))
import
sys
sys.exit(
255
)
#update_item()
|
后续的批量生成image和生成screen都可以通过zbx 的API来完成,这里就不再列举了
ok,最后看两张zabbix生成的靓图吧