准备给ZABBIX用的。

统计接口访问字次,平均响应时间,4XX,5XX次数

以后可以再改进。。

#!/usr/bin/env python
# coding: utf-8

###################################
# User:chengang                   #
# Email:aguncn@163.com    #
# Date:2016-02-25                 #
###################################

import time
import datetime
import sys
import os
import os.path
import re
import json

class NginxLog(object):

    def __init__(self, log_file, interface_list, seek_file):
        self.log_file = log_file
        self.interface_list = interface_list
        self.seek_file = seek_file

    # 将输出编码成json格式
    def jsonFormat(self, python_data):
        json_data = json.dumps(python_data, indent=2)
        return json_data

    # 获取电脑主机名
    def hostname(self):
        sys = os.name
        if sys == 'nt':
            hostname = os.getenv('computername')
            return hostname
        elif sys == 'posix':
            host = os.popen('echo $HOSTNAME')
            try:
                hostname = host.read()
                return hostname
            finally:
                host.close()
        else:
            return 'Unkwon hostname'

    # 将读过的文件游标写入临时文件
    def writeSeek(self, seek):
        with open(self.seek_file,'w') as f:
            f.write(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))+"\n")
            f.write(str(seek)+"\n")

    # 读出新生成的日志条目
    def LogRead(self):
        # 如果第一次运行,或是删除临时文件,从头运行,否则,从上次读取之后运行
        # 0代表从头开始,1代表当前位置,2代表文件最末尾位置。
        if os.path.exists(self.seek_file):
            with open(self.seek_file) as f:
                seek_tmp = f.readlines()
            seek_old = int(seek_tmp[1].strip())
        else:
            seek_old = 0
        with open(self.log_file) as f:
            #记录当前最新文件游标
            f.seek(0,2)
            seek_now = f.tell()
            # 读取上次读完之后的日志条目
            if seek_now >= seek_old:
                f.seek(seek_old,0)
                chunk = f.read(seek_now-seek_old)
                # 也可以考虑用xreadlines来实现
                # for line in f.xreadlines():
                #    pass # do something
            # 如果文件游标倒退,说明日志文件已轮循,从头开始
            else:
                f.seek(0,0)
                chunk = f.read(seek_now)
        # 将这次的游标写入临时文件
        # self.writeSeek(seek_now)
        return chunk

    def LogStatistics(self):
        #分析NGINX日志的正则表达示,如果日志格式更改,则需要相应作更改
        #我拿到的日志样本和鹏龙的不一样,所以注释了一个字段
        #field 0
        field_remote_addr = r"?P<l_remote_addr>.*"
        #field 1
        field_remote_user = r"?P<l_remote_user>-"
        #field 2
        field_time_local = r"?P<l_time_local>\[.*\]"
        #field 3
        field_request = r"?P<l_request>\"[^\"]*\""
        #field 4
        field_status = r"?P<l_status>\"[^\"]*\""
        #field 5
        field_body_bytes_sent = r"?P<l_body_bytes_sent>\d+"
        #field 6
        field_http_refere = r"?P<l_http_refere>\"[^\"]*\""
        #field 7
        field_http_user_agent = r"?P<l_http_user_agent>\"[^\"]*\""
        #field 8
        #field_http_x_fowarded_for = r"?P<l_http_x_fowarded_for>\"[^\"]*\""
        #field 8
        field_all_cookie = r"?P<l_all_cookie>\"[^\"]*\""
        #field 9
        field_gzip_ratio = r"?P<l_gzip_ratio>\"[^\"]*\""
        #field 10
        field_upstream_addr = r"?P<l_upstream_addr>.*"
        #field 11
        field_bytes_sent = r"?P<l_bytes_sent>\d+"
        #field 12
        field_request_length = r"?P<l_request_length>\d+"
        #field 13
        field_request_time = r"?P<l_request_time>.*"

        #以下为样例,方便调试
        '''
        10.25.162.22 - - [24/Feb/2016:14:09:25 +0800] "GET / HTTP/1.0" "200" 612 "-" 

        "-" "-" "-" - 846 54 0.000
        10.25.162.22 - - [24/Feb/2016:14:09:35 +0800] "GET 

        /dsf/getRealTimeDatas?codes=&codeTypes=&_v=14562941753244588 

        HTTP/1.0" "200" 37 

        "http://asfdte/quote/dsftml" "Mozilla/5.0 

        (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like 

        Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4" "-" "-" 10.25.174.34:30077 

        181 862 0.002
        '''
        # 正则匹配字段
        nginxlog_pattern = re.compile(r"(%s)\s-\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)\s(%s)" \
                                      %(field_remote_addr,field_remote_user,field_time_local,field_request,field_status, \
                                        field_body_bytes_sent,field_http_refere,field_http_user_agent, \
                                        field_all_cookie,field_gzip_ratio,field_upstream_addr,field_bytes_sent,field_request_length, \
                                        field_request_time),re.VERBOSE)
        #输出结果
        result_list = []
        # 未启用字段,作占位用
        time_ns =  datetime.datetime.now().microsecond
        #转换成符合要求的时间秒格式
        time_stamp = int(str(time.time())[0:10])
        host_name = self.hostname()
        # 多少个URL,就要循环读取多少次,算法粗糙,后面再想办法吧,因为如果只循环一次文件读取,则在里面要循环列表,还难理顺思路
        for interface_item in self.interface_list:
            # json格式样例 {"ns":470464001,"clock":1450368176,"value":"1","key":"macs.func.exeCount_0ms_50ms[104_202]","host":"SQSZ-L4"},
            # 构造符合要求的字典
            interface_item_dict_count = {}
            interface_item_dict_avg_request_time = {}
            interface_item_dict_2xx = {}
            interface_item_dict_4xx = {}
            interface_item_dict_5xx = {}
            interface_item_dict_count['ns']=interface_item_dict_avg_request_time['ns']=interface_item_dict_2xx['ns']=interface_item_dict_4xx['ns']=interface_item_dict_5xx['ns']=time_ns
            interface_item_dict_count['clock']=interface_item_dict_avg_request_time['clock']=interface_item_dict_2xx['clock']=interface_item_dict_4xx['clock']=interface_item_dict_5xx['clock']=time_stamp
            interface_item_dict_count['host']=interface_item_dict_avg_request_time['host']=interface_item_dict_2xx['host']=interface_item_dict_4xx['host']=interface_item_dict_5xx['host']=host_name
            interface_item_dict_count['key'] = interface_item + '_count'
            interface_item_dict_count['value'] = 0
            interface_item_dict_avg_request_time['key'] = interface_item + '_avg_request_time'
            interface_item_dict_avg_request_time['value'] = 0
            interface_item_dict_2xx['key'] = interface_item + '_2xx'
            interface_item_dict_2xx['value'] = 0
            interface_item_dict_4xx['key'] = interface_item + '_4xx'
            interface_item_dict_4xx['value'] = 0
            interface_item_dict_5xx['key'] = interface_item + '_5xx'
            interface_item_dict_5xx['value'] = 0
            hit_url_count = 0
            for line in self.LogRead().split('\n'):
                line_matchs = nginxlog_pattern.match(line)
                if line_matchs!=None:
                    #匹配字段
                    allGroups = line_matchs.groups()
                    remote_addr = allGroups[0]
                    #切割出真正的URL
                    request_url = allGroups[3].split()[1].split('?')[0].split('/')[-1]
                    status_code = allGroups[4]
                    request_time = allGroups[13]
                    # 匹配URL之后进行数据结构操作
                    if interface_item == request_url:
                        hit_url_count += 1
                        interface_item_dict_count['value'] += 1
                        interface_item_dict_avg_request_time['value'] += float(request_time)
                        '):
                            interface_item_dict_2xx['value'] += 1
                        '):
                            interface_item_dict_4xx['value'] += 1
                        '):
                            interface_item_dict_5xx['value'] += 1
            # 求平均请求反应时间
            if interface_item_dict_avg_request_time['value'] != 0:
                interface_item_dict_avg_request_time['value'] = interface_item_dict_avg_request_time['value'] / hit_url_count

            #入总列表
            result_list.append(interface_item_dict_count)
            result_list.append(interface_item_dict_avg_request_time)
            result_list.append(interface_item_dict_2xx)
            result_list.append(interface_item_dict_4xx)
            result_list.append(interface_item_dict_5xx)
        return self.jsonFormat(result_list)

    def resultOutput(self):
        pass

