1. 程式人生 > 程式設計 >淺析python 定時拆分備份 nginx 日誌的方法

淺析python 定時拆分備份 nginx 日誌的方法

一、背景:

nginx 的log 不會自動按天備份,而且記錄時間格式不統一,此程式專門解決這兩個問題;

二、windows 部署方式

1.在 nginx 目錄,建立一個 nginx_logs_backup.bat 檔案;檔案內容如下

python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error

2.在定時任務中加一個定時任務,呼叫這個 bat 檔案;

2.1 開始-程式-管理工具-任務計劃程式;

2.2 新建基本任務;

2.3 注意的一點是,在"編輯操作"視窗,在"起始於(可選)"這一欄需要填入 bat 所在目錄,否則 bat 不會執行;

三、執行邏輯

1.將指定字首的 log 在同目錄建立一個臨時檔案(對原始檔重新命名),如:access_200426.log;
2.使用 nginx -s 命令,從容重啟 nginx,重新建立 log;
3.讀 access_200426.log 檔案,將記是 2020-04-26 產生的日誌,轉存至 ./bac/access_200426.log 檔案中;
4.刪除臨時檔案 access_200426.log ;
注:同一天可多次執行,轉存的 log 將增量新增;

四、呼叫方式

python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error

引數:
nginxConf=nginx 配置檔案
nginxDir=nginx 目錄
logPrefixs=log檔案字首(多個逗號分隔)

五、nginx_logs_splter.py 原始碼

#!/usr/bin/env python3
# coding=utf-8
import os
import sys
import argparse
import codecs
import time,datetime
import re
 
'''
拆分 nginx access log
日誌不會自動按天建立,需要輔助任務把日誌按天拆分備份,統一日誌時間格式;
作者:草青工作室
'''
 
_version='200426.1'
_isDebug = True
_isDebug = False
 
def logSpliter(nginxDir,prefix):
 #今日
 today = datetime.datetime.now();
 yymmdd_today = today.strftime('%y%m%d')
 #昨日
 yestoday = datetime.date.today()-datetime.timedelta(days=1)
 yymmdd_yestoday = yestoday.strftime('%y%m%d')
 
 # logFileFullName = os.path.join(nginxDir,"logs","%s.log"%prefix)
 tmpFileFullName = os.path.join(nginxDir,"%s_%s.log"%(prefix,yymmdd_yestoday))
 bacFileFullName = os.path.join(nginxDir,"bac","%s-%s.log"%(prefix,yymmdd_yestoday))
 
 print('%s\ntmpFileFullName=%s\nbacFileFullName=%s\n\n'%(
  '-'*60,tmpFileFullName,bacFileFullName))
 
 start = datetime.datetime.now()
 totalCount = 0
 with codecs.open(tmpFileFullName,'r','utf-8') as f:
  for line in f.readlines():
   totalCount += 1
 print('總記錄數\t%s\tfileName=%s' % (totalCount,tmpFileFullName))
 # 針對 access log 的時間格式
 dtAccess = re.compile('\d{1,2}/[a-zA-Z]+/\d{4}:\d{1,2}:\d{1,2}')
 # 針對 error log 的時間格式
 dtError = re.compile('\d{4}/\d{1,2}/\d{1,2} \d{1,2}')
 # 轉換 access log 日期格式("24/Apr/2020:23:26:29 +0800" to 2020-04-24 23:26:29)
 dtReplace = re.compile('^".+?"|^\[.+?\]')
 # 增量寫備份檔案
 outputFile = open(bacFileFullName,'a+',encoding='utf-8')
 # 寫備註
 outputFile.writelines("#備份時間\t%s\n" % today.strftime('%Y-%m-%d %H:%M:%S'))
 outputFile.writelines("#版本號\t%s\n" % _version)
 #轉存 tmp 檔案
 with open(tmpFileFullName,encoding='utf-8') as f:
  rows = 0
  # 按行統計
  while True:
   rows += 1
   if rows % 10000 == 0:
    print('已分析\t%s/%s\t耗時\t%ss' % (rows,totalCount,(datetime.datetime.now() - start).seconds))
   # ------
   if _isDebug and rows>=35000:
    print('_isDebug = ',_isDebug)
    break
   # ------
   line = f.readline()
   if not line:  #等價於if line == "":
    break
   if line.startswith('#'):
    print("跳過註釋內容=>",line)
    continue
   #時間格式適配
   dt = None
   if 'access' in prefix:
    #獲取時間 "24/Apr/2020:14:43:38 +0800"
    arr = dtAccess.findall(line)
    if len(arr) == 0:
     continue
    dt = datetime.datetime.strptime(arr[0],'%d/%b/%Y:%H:%M:%S')
    #轉換時間格式
    line = dtReplace.sub('"%s"'%dt.strftime('%Y-%m-%d %H:%M:%S'),line)
   elif 'error' in prefix:
    #獲取時間 2020/04/24 23:37:46
    arr = dtError.findall(line)
    if len(arr) == 0:
     continue
    dt = datetime.datetime.strptime(arr[0],'%Y/%m/%d %H:%M:%S')
   if not dt:
    print('日期轉換失敗 dt is none')
    continue
   yymmdd_log = dt.strftime('%y%m%d')
   #小於昨天繼續
   if yymmdd_log<yymmdd_yestoday:
    #print('跳過,小於 %s'%yymmdd_yestoday)
    continue
   #大於昨天退出
   if yymmdd_log>yymmdd_yestoday:
    print('退出,大於 %s'%yymmdd_yestoday)
    break
   #print(line)
   outputFile.writelines("%s"%line)
 
 #關閉輸出檔案流
 if outputFile:
  outputFile.close()
 #分離後刪除 tmp 檔案
 if os.path.exists(bacFileFullName):
  os.remove(tmpFileFullName)
  print('刪除臨時檔案,%s\t%s'%(tmpFileFullName,not os.path.exists(tmpFileFullName)))
 print('\n\n%s\n拆分完成,耗時 %s 秒 \nlog=%s' % ('*' * 30,(datetime.datetime.now() - start).seconds,bacFileFullName))
 pass
