准备给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. (栈)栈 给定push序列,判断给定序列是否是pop序列

    题目: 输入两个整数序列.其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序.为了简单起见,我们假设push序列的任意两个整数都是不相等的. 比如输入的push序列是1.2. ...

  2. SQL语句执行顺寻

    SQL语句执行的时候是有一定顺序的.理解这个顺序对SQL的使用和学习有很大的帮助. 1.from 先选择一个表,或者说源头,构成一个结果集. 2.where 然后用where对结果集进行筛选.筛选出需 ...

  3. javascript Date 函数的坑

    Javascrip中对日期的解析.格式化简直是混乱不堪,各种的坑,攻城狮们多小心.   1. 不要用 Date("yyyy-mm-dd") 构造函数解析字符串. IE.firefo ...

  4. 关于Protobuf在游戏开发中的运用

    最近在研究protobuf在项目中的使用,由于我们项目服务端采用的是C++,客户端是cocos2dx-cpp,客户端与服务端的消息传输是直接对象的二进制流.如果客户端一直用C++来写,问题到不大,但是 ...

  5. nginx配置:支持phpfastcgi,nginx和php-cgi通信,部分nginx常量解释

    支持phpfastcgi的配置如下: server { listen       8000; server_name  localhost; root F:/home/projects/test; i ...

  6. 正则PerlRegEx实现的批量替换指定文件中的标签

    示例: 一个朋友需要而编写的标签升级更新. 速度超快,1w个文件大概4,5秒,本想加个多线程显示进度,后来想想算了 主要代码: reg.RegEx := '<' + Edit_regular1. ...

  7. delphi图形图像开发相关

    ①delphi的图形处理(doc) http://wenku.baidu.com/view/519df09951e79b89680226ee.html ②delphi的图形图像处理(ppt) http ...

  8. XE5 ANDROID通过webservice访问操作MSSQL数据库

    上接XE5 ANDROID平台 调用 webservice 一.服务端 在ro里添加函数(在impl上添加阿东connection,adoquery,dataprovider) function TN ...

  9. WPF自定义控件(三)——Window

    一样!先来看看效果吧: 怎么样?效果很好吧,而且不只是样式哟!所有系统窗体有的交互操作都可以实现! 但可惜...有很多和系统API有关的东西本人了解得并不多,所以这个窗体是基于他人的成果上产生的.关于 ...

  10. WIN7右下角的声音图标不见了

    有时候电脑启动了,但是声音图标却不见了,造成调试声音相当的麻烦,那么怎么来处理呢? 一:ctrl+shit+Esc键打开任务管理器 二:找到exeplore.exe,结束进程. 三:重新建立进程 上述 ...