浅析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中模拟enum枚举类型的5种方法分享
Nov 22 Python
详解Python 2.6 升级至 Python 2.7 的实践心得
Apr 27 Python
Python实现使用卷积提取图片轮廓功能示例
May 12 Python
python 简单照相机调用系统摄像头实现方法 pygame
Aug 03 Python
新手入门Python编程的8个实用建议
Jul 12 Python
Pytorch 抽取vgg各层并进行定制化处理的方法
Aug 20 Python
Python字典中的值为列表或字典的构造实例
Dec 16 Python
关于Python中定制类的比较运算实例
Dec 19 Python
Python猴子补丁知识点总结
Jan 05 Python
python自定义函数def的应用详解
Jun 03 Python
浅谈keras 模型用于预测时的注意事项
Jun 27 Python
Python爬虫之Selenium实现键盘事件
Dec 04 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
微信公众号点击菜单即可打开并登录微站的实现方法
2014/11/14 PHP
thinkphp模板输出技巧汇总
2014/11/24 PHP
tp5框架使用cookie加密算法实现登录功能示例
2020/02/10 PHP
父子窗体间传递JSON格式的数据的代码
2010/12/25 Javascript
jquery下为Event handler传递动态参数的代码
2011/01/06 Javascript
jQuery + Flex 通过拖拽方式动态改变图片的代码
2011/08/03 Javascript
SuperSlide标签切换、焦点图多种组合插件
2015/03/14 Javascript
JavaScript通过字典进行字符串翻译转换的方法
2015/03/19 Javascript
javascript判断变量是否有值的方法
2015/04/20 Javascript
浅析BootStrap模态框的使用(经典)
2016/04/29 Javascript
ionic实现滑动的三种方式
2016/08/27 Javascript
微信小程序  action-sheet详解及实例代码
2016/11/09 Javascript
JQuery实现图片轮播效果
2017/05/08 jQuery
详解基于webpack搭建react运行环境
2017/06/01 Javascript
使用JQuery实现图片轮播效果的实例(推荐)
2017/10/24 jQuery
通过Nodejs搭建网站简单实现注册登录流程
2019/06/14 NodeJs
Vue使用NProgress的操作过程解析
2019/10/10 Javascript
Vue使用vue-recoure + http-proxy-middleware + vuex配合promise实现基本的跨域请求封装
2019/10/21 Javascript
vue实现瀑布流组件滑动加载更多
2020/03/10 Javascript
微信小程序用户盒子、宫格列表的实现
2020/07/01 Javascript
python计算最大优先级队列实例
2013/12/18 Python
python 将对象设置为可迭代的两种实现方法
2019/01/21 Python
Win10下用Anaconda安装TensorFlow(图文教程)
2020/06/18 Python
python用tkinter实现一个gui的翻译工具
2020/10/26 Python
python3实现简单飞机大战
2020/11/29 Python
scrapy-splash简单使用详解
2021/02/21 Python
List, Set, Map是否继承自Collection接口?
2016/05/16 面试题
护士自我鉴定范文
2013/10/06 职场文书
酒店人事专员岗位职责
2013/12/19 职场文书
社团活动总结怎么写
2014/06/30 职场文书
授权委托书
2014/07/31 职场文书
2014年销售内勤工作总结
2014/12/01 职场文书
毕业生就业推荐表导师评语
2014/12/31 职场文书
单位工作证明范本
2015/06/15 职场文书
黑暗中的舞者观后感
2015/06/18 职场文书
Javascript中Microtask和Macrotask鲜为人知的知识点
2022/04/02 Javascript