1. 程式人生 > >Python統計web應用的每個連接使用情況

Python統計web應用的每個連接使用情況

日誌分析 nginx 功能

背景:前段時間接到一個需求,領導說他想要知道我們在生產環境中某系統的每個應用使用情況。

需求:

  • 統計每個按鈕的點擊量;

  • 不能影響生產環境;

  • 數據要不斷遞增,而不是看某個時間段的;

  • 數據要永久存放,不丟;


思路:我想這可以通過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應用的每個連接使用情況