使用Python分析nginx日志

大模型向量数据库智能内容

使用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&param=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&param=A000184&adsid=14&picid=141&time=1477842977818 HTTP/1.1 , 一个是参数: GET/index.php?m=newbar&a=operate&type=1&op=0&param=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,下载密码:请在公众号底部回复“**日志代码** ”四个字后获取。

picture.image

Python中文社区

www.python-cn.com

picture.image

picture.image

致力于成为

国内最好的Python社区

QQ群:152745094

Github :github.com/PyCN

简书、知乎专栏:Python中文社区

专栏作者申请请发邮件至:

sinoandywong@gmail.com

picture.image

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
基于火山引擎 EMR 构建企业级数据湖仓
火山引擎 EMR 是一款云原生开源大数据平台,提供主流的开源大数据引擎,加持了字节跳动内部的优化、海量数据处理的最佳实践。本次演讲将为大家介绍火山引擎 EMR 的架构及核心特性,如何基于开源架构构建企业级数据湖仓,同时向大家介绍火山 EMR 产品的未来规划。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论