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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python统计web应用的每个连接使用情况相关的知识,希望对你有一定的参考价值。

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

需求:

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

  • 不能影响生产环境;

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

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


思路:我想这可以通过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 systemmongo
ActionLog = ‘../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.0
import systemmongo,os
# 写一个方法,判断文件是否存在.返回布尔值
def judgment_file(FileName):
    if os.path.exists( FileName ):
        return True
    else:
        return False
# 写一个方法,把字符串切割成列表,return list
def 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的日志切割

[[email protected] ~]# cat /etc/nginx/sbin/cut_log_hour.sh 
#!/bin/bash
#nginx 日志路径
log_dir="/Disk/log/nginx"
#当前时间 2017/09/28/15
date_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

以上是关于Python统计web应用的每个连接使用情况的主要内容,如果未能解决你的问题,请参考以下文章

使用pygal统计投掷N次骰子之后点数的分布情况

多客户端Web应用程序设计

Web开发Python实现Web服务器(Flask测试统计图表)

如何在 python Web 服务器中保留数据库连接

HTTP长连接和短连接及应用情景

在不读取文件的情况下使用 parquet 文件统计信息