'''
>>> f = open('test.txt','w') # 若是'wb'就表示寫二進位制檔案
>>> f.write('Hello,world!')
>>> f.close()
python檔案物件提供了兩個“寫”方法: write() 和 writelines()。
write()方法和read()、readline()方法對應,是將字串寫入到檔案中。
writelines()方法和readlines()方法對應,也是針對列表的操作。它接收一個字串列表作為引數,將他們寫入到檔案中,換行符不會自動的加入,因此,需要顯式的加入換行符。
關於open()的mode引數:
'r':讀
'w':寫
'a':追加
'r+' == r+w(可讀可寫,檔案若不存在就報錯(IOError))
'w+' == w+r(可讀可寫,檔案若不存在就建立)
'a+' ==a+r(可追加可寫,檔案若不存在就建立)
對應的,如果是二進位制檔案,就都加一個b就好啦:
'rb'  'wb'  'ab'  'rb+'  'wb+'  'ab+'
'''
 
def test():
 # "24/Apr/2020:14:43:38 +0800"
 dt =time.time()
 print(time.strftime('%Y-%m-%d %H:%M:%S [%Z]',time.localtime(dt)))
 print(time.strftime('%y-%m-%d %I:%M:%S [%Z]',time.localtime(dt)))
 print(time.strftime('%d/%b/%Y %H:%M:%S [%Z]',time.localtime(dt)))
 print('-'*30)
 str = '24/Apr/2020:14:43:38'
 dt = datetime.datetime.strptime(str,'%d/%b/%Y:%H:%M:%S')
 print("%s[%s] => %s[%s]" % (str,type(str),dt,type(dt)))
 str = dt.strftime('%Y-%m-%d %H:%M:%S')
 print("%s [%s]" % (str,type(str)))
 pass
 
