淺析python 定時(shí)拆分備份 nginx 日志的方法
一、背景:
nginx 的log 不會(huì)自動(dòng)按天備份,而且記錄時(shí)間格式不統(tǒng)一,此程序?qū)iT(mén)解決這兩個(gè)問(wèn)題;
二、windows 部署方式
1.在 nginx 目錄,創(chuàng)建一個(gè) nginx_logs_backup.bat 文件;文件內(nèi)容如下
python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error
2.在定時(shí)任務(wù)中加一個(gè)定時(shí)任務(wù),調(diào)用這個(gè) bat 文件;
2.1 開(kāi)始-程序-管理工具-任務(wù)計(jì)劃程序;
2.2 新建基本任務(wù);
2.3 注意的一點(diǎn)是,在"編輯操作"窗口,在"起始于(可選)"這一欄需要填入 bat 所在目錄,否則 bat 不會(huì)執(zhí)行;
三、執(zhí)行邏輯
1.將指定前綴的 log 在同目錄創(chuàng)建一個(gè)臨時(shí)文件(對(duì)源文件重命名),如:access_200426.log;
2.使用 nginx -s 命令,從容重啟 nginx,重新創(chuàng)建 log;
3.讀 access_200426.log 文件,將記是 2020-04-26 產(chǎn)生的日志,轉(zhuǎn)存至 ./bac/access_200426.log 文件中;
4.刪除臨時(shí)文件 access_200426.log ;
注:同一天可多次執(zhí)行,轉(zhuǎn)存的 log 將增量添加;
四、調(diào)用方式
python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error
參數(shù):
nginxConf=nginx 配置文件
nginxDir=nginx 目錄
logPrefixs=log文件前綴(多個(gè)逗號(hào)分隔)
五、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
日志不會(huì)自動(dòng)按天創(chuàng)建,需要輔助任務(wù)把日志按天拆分備份,統(tǒng)一日志時(shí)間格式;
作者:草青工作室
'''
_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\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('總記錄數(shù)\t%s\tfileName=%s' % (totalCount,tmpFileFullName))
# 針對(duì) access log 的時(shí)間格式
dtAccess = re.compile('\d{1,2}/[a-zA-Z]+/\d{4}:\d{1,2}:\d{1,2}:\d{1,2}')
# 針對(duì) error log 的時(shí)間格式
dtError = re.compile('\d{4}/\d{1,2}/\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}')
# 轉(zhuǎn)換 access log 日期格式("24/Apr/2020:23:26:29 +0800" to 2020-04-24 23:26:29)
dtReplace = re.compile('^".+?"|^\[.+?\]')
# 增量寫(xiě)備份文件
outputFile = open(bacFileFullName, 'a+', encoding='utf-8')
# 寫(xiě)備注
outputFile.writelines("#備份時(shí)間\t%s\n" % today.strftime('%Y-%m-%d %H:%M:%S'))
outputFile.writelines("#版本號(hào)\t%s\n" % _version)
#轉(zhuǎn)存 tmp 文件
with open(tmpFileFullName, 'r', encoding='utf-8') as f:
rows = 0
# 按行統(tǒng)計(jì)
while True:
rows += 1
if rows % 10000 == 0:
print('已分析\t%s/%s\t耗時(shí)\t%ss' % (rows
,totalCount
,(datetime.datetime.now() - start).seconds))
# ------
if _isDebug and rows>=35000:
print('_isDebug = ',_isDebug)
break
# ------
line = f.readline()
if not line: #等價(jià)于if line == "":
break
if line.startswith('#'):
print("跳過(guò)注釋內(nèi)容=>",line)
continue
#時(shí)間格式適配
dt = None
if 'access' in prefix:
#獲取時(shí)間 "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')
#轉(zhuǎn)換時(shí)間格式
line = dtReplace.sub('"%s"'%dt.strftime('%Y-%m-%d %H:%M:%S'),line)
elif 'error' in prefix:
#獲取時(shí)間 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('日期轉(zhuǎn)換失敗 dt is none')
continue
yymmdd_log = dt.strftime('%y%m%d')
#小于昨天繼續(xù)
if yymmdd_log<yymmdd_yestoday:
#print('跳過(guò),小于 %s'%yymmdd_yestoday)
continue
#大于昨天退出
if yymmdd_log>yymmdd_yestoday:
print('退出,大于 %s'%yymmdd_yestoday)
break
#print(line)
outputFile.writelines("%s"%line)
#關(guān)閉輸出文件流
if outputFile:
outputFile.close()
#分離后刪除 tmp 文件
if os.path.exists(bacFileFullName):
os.remove(tmpFileFullName)
print('刪除臨時(shí)文件,%s\t%s'%(tmpFileFullName
,not os.path.exists(tmpFileFullName)))
print('\n\n%s\n拆分完成,耗時(shí) %s 秒 \nlog=%s' % ('*' * 30
, (datetime.datetime.now() - start).seconds
, bacFileFullName))
pass
'''
>>> f = open('test.txt', 'w') # 若是'wb'就表示寫(xiě)二進(jìn)制文件
>>> f.write('Hello, world!')
>>> f.close()
python文件對(duì)象提供了兩個(gè)“寫(xiě)”方法: write() 和 writelines()。
write()方法和read()、readline()方法對(duì)應(yīng),是將字符串寫(xiě)入到文件中。
writelines()方法和readlines()方法對(duì)應(yīng),也是針對(duì)列表的操作。它接收一個(gè)字符串列表作為參數(shù),將他們寫(xiě)入到文件中,換行符不會(huì)自動(dòng)的加入,因此,需要顯式的加入換行符。
關(guān)于open()的mode參數(shù):
'r':讀
'w':寫(xiě)
'a':追加
'r+' == r+w(可讀可寫(xiě),文件若不存在就報(bào)錯(cuò)(IOError))
'w+' == w+r(可讀可寫(xiě),文件若不存在就創(chuàng)建)
'a+' ==a+r(可追加可寫(xiě),文件若不存在就創(chuàng)建)
對(duì)應(yīng)的,如果是二進(jìn)制文件,就都加一個(gè)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中時(shí)間日期格式化符號(hào):
%y 兩位數(shù)的年份表示(00-99)
%Y 四位數(shù)的年份表示(000-9999)
%m 月份(01-12)
%d 月內(nèi)中的一天(0-31)
%H 24小時(shí)制小時(shí)數(shù)(0-23)
%I 12小時(shí)制小時(shí)數(shù)(01-12)
%M 分鐘數(shù)(00=59)
%S 秒(00-59)
%a 本地簡(jiǎn)化星期名稱(chēng)
%A 本地完整星期名稱(chēng)
%b 本地簡(jiǎn)化的月份名稱(chēng)
%B 本地完整的月份名稱(chēng)
%c 本地相應(yīng)的日期表示和時(shí)間表示
%j 年內(nèi)的一天(001-366)
%p 本地A.M.或P.M.的等價(jià)符
%U 一年中的星期數(shù)(00-53)星期天為星期的開(kāi)始
%w 星期(0-6),星期天為星期的開(kāi)始
%W 一年中的星期數(shù)(00-53)星期一為星期的開(kāi)始
%x 本地相應(yīng)的日期表示
%X 本地相應(yīng)的時(shí)間表示
%Z 當(dāng)前時(shí)區(qū)的名稱(chēng)
'''
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\n執(zhí)行 nginx reload 命令\n\t%s\n\n'%('-'*60,cmd))
#os.system() 將導(dǎo)致進(jìn)程阻塞
os.system(cmd)
#等待重啟
time.sleep(3)
#判斷文件是否存在
print('rolad 命令已觸發(fā),驗(yàn)證log 是否新建')
for prefix in prefixArr:
log = os.path.join(nginxDir,"logs",'%s.log'%prefix)
print('\t%s rename %s'%(log,os.path.exists(log)))
print('\n')
def main(nginxConf,nginxDir, logPrefixs):
if not nginxDir or not logPrefixs:
print("參數(shù)為空:--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)
#分離當(dāng)天的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()
'''
功能:
備份執(zhí)行時(shí)間-1天(昨天)的 nginx log,需要指定 log 的前綴,多個(gè)文件名逗號(hào)分隔;
運(yùn)行邏輯:
1.將指定前綴的 log 在同目錄創(chuàng)建一個(gè)臨時(shí)文件(對(duì)源文件重命名),如:access_200426.log;
2.使用 nginx -s 命令,從容重啟 nginx,重新創(chuàng)建 log;
3.讀 access_200426.log 文件,將記是 2020-04-26 產(chǎn)生的日志,轉(zhuǎn)存至 ./bac/access_200426.log 文件中;
4.刪除臨時(shí)文件 access_200426.log ;
注:同一天可多次執(zhí)行,轉(zhuǎn)存的 log 將增量添加;
調(diào)用方式:
python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error
參數(shù):
nginxConf=nginx 配置文件
nginxDir=nginx 目錄
logPrefixs=log文件前綴(多個(gè)逗號(hào)分隔)
windows 部署:
1.在 nginx 目錄,創(chuàng)建一個(gè) nginx_logs_backup.bat 文件;文件內(nèi)容如下
python nginx_logs_splter.py --nginxConf=nginx.conf --nginxDir=xxxxx --logPrefixs=access,error
2.在定時(shí)任務(wù)中加一個(gè)定時(shí)任務(wù),調(diào)用這個(gè) bat 文件;
2.1 開(kāi)始-程序-管理工具-任務(wù)計(jì)劃程序;
2.2 新建基本任務(wù);
2.3 注意的一點(diǎn)是,在"編輯操作"窗口,在"起始于(可選)"這一欄需要填入 bat 所在目錄,否則 bat 不會(huì)執(zhí)行;
'''
sys.exit(main(args.nginxConf,args.nginxDir,args.logPrefixs))
到此這篇關(guān)于淺析python 定時(shí)拆分備份 nginx 日志的方法的文章就介紹到這了,更多相關(guān)python nginx 日志內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Docker構(gòu)建python Flask+ nginx+uwsgi容器
- nginx搭建基于python的web環(huán)境的實(shí)現(xiàn)步驟
- python實(shí)現(xiàn)的分析并統(tǒng)計(jì)nginx日志數(shù)據(jù)功能示例
- python監(jiān)控nginx端口和進(jìn)程狀態(tài)
- Python開(kāi)發(fā)之Nginx+uWSGI+virtualenv多項(xiàng)目部署教程
- Python運(yùn)維自動(dòng)化之nginx配置文件對(duì)比操作示例
- 詳解python使用Nginx和uWSGI來(lái)運(yùn)行Python應(yīng)用
- Python的Flask框架及Nginx實(shí)現(xiàn)靜態(tài)文件訪問(wèn)限制功能
- 在阿里云服務(wù)器上配置CentOS+Nginx+Python+Flask環(huán)境
- python 檢測(cè)nginx服務(wù)郵件報(bào)警的腳本
相關(guān)文章
Pytorch Tensor基本數(shù)學(xué)運(yùn)算詳解
今天小編就為大家分享一篇Pytorch Tensor基本數(shù)學(xué)運(yùn)算詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12
jupyter notebook oepncv 顯示一張圖像的實(shí)現(xiàn)
這篇文章主要介紹了jupyter notebook oepncv 顯示一張圖像的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04
Python通過(guò)pytesseract庫(kù)實(shí)現(xiàn)識(shí)別圖片中的文字
Pytesseract是一個(gè)Python的OCR庫(kù),它可以識(shí)別圖片中的文本并將其轉(zhuǎn)換成文本形式。本文就來(lái)用pytesseract庫(kù)實(shí)現(xiàn)識(shí)別圖片中的文字,感興趣的可以了解一下2023-05-05
python的import?機(jī)制是怎么實(shí)現(xiàn)的
這篇文章主要介紹了python的import?機(jī)制是怎么實(shí)現(xiàn)的,import有Python運(yùn)行時(shí)的全局模塊池的維護(hù)和搜索、解析與搜索模塊路徑的樹(shù)狀結(jié)構(gòu)等作用,下文具體相關(guān)介紹需要的小伙伴可以參考一下2022-05-05
Python能干什么、Python主要應(yīng)用于哪些方面
無(wú)論是從入門(mén)級(jí)選手到專(zhuān)業(yè)級(jí)選手都在做的爬蟲(chóng),還是Web程序開(kāi)發(fā)、桌面程序開(kāi)發(fā)還是科學(xué)計(jì)算、圖像處理, Python都可以勝任。Python為我們提供了非常完善的基礎(chǔ)代碼庫(kù),覆蓋了網(wǎng)絡(luò)、文件、GUI、 數(shù)據(jù)庫(kù)、文本等大量?jī)?nèi)容。用Python開(kāi)發(fā),許多功能不必從零編寫(xiě)2023-06-06
python嵌套函數(shù)使用外部函數(shù)變量的方法(Python2和Python3)
這篇文章主要介紹了python嵌套函數(shù)使用外部函數(shù)變量的方法,需要的朋友可以參考下2016-01-01
Python統(tǒng)計(jì)日志中每個(gè)IP出現(xiàn)次數(shù)的方法
這篇文章主要介紹了Python統(tǒng)計(jì)日志中每個(gè)IP出現(xiàn)次數(shù)的方法,實(shí)例分析了Python基于正則表達(dá)式解析日志文件的相關(guān)技巧,需要的朋友可以參考下2015-07-07
使用IPython來(lái)操作Docker容器的入門(mén)指引
這篇文章主要介紹了使用IPython來(lái)操作Docker容器的方法,包括一些基本的搭建和連接,主要依靠docker-py模塊,需要的朋友可以參考下2015-04-04

