背景:前段时间接到一个需求,领导说他想要知道我们在生产环境中某系统的每个应用使用情况。
需求:
统计每个按钮的点击量;
不能影响生产环境;
数据要不断递增,而不是看某个时间段的;
-
数据要永久存放,不丢;
思路:我想这可以通过nginx的日志来进行分析,每个action和后台的nginx接到请求肯定是一对一的,那么我们通过nginx的日志,那这个需求就解决了;
方案:
分析nginx的请求日志;
凌晨进行日志分析,且数据不妨到生产环境;
做定时任务;
存放到mongodb;
总结:在每天凌晨进行日志分析,把处理结果存放那个到线下mongodb数据库中
代码实现:
连接mongo代码↓
#coding=utf-8# auth: xinsir
# date: 2017/10/02
# version:3.0
from pymongo import MongoClient
import pickle
#建立MongoDB数据库连接
client = MongoClient('192.168.1.197',27017)
#连接所需数据库,test为数据库名
db=client.nginxlog
#连接所用集合,也就是我们通常所说的表,test为表名
collection=db.recording
# 写一个方法,用于反序列化数据
def Deserialization(name):
Data = pickle.load(name)
return Data
# 写一个方法,向mongo中存放数据
def InsterData(data):
collection.insert(data)
# 写一个方法,用来查询mongo中的数据
def SechMongo(link):
for u in collection.find( {'Link': link} ):
return True
else:
return False
# 写一个方法,用来更新mongo中的数据
def Update(wherelink):
data = collection.find_one({'Link':wherelink})
collection.update({'Link':wherelink},{'$set':{'cunt':int(data['cunt'])+1}})
插入模版代码↓
#coding=utf-8# auth: xinsir# date: 2017/10/02# version:3.0#_*_ coding:utf-8 _*_# 写一个方法,用来导入请求连接的模版,在进行日志分析之前,首先要对mongo集合中插入模版import systemmongoActionLog = '../nginxlog/result.txt'def Sech(File): SechDic = {} with open(File,'r',encoding='UTF-8') as ActionLogFile: for line in ActionLogFile.readlines(): a = line.split('\t') b = a[-1].split('\n') del a[-1] a.append(b[0]) SechDic[a[0]] = { 'ModuleName': a[0], 'ButtonName': a[1], 'Link': a[2], 'cunt': a[3], } systemmongo.InsterData(SechDic[a[0]]) ActionLogFile.close()if __name__ == '__main__': Sech(ActionLog)
看一下action模版的格式
看一下插入后的集合样子
分析nginx日志代码↓
#_*_ coding:utf-8 _*_# auth: xinsir# date: 2017/10/02# version:3.0import systemmongo,os# 写一个方法,判断文件是否存在.返回布尔值def judgment_file(FileName): if os.path.exists( FileName ): return True else: return False# 写一个方法,把字符串切割成列表,return listdef SplitStr(StrName, Format,): return StrName.split(Format)# 读取日志文件,获取文件中的所有包含action的记录,并写入到新的log文件中def read_file(file, new_file,): ReadPosition = 0 LastLine = 0 FileSize = 0 FileDic = {} # 打开两个文件,一个是日志文件,一个是临时文件,把日志文件进行更改后,以字典的格式序列化到日志文件中 with open(file, 'r') as log_file, open(new_file, 'w') as new_log_file: # 查看文件总长多少,写入临时文件 FileSizeNew = os.path.getsize(file) log_file.seek(ReadPosition) if FileSize < FileSizeNew: for (num, line) in enumerate(log_file): if '.action' in line.strip(): new_line = line.strip().split(sep='\" \"') ListFirstValue = SplitStr(new_line[0], '\"') ListMostValue = SplitStr(new_line[-1], '\"') del new_line[0] del new_line[-1] new_line.insert(0, ListFirstValue[1]) new_line.append(ListMostValue[0]) Method = str(new_line[3]).split()[0] request = str(new_line[3]).split()[1] HttpVersion = str(new_line[3]).split()[2] if '?' in request: Uri = request.split(sep='?')[0] Query_string = request.split(sep='?')[1] else: Uri = request.split( sep='?' )[0] Query_string = '' if '.action' in Uri: # if LogFileStatus : FileDic[num + 1 + LastLine] = { 'remote_addr': new_line[0], 'host': new_line[1], 'time_local': new_line[2], 'request': request, 'uri':Uri, 'query_string':Query_string, 'eethod': Method, 'HttpVersion': HttpVersion, 'body_bytes_sent': new_line[4], 'http_referer': new_line[5], 'http_user_agent': new_line[6], 'http_x_forwarded_for': new_line[7], 'server_addr': new_line[8], 'status': new_line[9], 'request_time': new_line[10], } else: print('静态请求不做记录!') continue IsNot = systemmongo.SechMongo( 'http://' + FileDic[num + 1 + LastLine]['host'] + FileDic[num + 1 + LastLine]['uri']) if IsNot: systemmongo.Update( 'http://' + FileDic[num + 1 + LastLine]['host'] + FileDic[num + 1 + LastLine]['uri']) print('更新记录成功:''http://' + FileDic[num + 1 + LastLine]['host'] + FileDic[num + 1 + LastLine]['uri']) else: print('action请求不存在!不做记录!') else: print('静态请求不做处理!') else: print('日志文件没有发生改变!') new_log_file.write(str(FileDic)) log_file.close() new_log_file.close()if __name__ == '__main__': LOGPATH_new = '../nginxlog/b.txt' for fpathe, dirs, fs in os.walk('E:\python工程\jlj-nginx-log-web\jlj-nginx-log-web\\nginxlog\log'): #循环目录下的所有日志文件 for f in fs: LOGPATH = os.path.join(fpathe, f) read_file(LOGPATH, LOGPATH_new)
配合linux的crontab任务,每天凌晨把生产环境的nginx日志scp到线下,这里特别要说明,因为我们的nginx访问量很大,大的时候在线连接数能达到3000+,可想而知一天的nginx日志也要有八九百兆,之前小编写的代码是一次性打开文件分别循环日志的每一行,但是这样会把机器的内存撑爆,所以现在是按照年月日的格式把nginx的日志进行了切割。
看一下nginx的日志切割
[root@localhost ~]# cat /etc/nginx/sbin/cut_log_hour.sh #!/bin/bash#nginx 日志路径log_dir="/Disk/log/nginx"#当前时间 2017/09/28/15date_dir=`date +%Y/%m/%d/%H`#创建时间目录/bin/mkdir -p ${log_dir}/${date_dir} > /dev/null 2>&1# 把当前日志移动到对应的目录下,并且重命名/bin/mv ${log_dir}/access.log ${log_dir}/${date_dir}/access.log# 重新生成一个日志文件kill -USR1 `cat /var/run/nginx.pid`
在看以下nginx的日志记录格式,每一个关键词都用双引号进行了分割,这样有助于我们后台进行日志分析
log_format main '"$remote_addr" "$host" "$time_local" "$request" "$body_bytes_sent" "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "$server_addr" "$status" "$request_time"';
小编也是初次写代码,如果有不对和思路凌乱的地方,还请大家指导,环境大家在评论区进行评论,也欢迎大家加我QQ同学习。
QQ:894747821
本文出自 “学习改变命运” 博客,请务必保留此出处http://xinsir.blog.51cto.com/5038915/1970198