'''
python中時間日期格式化符號:
 %y 兩位數的年份表示(00-99)
 %Y 四位數的年份表示(000-9999)
 %m 月份(01-12)
 %d 月內中的一天(0-31)
 %H 24小時制小時數(0-23)
 %I 12小時制小時數(01-12) 
 %M 分鐘數(00=59)
 %S 秒(00-59) 
 %a 本地簡化星期名稱
 %A 本地完整星期名稱
 %b 本地簡化的月份名稱
 %B 本地完整的月份名稱
 %c 本地相應的日期表示和時間表示
 %j 年內的一天(001-366)
 %p 本地A.M.或P.M.的等價符
 %U 一年中的星期數(00-53)星期天為星期的開始
 %w 星期(0-6),星期天為星期的開始
 %W 一年中的星期數(00-53)星期一為星期的開始
 %x 本地相應的日期表示
 %X 本地相應的時間表示
 %Z 當前時區的名稱 
'''
def createTempFile(nginxConf,nginxDir,prefixArr):
 yestoday = datetime.date.today()-datetime.timedelta(days=1)
 yymmdd = yestoday.strftime('%y%m%d')
 for prefix in prefixArr:
  logFileFullName = os.path.join(nginxDir,"%s.log"%prefix)
  tmpFileullName = os.path.join(nginxDir,yymmdd))
  if not os.path.exists(logFileFullName):
   print('log 檔案不已存在:%s'%tmpFileullName)
   continue
  if os.path.exists(tmpFileullName):
   print('tmp 檔案已存在:%s'%tmpFileullName)
   continue
  #備份log
  os.rename(logFileFullName,tmpFileullName)
  if not os.path.exists(tmpFileullName):
   print('log 重新命名失敗:%s'%logFileFullName)
   continue
  print('%s rename %s'%(tmpFileullName,os.path.exists(tmpFileullName)))
 
 #重啟 nginx
 cmd = 'nginx -p %s -c %s -s reload'%(nginxDir,nginxConf)
 print('%s\n執行 nginx reload 命令\n\t%s\n\n'%('-'*60,cmd))
 #os.system() 將導致程序阻塞
 os.system(cmd)
 #等待重啟
 time.sleep(3)
 #判斷檔案是否存在
 print('rolad 命令已觸發,驗證log 是否新建')
 for prefix in prefixArr:
  log = os.path.join(nginxDir,'%s.log'%prefix)
  print('\t%s rename %s'%(log,os.path.exists(log)))
 print('\n')
 
def main(nginxConf,logPrefixs):
 if not nginxDir or not logPrefixs:
  print("引數為空:--nginxDir={} --logPrefixs={}".format(nginxDir,logPrefixs))
  return
 if not os.path.exists(nginxDir):
  print("檔案不存在:--nginxDir={} ".format(nginxDir))
  return
 conf = os.path.join(nginxDir,nginxConf)
 if not os.path.exists(conf):
  print("nginx config 不存在:--nginxConf={} ".format(conf))
  return
 prefixArr = logPrefixs.split(',')
 #備份+重新載入 nginx
 createTempFile(nginxConf,prefixArr)
 
 #分離當天的log
 for prefix in prefixArr:
  try:
   print("備份 %s 檔案"%prefix)
   logSpliter(nginxDir,prefix)
  except Exception as ex:
   print("備份 %s 異常"%prefix,ex)
 pass
 
 
if __name__ == '__main__':
 parser = argparse.ArgumentParser(description='manual to this script')
 parser.add_argument('--nginxConf',type=str,default = None)
 parser.add_argument('--nginxDir',default = None)
 parser.add_argument('--logPrefixs',default= None)
 args = parser.parse_args()
 #test()
 ''' 
 功能:
  備份執行時間-1天(昨天)的 nginx log,需要指定 log 的字首,多個檔名逗號分隔;
 執行邏輯:
  1.將指定字首的 log 在同目錄建立一個臨時檔案(對原始檔重新命名),如:access_200426.log;
  2.使用 nginx -s 命令,從容重啟 nginx,重新建立 log;
  3.讀 access_200426.log 檔案,將記是 2020-04-26 產生的日誌,轉存至 ./bac/access_200426.log 檔案中;
  4.刪除臨時檔案 access_200426.log ;
  注:同一天可多次執行,轉存的 log 將增量新增;
 呼叫方式:
  python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error
  引數:
   nginxConf=nginx 配置檔案
   nginxDir=nginx 目錄
   logPrefixs=log檔案字首(多個逗號分隔)
 windows 部署:
  1.在 nginx 目錄,建立一個 nginx_logs_backup.bat 檔案;檔案內容如下
   python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error
  2.在定時任務中加一個定時任務,呼叫這個 bat 檔案;
   2.1 開始-程式-管理工具-任務計劃程式;
   2.2 新建基本任務;
   2.3 注意的一點是,在"編輯操作"視窗,在"起始於(可選)"這一欄需要填入 bat 所在目錄,否則 bat 不會執行;
 '''
 sys.exit(main(args.nginxConf,args.nginxDir,args.logPrefixs))

到此這篇關於淺析python 定時拆分備份 nginx 日誌的方法的文章就介紹到這了,更多相關python nginx 日誌內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!