def main():
    #需要收集的url
    interface_list = ['getIndexData', \
                      'getRealTimeDatas',
                      'hehel',]
    #日志定位
    log_file  = 'd:\\demo\\sample.log'
    # 临时文件游标文件
    seek_file = 'd:\\demo\\log_check_seek.tmp'

    nginx_log = NginxLog(log_file, interface_list, seek_file)
    return_json_data = nginx_log.LogStatistics()
    print return_json_data

if __name__ == "__main__":
    main()
    

一天,python搞个分析NGINX日志的脚本的更多相关文章

  1. 利用python分析nginx日志

    最近在学习python,写了个脚本分析nginx日志,练练手.写得比较粗糙,但基本功能可以实现. 脚本功能:查找出当天访问次数前十位的IP,并获取该IP来源,并将分析结果发送邮件到指定邮箱. 实现前两 ...

  2. 使用Docker快速部署ELK分析Nginx日志实践(二)

    Kibana汉化使用中文界面实践 一.背景 笔者在上一篇文章使用Docker快速部署ELK分析Nginx日志实践当中有提到如何快速搭建ELK分析Nginx日志,但是这只是第一步,后面还有很多仪表盘需要 ...

  3. 烂泥:利用awstats分析nginx日志

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 昨天把nginx的日志进行了切割,关于如何切割nginx日志,可以查看<烂泥:切割 ...

  4. elk实战分析nginx日志文档

    elk实战分析nginx日志文档 架构: kibana <--- es-cluster <--- logstash <--- filebeat 环境准备:192.168.3.1 no ...

  5. elk平台分析nginx日志的基本搭建

    一.elk套件介绍 ELK 由 ElasticSearch . Logstash 和 Kiabana 三个开源工具组成.官方网站: https://www.elastic.co/products El ...

  6. Awstats分析Nginx日志

    1.nginx日志格式设定 log_format access '$remote_addr - $remote_user [$time_local] "$request" ' '$ ...

  7. hive分析nginx日志之UDF清洗数据

    hive分析nginx日志一:http://www.cnblogs.com/wcwen1990/p/7066230.html hive分析nginx日志二:http://www.cnblogs.com ...

  8. awstat分析nginx日志

    awstat分析nginx日志 http://lxw66.blog.51cto.com/5547576/1323712 server{ listen ; server_name localhost; ...

  9. shell脚本分析nginx日志

    shell脚本分析nginx日志: name=`awk -F ',' '{print $13":"$32}' $file | awk -F ':' '{print $4}'`ech ...

