欢迎访问优讯网!
您当前的位置:首页 > 爱编程

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

时间:2020-04-28 09:29:02  来源:优讯网  作者:小卡司  浏览次数:
本文给大家分享python 定时拆分备份 nginx 日志的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

一、背景:

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 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#!/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 日志的方法的文章就介绍到这了

来顶一下
返回首页
返回首页

原文链接:https://www.jb51.net/article/185586.htm


推荐资讯
如何下载旧版centos iso镜像 如何下载迷你mini版的centos镜像
如何下载旧版centos i
计算机的正确使用姿势 电脑痴如何正确的使用电脑
计算机的正确使用姿势
好用的后台管理的前端框架模版H-ui H-ui框架模版分享
好用的后台管理的前端
微信电脑多开方法 无需辅助电脑版微信双开方法分享
微信电脑多开方法 无
相关文章
栏目更新
栏目热门