使用Python解析nginx日志文件

本文使用Python2.7解析nginx日志文件,并把nginx的时间转化为时间戳(1970纪元后经过的浮点秒数),并存放到特定文件中。

日志规则描述

Nginx的http日志格式:

 log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" ';

示例如下:

199.120.110.21 - - [01/Jul/1995:00:00:09 -0400] "GET /shuttle/missions/sts-73/mission-sts-73.html HTTP/1.0" 200 4085

解决思路

获取所有日志文件

这里使用Python的glob模块来获取所有日志文件。日志文件每天0时进行备份,命名为nginx.log.YYMMDD。

import glob

def readfile(path):
    return glob.glob(path + '*')

获取日志中所有行

模块linecache允许从任何文件里得到任何的行,并且使用缓存进行优化,常见的情况是从单个文件读取多行。

import linecache

def readline(path):
    return linecache.getlines(path)

解析每一条日志

使用python的re模块解析每一条日志。

正则表达式

ip_regex = r"?P[\d.]*"
date_regex = r"?P\d+"
month_regex = r"?P\w+"
year_regex = r"?P\d+"
day_time_regex = r"?P\S+"
method_regex = r"?P\S+"
request_regex = r"?P\S+"
status_regex = r"?P\d+"
body_bytes_regex = r"?P\S+"

其中body_bytes捕获非空字符串,而不是数字,因为日志里可能存在该字段值为“-”,即没有请求体。

解析日志

def parse_log(log_line):
    """
    解析日志,日志格式: 199.120.110.21 - - [01/Jul/1995:00:00:09 -0400] "GET /shuttle/missions/sts-73/mission-sts-73.html HTTP/1.0" 200 4085
    """
    log_fmt = r"(%s)\ - \ -\ \[(%s)/(%s)/(%s)\:(%s)\ [\S]+\]\ \"(%s)?[\s]?(%s)?.*?\"\ (%s)\ (%s)\s"
    p = re.compile(log_fmt %(ip_regex, date_regex, month_regex, year_regex, day_time_regex, method_regex, request_regex, status_regex, body_bytes_regex), 
    re.VERBOSE)
    return re.search(p, log_line)

时间提取

date、method、request等参数可以采用以下方式进行提取。

matches = parse_log(line)
date = matches.group("date")
month = matches.group("month")
year = matches.group("year")
day_time = matches.group("day_time")

时间转换

使用python的time模块把时间转为时间戳。

def parse_time(date, month, year, log_time):
    """转化为long型时间"""
    time_str = '%s%s%s %s' %(year, month, date, log_time)
    return time.mktime(time.strptime(time_str, '%Y%b%d %H:%M:%S'))

完整代码

#!/usr/bin/python2
# -*- coding: UTF-8 -*- 
import re
import time
import glob
import linecache


ip_regex = r"?P[\d.]*"
date_regex = r"?P\d+"
month_regex = r"?P\w+"
year_regex = r"?P\d+"
day_time_regex = r"?P\S+"
method_regex = r"?P\S+"
request_regex = r"?P\S+"
status_regex = r"?P\d+"
body_bytes_regex = r"?P\d+"


def read_file(path):
    return glob.glob(path)

def read_line(path):
    """读取文件中每一行的内容"""
    return linecache.getlines(path)
     
def write_line(file, str):
    file.write(str + "\n")

def parse_log(log_line):
    """
    解析日志,日志格式: 199.120.110.21 - - [01/Jul/1995:00:00:09 -0400] "GET /shuttle/missions/sts-73/mission-sts-73.html HTTP/1.0" 200 4085
    """
    log_fmt = r"(%s)\ - \ -\ \[(%s)/(%s)/(%s)\:(%s)\ [\S]+\]\ \"(%s)?[\s]?(%s)?.*?\"\ (%s)\ (%s)\s"
    p = re.compile(log_fmt %(ip_regex, date_regex, month_regex, year_regex, day_time_regex, method_regex, request_regex, status_regex, body_bytes_regex), 
    re.VERBOSE)
    return re.search(p, log_line)

def parse_time(date, month, year, log_time):
    """转化为时间戳,整形,单位秒"""
    time_str = '%s%s%s %s' %(year, month, date, log_time)
    return int(time.mktime(time.strptime(time_str, '%Y%b%d %H:%M:%S')))

if __name__ == '__main__':
    time_file = open("time.log", "a")     # 直接打开一个文件用于写,文件指针放在文件的结尾,如果文件不存在则创建文件

    log_path = read_file("./nginx.log")[0]
    for line in read_line(log_path):
        matches = parse_log(line)
        if matches == None:
            print "match fail, line: %s" % line
            continue
        date = matches.group("date")
        month = matches.group("month")
        year = matches.group("year")
        day_time = matches.group("day_time")
        ctime = parse_time(date, month, year, day_time)
        print ctime
        write_line(time_file, str(ctime))

输出结果

产生文件time.log,内容如下:

806909465
806909465
806909465
806909466
806909466
806909466

参考文献

  • 使用Python解析nginx日志文件
  • 详解python linecache模块读取文件的方法
  • 详解Python正则表达式之: (?P…) named group 带命名的组

本文作者: seawish
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!

你可能感兴趣的:(使用Python解析nginx日志文件)