使用Python分析nginx日志
专栏作者:熊球
♚ 土木工程毕业,现从事web后端开发方面的工作,擅长python,flask框架等。博客:codechat.cc
github地址:https://github.com/XiongQiuQiu/
相信各位web后端的小伙伴对Nginx并不陌生,它是是一款面向性能设计的HTTP服务器,具有占有内存少,稳定性高等优势。所以很多个人网站,或者公司都会选择使用nginx作为服务器。在使用nginx的时候,每一个http请求都会产生一条日志,通过python分析日志我们可以清楚的了解网站的pv,uv等一些重要数据。
在服务器上我们通常使用logrotate来分割当天日志进行分析, 假设我当天结束分割出的的日志名字为log20101001.gz, 我们使用python的gzip库来读取这个压缩文件所以我们可以直接使用gzip库来打开文件
1. `class an_log(object):`
2. `"""分析记录"""`
3. `def __init__(self, filename):`
4. `self.filename = filename`
5. `self.picid_value = {} # 一个用于存储所有pv,uv的字典`
6.
7. `def read_log(self):`
8. `f = gzip.open(self.filename, 'r')`
9. `for line in f:`
10. `all_line = line.split()`
一般一条nginx数据是这样的:
1. `-
180.171
.
241.42
tb
.
lifehp
.
com
-
-
[
30
/
Oct
/
2016
:
23
:
58
:
03
+
0800
]
"GET /index.php?m=newbar&a=operate&type=1&op=0¶m=A000184&adsid=14&picid=141&time=1477842977818 HTTP/1.1"
200
0.000
342
31
"-"
"Mozilla/5.0 (iPhone; CPU iPhone OS 10\_0\_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Mobile/14A456 MicroMessenger/6.3.29 NetType/WIFI Language/zh\_CN"
"-"
-`
看起来很杂乱无章,其实在分析pv,uv的时候我们着重需要的数据一共只有几个, 一个是ip:
- 180.171.241.42
,
一个是参数:
GET/index.php?m=newbar&a=operate&type=1&op=0¶m=A000184&adsid=14&picid=141&time=1477842977818 HTTP/1.1
, 一个是参数:
GET/index.php?m=newbar&a=operate&type=1&op=0¶m=A000184&adsid=14&picid=141&time=1477842977818 HTTP/1.1
每一个pv是由这些参数共同决定的,如果这些参数全部一致那就是一个pv,如果在参数一致的情况下ip从没出现过那就是一个uv, 所以我们只需要解析这些参数就可以
1. `def read_log(self):`
2. `f = gzip.open(self.filename, 'r')`
3. `for line in f:`
4. `all_line = line.split()`
5. `try:`
6. `a_line = dict(k.split('=') for k in all_line[8].split('&'))`
7. `# 把所有参数解析到一个字典中,key为参数名,value为参数值类似于{type:1,param:A00184}`
8. `ip = all_line[1] # 获取ip`
9. `media_id = a_line['param']`
10. `op = a_line['op']`
11. `except:`
12. `continue`
13. `try:`
14. `adsid = a_line.get('adsid', 'null')`
15. `picid = a_line.get('picid', 'null')`
16. `area_name = a_line.get('area', 'null')`
17. `os = a_line.get('os', '0')`
18. `except:`
19. `continue`
使用try,except语句是因为很多日志并不是我们想要的类似于
GET /small/v10/css/tlbs.css HTTP/1.1
,当碰到这种类型的日志的时候,生成字典后通过try如果提取不到我们需要的参数就说明这条日志不需要,通过continue直接分下一条日志
pic = picid + media\_id + adsid + op + area\_name + os # 把参数组合生成唯一键名
如果键名存在就直接对pv,uv数值操作
1. `if pic in self.picid_value.keys():`
2. `self.analysis_pv(pic)`
3. `self.analysis_uv(pic, ip)`
pv += 1 uv通过判断ip是否存在来判断是否加一
1. `def analysis_pv(self, pic,):`
2. `self.picid_value[pic]['pv'] += 1`
3. `return self.picid_value`
4. `def analysis_uv(self, pic, ip):`
5. `if ip not in self.picid_value[pic]['ip']:`
6. `self.picid_value[pic]['uv'] += 1`
7. `self.picid_value[pic]['ip'].add(ip)`
8. `return self.picid_value`
这里ip要使用set集合,如果使用列表 每次判断ip是否存在都要进行一次遍历时间复杂度为O(n),而集合判断是否存在时间复杂度为O(1)大大提高性能
如果键名不存在则进行初始化键
1. `if pic in self.picid_value.keys():`
2. `self.analysis_pv(pic)`
3. `self.analysis_uv(pic, ip)`
4. `else:`
5. `self.picid_value[pic] = {}`
6. `self.picid_value[pic]['picid'] = picid`
7. `self.picid_value[pic]['adsid'] = adsid`
8. `self.picid_value[pic]['media_id'] = media_id`
9. `self.picid_value[pic]['op'] = op_name_dict[op]`
10. `self.picid_value[pic]['os'] = os_name_dict[os]`
11. `self.picid_value[pic]['pv'] = 0`
12. `self.picid_value[pic]['uv'] = 0`
13. `self.picid_value[pic]['ip'] =set()`
14. `self.picid_value[pic]['area']=area_name_dict[area_name]`
15. `self.analysis_pv(pic)`
16. `self.analysis_uv(pic, ip)`
最后返回一个字典
1. `return
self
.
picid\_value`
然后把分析的数据写入excel,这里我使用的是xlwt库
1. `def write_excel(self, excel_name):`
2. `workbook = xlwt.Workbook()`
3. `worksheet = workbook.add_sheet('toolbar')`
4. `cl_name = [u'媒体', 'op', 'os', 'adsid', 'picid', u'位置', 'pv', 'uv']`
5. `c = 0`
6. `for data in cl_name:`
7. `worksheet.write(0, c, data)`
8. `c += 1`
9. `row_list = ['media_id', 'op', 'os', 'adsid', 'picid', 'area', 'pv', 'uv']`
10. `r = 1`
11.
12. `for pic_name in self.picid_value:`
13. `cl = 0`
14. `for data_name in row_list:`
15. `worksheet.write(r, cl, self.picid_value[pic_name][data_name])`
16. `cl += 1`
17. `r += 1`
18. `workbook.save(excel_name)`
使用argparse添加一些参数说明,使用的时候直接 -h就能看到各种参数名字与作用
1. `if __name__ == '__main__':`
2. `parser = argparse.ArgumentParser('log statistic')`
3. `parser.add_argument('-f', '--file', default=None, help='filename')`
4. `args = parser.parse_args()`
5. `log_value = an_log(args.file)`
6. `if log_value:`
7. `log_value.read_log()`
8. `file_name1 = 'example2.xls'`
9. `log_value.write_excel(file_name1)`
也可以使用各种python数据分析库来进行分析,添加分析参数只需要在in_value方法中添加各种相应的参数字段就可以。水平有限,代码还有很多需要改进的地方,如果各位有什么好的想法和建议也欢迎反馈。点击阅读原文可访问作者博客。
获取本文完整代码百度网盘下载地址:http://pan.baidu.com/s/1jIdlfCU,下载密码:请在公众号底部回复“**日志代码** ”四个字后获取。
Python中文社区
致力于成为
国内最好的Python社区
QQ群:152745094
Github :github.com/PyCN
简书、知乎专栏:Python中文社区
专栏作者申请请发邮件至: