浅析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的框架中一些会话程序的管理
Apr 20 Python
python中的格式化输出用法总结
Jul 28 Python
python 对key为时间的dict排序方法
Oct 17 Python
对python中字典keys,values,items的使用详解
Feb 03 Python
Python3.5基础之函数的定义与使用实例详解【参数、作用域、递归、重载等】
Apr 26 Python
python SVD压缩图像的实现代码
Nov 05 Python
Python自动化测试笔试面试题精选
Mar 12 Python
Python使用pyyaml模块处理yaml数据
Apr 14 Python
Python flask框架实现查询数据库并显示数据
Jun 04 Python
用Python制作mini翻译器的实现示例
Aug 17 Python
如何使用Python自动生成报表并以邮件发送
Oct 15 Python
Python中zipfile压缩包模块的使用
May 14 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
PHILIPS AE3805收音机的分析打磨
2021/03/02 无线电
原生php实现excel文件读写的方法分析
2018/04/25 PHP
js form 验证函数 当前比较流行的错误提示
2009/06/23 Javascript
关于Jqzoom的使用心得 jquery放大镜效果插件
2010/04/12 Javascript
js获得地址栏?问号后参数的方法
2013/08/08 Javascript
动态载入js提高网页打开速度的方法
2014/07/04 Javascript
javascript实现一个数值加法函数
2015/06/26 Javascript
JavaScript黑洞数字之运算路线查找算法(递归算法)实例
2016/01/28 Javascript
JavaScript操作表单实例讲解(上)
2016/06/20 Javascript
第八篇Bootstrap下拉菜单实例代码
2016/06/21 Javascript
Map.vue基于百度地图组件重构笔记分享
2017/04/17 Javascript
jQuery实现标签子元素的添加和赋值方法
2018/02/24 jQuery
javascript与PHP动态往类中添加方法对比
2018/03/21 Javascript
详解ES6中的 Set Map 数据结构学习总结
2018/11/06 Javascript
微信小程序把百度地图坐标转换成腾讯地图坐标过程详解
2019/07/10 Javascript
vue实现表格过滤功能
2019/09/27 Javascript
Vue实现页面添加水印功能
2019/11/09 Javascript
javascript实现简易的计算器
2020/01/17 Javascript
使用Node.js实现base64和png文件相互转换的方法
2020/03/11 Javascript
Python通过websocket与js客户端通信示例分析
2014/06/25 Python
讲解Python中fileno()方法的使用
2015/05/24 Python
举例讲解Python中的Null模式与桥接模式编程
2016/02/02 Python
Python中random模块生成随机数详解
2016/03/10 Python
python 读取.csv文件数据到数组(矩阵)的实例讲解
2018/06/14 Python
Python实现重建二叉树的三种方法详解
2018/06/23 Python
通过cmd进入python的步骤
2020/06/16 Python
Python如何执行系统命令
2020/09/23 Python
Vilebrequin欧洲官网:法国豪华泳装品牌(男士沙滩裤)
2018/04/14 全球购物
莫斯科隐形眼镜网上商店:Linzi
2019/07/22 全球购物
后勤副校长自我鉴定
2013/10/13 职场文书
主持人演讲稿范文
2013/12/28 职场文书
党建示范点实施方案
2014/03/12 职场文书
个人银行贷款担保书
2014/04/01 职场文书
服务之星事迹材料
2014/05/03 职场文书
说明书格式及范文
2014/05/07 职场文书
三八红旗手先进事迹材料
2014/05/13 职场文书