歡迎您光臨本站 註冊首頁

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

←手機掃碼閱讀     火星人 @ 2020-04-28 , reply:0

一、背景:

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

二、windows 部署方式

1.在 nginx 目錄,創建一個 nginx_logs_backup.bat 文件;文件內容如下

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,"logs","%s_%s.log"%(prefix,yymmdd_yestoday)) bacFileFullName = os.path.join(nginxDir,"logs","bac","%s-%s.log"%(prefix,yymmdd_yestoday)) print('%s

tmpFileFullName=%s

bacFileFullName=%s



'%( '-'*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('總記錄數 %s fileName=%s' % (totalCount,tmpFileFullName)) # 針對 access log 的時間格式 dtAccess = re.compile('d{1,2}/[a-zA-Z]+/d{4}:d{1,2}:d{1,2}:d{1,2}') # 針對 error log 的時間格式 dtError = re.compile('d{4}/d{1,2}/d{1,2} 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("#備份時間 %s

" % today.strftime('%Y-%m-%d %H:%M:%S')) outputFile.writelines("#版本號 %s

" % _version) #轉存 tmp 文件 with open(tmpFileFullName, 'r', encoding='utf-8') as f: rows = 0 # 按行統計 while True: rows += 1 if rows % 10000 == 0: print('已分析 %s/%s 耗時 %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) break #print(line) outputFile.writelines("%s"%line) #關閉輸出文件流 if outputFile: outputFile.close() #分離後刪除 tmp 文件 if os.path.exists(bacFileFullName): os.remove(tmpFileFullName) print('刪除臨時文件,%s %s'%(tmpFileFullName ,not os.path.exists(tmpFileFullName))) print('



%s

拆分完成,耗時 %s 秒

log=%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,"logs","%s.log"%prefix) tmpFileullName = os.path.join(nginxDir,"logs","%s_%s.log"%(prefix,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

執行 nginx reload 命令

%s



'%('-'*60,cmd)) #os.system() 將導致進程阻塞 os.system(cmd) #等待重啟 time.sleep(3) #判斷文件是否存在 print('rolad 命令已觸發,驗證log 是否新建') for prefix in prefixArr: log = os.path.join(nginxDir,"logs",'%s.log'%prefix) print(' %s rename %s'%(log,os.path.exists(log))) print('

') def main(nginxConf,nginxDir, 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,nginxDir,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', type=str, default = None) parser.add_argument('--logPrefixs', type=str, 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 日誌的方法已經有394次圍觀

http://coctec.com/docs/nginx/show-post-231898.html