浅析python 定时拆分备份 nginx 日志的方法


Posted in Python onApril 27, 2020

一、背景:

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,"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('总记录数\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}:\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("#备份时间\t%s\n" % today.strftime('%Y-%m-%d %H:%M:%S'))
 outputFile.writelines("#版本号\t%s\n" % _version)
 #转存 tmp 文件
 with open(tmpFileFullName, 'r', 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,"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执行 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,"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("参数为空:--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 日志的方法的文章就介绍到这了,更多相关python nginx 日志内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
详解python使用递归、尾递归、循环三种方式实现斐波那契数列
Jan 16 Python
Python迭代器和生成器定义与用法示例
Feb 10 Python
python中map的基本用法示例
Sep 10 Python
Python 微信之获取好友昵称并制作wordcloud的实例
Feb 21 Python
python使用adbapi实现MySQL数据库的异步存储
Mar 19 Python
Python 获取ftp服务器文件时间的方法
Jul 02 Python
python selenium循环登陆网站的实现
Nov 04 Python
python GUI库图形界面开发之PyQt5简单绘图板实例与代码分析
Mar 08 Python
记录模型训练时loss值的变化情况
Jun 16 Python
python re的findall和finditer的区别详解
Nov 15 Python
Python实现Word文档转换Markdown的示例
Dec 22 Python
Python可视化动图组件ipyvizzu绘制惊艳的可视化动图
Apr 21 Python
python异步Web框架sanic的实现
Apr 27 #Python
python库skimage给灰度图像染色的方法示例
Apr 27 #Python
python实现密度聚类(模板代码+sklearn代码)
Apr 27 #Python
Django中文件上传和文件访问微项目的方法
Apr 27 #Python
详解Python中namedtuple的使用
Apr 27 #Python
Python PyQt5运行程序把输出信息展示到GUI图形界面上
Apr 27 #Python
使用python实现微信小程序自动签到功能
Apr 27 #Python
You might like
用PHP实现读取和编写XML DOM代码
2010/04/07 PHP
windows环境下使用Composer安装ThinkPHP5
2018/05/18 PHP
php多进程模拟并发事务产生的问题小结
2018/12/07 PHP
基于jQuery判断两个元素是否有重叠部分的代码
2012/07/25 Javascript
javascript控制swfObject应用介绍
2012/11/29 Javascript
Jquery实现的一种常用高亮效果示例代码
2014/01/28 Javascript
jquery下div 的resize事件示例代码
2014/03/09 Javascript
NodeJS中利用Promise来封装异步函数
2015/02/25 NodeJs
JQuery+EasyUI轻松实现步骤条效果
2016/02/22 Javascript
vue 自定义组件 v-model双向绑定、 父子组件同步通信的多种写法
2017/11/27 Javascript
浅谈vue单一组件下动态修改数据时的全部重渲染
2018/03/01 Javascript
浅谈在Vue.js中如何实现时间转换指令
2019/01/06 Javascript
Angular CLI 使用教程指南参考小结
2019/04/10 Javascript
JavaScript中将值转换为字符串的五种方法总结
2019/06/06 Javascript
vue中el-input绑定键盘按键(按键修饰符)
2020/07/22 Javascript
[05:03]2018DOTA2亚洲邀请赛主赛事首日回顾
2018/04/04 DOTA
全面解读Python Web开发框架Django
2014/06/30 Python
Python实现拷贝多个文件到同一目录的方法
2016/09/19 Python
使用Python多线程爬虫爬取电影天堂资源
2016/09/23 Python
Python加密方法小结【md5,base64,sha1】
2017/07/13 Python
Python序列化基础知识(json/pickle)
2017/10/19 Python
python去掉 unicode 字符串前面的u方法
2018/10/21 Python
python 实现Flask中返回图片流给前端展示
2020/01/09 Python
CSS3过渡transition效果实例介绍
2016/05/03 HTML / CSS
ROSEFIELD手表荷兰官方网上商店:北欧极简设计女士腕表品牌
2018/01/24 全球购物
澳大利亚在线生活方式商店:Mytopia
2018/07/08 全球购物
英国在线女鞋目的地:SIMMI
2018/12/27 全球购物
英国在线药房:Chemist.co.uk
2019/03/26 全球购物
FC-Moto英国:欧洲最大的摩托车服装和头盔商店之一
2019/08/25 全球购物
工作的心得体会
2013/12/31 职场文书
给老师的一封建议书
2014/03/13 职场文书
爱心捐款倡议书
2014/04/14 职场文书
飞机制造技术专业求职信
2014/07/27 职场文书
工作作风整顿个人剖析材料
2014/10/11 职场文书
2015小学教师德育工作总结
2015/05/12 职场文书
民事撤诉申请书范本
2015/05/18 职场文书