Python统计web应用的每个连接使用情况

时间:2022-05-20 22:31:38

背景:前段时间接到一个需求,领导说他想要知道我们在生产环境中某系统的每个应用使用情况。

需求:

  • 统计每个按钮的点击量;

  • 不能影响生产环境;

  • 数据要不断递增,而不是看某个时间段的;

  • 数据要永久存放,不丢;


思路:我想这可以通过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模版的格式

Python统计web应用的每个连接使用情况

看一下插入后的集合样子

Python统计web应用的每个连接使用情况

分析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