随机推荐

  1. (三)Qt语言国际化

    Vs 2010+ Qt5 实现语言国际化 创建一个工程,cpp代码如下: 1.创建工程 #include "languageinternationalized.h" #includ ...

  2. Data truncated for column 错误

    今天插入mysql数据数据时,报错Data truncated for column.研究了一下原理是我数据的长途超出了该字段的最大长度,所以解决办法很简单,就是修改数据库中字段属性,使其长度增加即可 ...

  3. 《用户和组的管理》Redhat6.3

    linux下有三类用户:  1.超级用户 :root 具有操作系通的一切权限 uid 0 2.普通用户:普通用户具有操作系统有限的权限 uid 500-6000 3.伪用户 :是为了方便系统管理,满足 ...

  4. FTP 数字代码的意义

    110 重新启动标记应答. 120 服务在多久时间内ready. 125 数据链路埠开启,准备传送. 150 文件状态正常,开启数据连接端口. 200 命令执行成功. 202 命令执行失败. 211 ...

  5. apache http server 局域网无法访问

    apache 本地配置完成测试成功,但局域网内无法访问. 1.主要是本本地的防火墙设置有关,修改防火墙设置就成了 控制面板->系统和安全->Windows 防火墙->允许程序通过Wi ...

  6. Sending Email from mailx Command in Linux Using Gmail’s SMTP

    The mailx or mail command in Linux is still providing service for guys like me, especially when we n ...

  7. 伴随ListView、RecyclerView、ScrollView滚动滑入滑出小图标--第三方开源--FloatingActionButton

    FloatingActionButton在github上的项目主页是:https://github.com/makovkastar/FloatingActionButton 它的依赖包NineOldA ...

  8. 编辑器未包含main类型解决方法

    将文件移到 src 这个 Java Source Folder 下面去,现在在外面的 java 文件不会被当成一个需要编译的类,eclipse 不会编译 Java Source Folder 外面的任 ...

  9. Daily Scrum 11.11

    摘要:本次会议继续讨论程序的问题以及单元测试和集成测试,本次测试为1.02版本.本次的Task列表如下: Task列表 出席人员 Today's Task Tomorrow's Task 刘昊岩  t ...

  10. .Xresources 配置文件

    安装rxvt-unicode-256color,如果不是这个版本的话VIM配色会显示不正常. ~/.Xresources配置文件如下 !urxvt color scheme: URxvt*backgr ...