Python项目的一个需求是解析nginx的日志文件,这里给出详细的过程分析。
日志规则描述
首先需要明确自己的Nginx日志格式,这里是默认的Nginx日志格式:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
其中一条真实记录样例如下:
代码如下:
172.22.8.207 - - [16/Dec/2014:17:57:35 +0800] "GET /report?DOmjjuS6keWJp+WculSQAgdUkAIPODExMzAwMDJDN0FC HTTP/1.1" 200 0 "-" "XXXXXXX/1.0.16; iPhone/iOS 8.1.2; ; 8DA77E2F91D0"
其中,客户端型号信息用XXXXXXX代替。
Nginx 日志文件已经按照项目中的业务规则进行了处理。命名规则如下:
ID-ID-YYMMDD-hhmmss
并且所有的日志文件存放在统一路径下。
解决思路
获取所有日志文件path
这里使用Python的glob模块来获取日志文件path
import glob
def readfile(path):
return glob.glob(path + '*-*-*-*')
获取日志文件中每一行的内容
使用Python的linecache模块来获取文件行的内容
import linecache
def readline(path):
return linecache.getlines(path)
注意:linecache模块使用了缓存,所以存在以下问题:
使用linecache模块读取文件内容后,如果文件发生变化,需要使用linecache.updatecache(filename)更新缓存,获取最新的变化。
linecache模块使用了缓存,所以会消耗内存,消耗量和要解析的文件有关。使用后最好执行linecache.clearcache()清除缓存。
当然,作为优化,这里可以使用生成器进行优化。现在按下按钮。
处理日志条目
一条日志信息是一个特定格式的字符串,所以要用正则表达式来解析,这里用到了Python的re模块。
下面,一条一条建立规则:
规则
ip = r"?P<ip>[\d.]*"
date = r"?P<date>\d+"
month = r"?P<month>\w+"
year = r"?P<year>\d+"
log_time = r"?P<time>\S+"
method = r"?P<method>\S+"
request = r"?P<request>\S+"
status = r"?P<status>\d+"
bodyBytesSent = r"?P<bodybytessent>\d+"
refer = r"""?P<refer>
[^\"]*
"""
userAgent=r"""?P<useragent>
.*
"""
</useragent></refer></bodybytessent></status></request></method></time></year></month></date></ip>
解析
代码如下:
p = re.compile(r"(%s)\ -\ -\ \[(%s)/(%s)/(%s)\:(%s)\ [\S]+\]\ \"(%s)?[\s]?(%s)?.*?\"\ (%s)\ (%s)\
\"(%s)\"\ \"(%s).*?\""
%( ip, date, month, year, log_time, method, request, status, bodyBytesSent, refer, userAgent ),\
re.VERBOSE)
m = re.findall(p, logline)
这样就可以得到日志条目中各个元素的原始数据。
格式及内容转化
获取原始日志数据后,需要根据业务需求对原始数据的格式和内容进行转换。
这里需要处理的内容包括:时间,request,userAgent
时间格式转化
日志信息的原始数据中有Dec这样的信息,使用Python的time模块可以很方便的分析出来
import time
def parsetime(date, month, year, log_time):
time_str = '%s%s%s %s' %(year, month, date, log_time)
return time.strptime(time_str, '%Y%b%d %H:%M:%S')
解析request
在日志信息原始数据中得到的request的内容格式为:
/report?XXXXXX
这里只需要根据协议取出XXXXXX即可。
这里仍然采用Python的re模块
import re
def parserequest(rqst):
param = r"?P<param>.*"
p = re.compile(r"/report\?(%s)" %param, re.VERBOSE)
return re.findall(p, rqst)
接下来需要根据业务约定解析参数内容。这里需要先使用base64模块解码,再使用struct模块解构内容:
import struct
import base64
def parseparam(param):
decodeinfo = base64.b64decode(param)
s = struct.Struct('!x' + bytes(len(decodeinfo) - (1 + 4 + 4 + 12)) + 'xii12x')
return s.unpack(decodeinfo)
解析userAgent
在日志信息原始数据中userAgent数据的格式为:
XXX; XXX; XXX; XXX
根据业务要求,只需要取出最后一项即可。
这里采用re模块来解析。
import re
def parseuseragent(useragent):
agent = r"?P<agent>.*"
p = re.compile(r".*;.*;.*;(%s)" %agent, re.VERBOSE)
return re.findall(p, useragent)
至此,nginx日志文件解析基本完成。
剩下的工作就是根据业务需要,对获取到的基础信息进行处理。
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 如何在python中导入模块10/13
- ♥ 如何用python导出数据10/26
- ♥ python中Monkey测试有什么特点11/14
- ♥ 什么是 Python UUID 模块?01/01
- ♥ Python新手FAQ 7:循环加载模块12/05
- ♥ 如何在python中做3D图形10/22
内容反馈