|
|
silon212
发表于 2011-2-10 17:13:01
|
显示全部楼层
对之前的 mygzip.py (CGI) 的使用做一下更新
(1). 之前的 mygzip.py 有点小问题,如果是 HM 主机用的是 py2.4 则没有全局的 exit() 函数,所以要把 exit(-1) 改成 sys.exit(-1),当时开发时在 py2.6 下,所以没发现这个 BUG。
(2). 写了一个 clean_mygzip.py,它是一个清理 mygzip.py 的压缩日志 mygzip.log 的程序,配合 mygzip.py 起来很好。
功能是根据“压缩的时间范围条件”和“压缩后的 gzip 文件名模式”匹配日志 mygzip.log 中记录的 .gz 文件路径,然后删除这些缓存的 .gz 文件,并清理日志中对应的行。
当更新 .css、.js 后,可以用 clean_mygzip.py 清理以前经 mygzip.py 压缩后缓存的 .css.gz、.js.gz 文件。也可用 cron 定时执行 clean_mygzip.py
其实,用 find 命令的 -iname 和 -newer 选项也可以完成 clean_mygzip.py 的批量删除缓存 .gz 的作用,但是考虑 web 服务目录下可能有除 mygzip.py 生成的 .gz 之外的其它的 .gz 文件,所以最好还是读取 mygzip.py 的压缩日志,根据日志的记录来删除缓存的 .gz。
使用示例:- # 最简单的使用方法:删除所有 mygzip.log 中记录的 .gz 文件,并清空日志
- clean_mygzip.py -l mygzip.log
- # 删除 mygzip.log 中所有匹配文件名 index.css 或 index.js 的 .gz 文件,如 index.css.gz
- clean_mygzip.py -f "index\.(css|js)" -l mygzip.log
- # 删除 mygzip.log 中压缩时间从 2011-01-27 21:24:57 到现在的 .gz 文件
- clean_mygzip.py -t 2011/1/27@21:24:57- -l /path/to/mygzip.log
复制代码 clean_mygzip.py 代码如下:- #!/usr/bin/env python
- #coding=utf-8
- ##########
- #
- # 本脚本是配合 mygzip.py CGI 脚本的程序
- # 本脚本读取 mygzip.py 生成的 gzip 压缩日志文件 mygzip.log,根据指定时间和 gzip
- # 路径名条件,删除日志中匹配的 gzip 文件,并清理日志中的匹配行
- #
- # 使用示例:
- # clean_mygzip.py -f "index\.(css|js)" -t 2011/1/27@21:24:57- -l /path/to/mygzip.log
- # 表示删除 mygzip.log 中记录的 gzip 压缩时间从 2011-01-27 21:24:57 到现在的 gzip 文件,
- # 并且这些 gzip 文件名为 index.css.gz 或 index.js.gz;删除掉 gzip 文件后,也会清理日志中
- # 的对应行
- #
- # -t 指定的时间格式为 'BEG-END',BEG 和 END 的格式都为 'YYYY/MM/DD@HH:MM:SS'
- # BEG 为开始时间,如果省略 BEG,取开始时间为 1900/01/01@00:00:00
- # END 为结束时间,如果省略 END,取结束时间为当前时间(web 服务器)
- # -f 指定的 gzip 文件路径正则表达式,如果其中有空格字符,需用 "" 括起来(不要用 '' 括起来)
- # 如 -f "index style\.css"
- #
- # 如果省略 -t,表示对所有的压缩时间都会清理,是否清理由 -f 指定的文件名模式(正则)决定
- # 如果省略 -f,表示对所有的 gzip 文件名都会清理,是否清理由 -t 指定的时间范围决定
- # -t、-f 都省略,表示将删除日志中所有行对应的 gzip 文件,日志也将会清空
- #
- # 文件共享操作问题:
- # 因为 mygzip.log 日志可能正在由 mygzip.py CGI 脚本访问,并且
- # 需要删除的 gzip 文件,可能正在由 web 服务访问
- # 如果删除 gzip 文件失败,会将删除失败的日志行写入新的日志文件:和 -l 指定的日志文件同目录同名带 .err 的文件
- # 如果删除原 -l 日志文件失败,则保留处理后的临时日志文件,此后可手工重命名
- #
- # by breaker.zy@gmail.com, 2011-01
- #
- ##########
- import sys
- import os.path
- import datetime
- import time
- import getopt
- import re
- import random
- SCRIPT_NAME = ''
- GZIP_PATTERN = ''
- GZIP_LOG = ''
- NOW = datetime.datetime.now()
- TIME_BEGIN = None
- TIME_END = None
- DEF_TIME_BEGIN = datetime.datetime(1900, 1, 1)
- DEF_TIME_END = NOW
- STRTIME_END = 19
- ERR_LOG_SUFFIX = '.err'
- def usage() :
- print 'usage:'
- print SCRIPT_NAME, '-t TIME-RANGE -f GZIP-FILE-REGEX -l MYGZIP.log\n'
- print " all gzip files matched by -t AND -f condition in MYGZIP.log will be deleted, and the matched line in log file will be removed.\n"
- print "-t give time range, format is 'YYYY/MM/DD@HH:MM:SS-YYYY/MM/DD@HH:MM:SS'"
- print " if begin time omited, it uses '%s'" % datetime.datetime(1900,1,1).strftime('%Y/%m/%d@%H:%M:%S')
- print " if end time omited, it uses Current Time."
- print " if -t omited, any time is accepted.\n"
- print "-f give the gzip file path pattern."
- print " it uses regular expression to match file path."
- print " if -f omited, any gzip file path is matched.\n"
- print "-l give the mygzip generated log file path."
- print " -l is mandatory."
- # 解决 datetime.strptime() 在 Python 2.5 之后才可用的问题
- def strptime_(strdate, datefmt) :
- return datetime.datetime(*(time.strptime(strdate, datefmt)[0:6]))
- # 解析命令行参数
- def parse_opts() :
- global SCRIPT_NAME, GZIP_LOG, GZIP_PATTERN, TIME_BEGIN, TIME_END
- SCRIPT_NAME = os.path.basename(__file__)
- try :
- opts, left_args = getopt.getopt(sys.argv[1:], 't:f:l:')
- except Exception, ex :
- print 'parse options error:', str(ex), '\n'
- usage()
- sys.exit(-1)
- time_range = ''
- for o, a in opts :
- if o == '-t' :
- time_range = a.strip()
- elif o == '-f' :
- GZIP_PATTERN = a
- elif o == '-l' :
- GZIP_LOG = a.strip()
- if GZIP_LOG == '' :
- print '-l is mandatory, and MUST NOT be none.\n'
- usage()
- sys.exit(-1)
- # 解析 -t 选项
- if time_range != '' :
- # BEGIN
- time_range = time_range.split('-')
- if len(time_range) != 2 :
- print '-t time range format is wrong.\n'
- usage()
- sys.exit(-1)
- dt = []
- try :
- for i in (0, 1) :
- if time_range[i].strip() == '' :
- if i == 0 :
- dt.append(DEF_TIME_BEGIN)
- else :
- dt.append(DEF_TIME_END)
- else :
- dt.append(strptime_(time_range[i], '%Y/%m/%d@%H:%M:%S'))
- except Exception, ex :
- print '-t time range format is wrong:', str(ex), '\n'
- usage()
- sys.exit(-1)
- TIME_BEGIN = dt[0]
- TIME_END = dt[1]
- if TIME_BEGIN > TIME_END :
- print "-t time range is weird: begin time '%s' is later than end time '%s'\n" % (TIME_BEGIN.strftime('%Y/%m/%d@%H:%M:%S'), TIME_END.strftime('%Y/%m/%d@%H:%M:%S'))
- usage()
- sys.exit(-1)
- # END
- # TEST
- def test() :
- print '***** TEST BEGIN *****'
- if TIME_BEGIN != None and TIME_END != None :
- print 'begin time: %s, end time: %s' % (TIME_BEGIN.strftime('%Y/%m/%d@%H:%M:%S'), TIME_END.strftime('%Y/%m/%d@%H:%M:%S'))
- else :
- print '-t is not given.'
- print "gzip pattern: [%s]" % GZIP_PATTERN
- print "log file: [%s]" % GZIP_LOG
- print '***** TEST END *****'
- def main() :
- try :
- f_log = open(GZIP_LOG, 'r')
- except Exception, ex :
- print 'open mygzip log file error:', str(ex)
- sys.exit(-1)
- # 处理日志的每一行
- ln = 0
- will_del = False
- update_log = False
- remainlns = []
- failedlns = [] # 匹配删除 gzip 文件的行,但删除 gzip 文件失败的行
- for line in f_log :
- # BEGIN
- line = line.strip()
- ln += 1
- strtime = line[:STRTIME_END]
- gzpath = line[STRTIME_END + 1:].lstrip()
- # TEST
- #print 'strtime: [%s]' % strtime
- #print 'gzpath: [%s]' % gzpath
- try :
- dt = strptime_(strtime, '%Y-%m-%d %H:%M:%S')
- if gzpath == '' :
- raise AssertionError, 'there is no gzip file path in log file'
- except Exception, ex :
- print 'log file may corrupt:'
- print ' log file format is wrong:', str(ex)
- print ' line %d, log file path: %s' % (ln, f_log.name)
- sys.exit(-1)
- # 判断 -t 条件(时间匹配)
- if TIME_BEGIN != None and TIME_END != None :
- will_del = (dt >= TIME_BEGIN and dt <= TIME_END)
- else :
- will_del = True
- # -t、-f 之间是与关系,必需同时满足才删除 gzip 文件
- if not will_del :
- remainlns.append(line)
- continue
- # 判断 -f 条件(gzip 文件路径匹配)
- if GZIP_PATTERN == '' :
- will_del = True
- else :
- will_del = (re.search(GZIP_PATTERN, gzpath) != None)
- # 删除 gzip 文件
- # TEST
- #print 'will_del:', will_del
- if will_del :
- update_log = True
- if not remove_file(gzpath) :
- failedlns.append(line)
- else :
- remainlns.append(line)
- # END
- # TEST
- #print 'failedlns:', failedlns
- #print 'remainlns:', remainlns
- f_log.close()
- if update_log :
- write_log(remainlns, failedlns)
- # 写入处理后的 mygzip 日志文件,remainlns 是原日志中未匹配删除 gzip 文件的行,failedlns 是匹配删除 gzip 文件的行,但删除 gzip 文件失败
- def write_log(remainlns, failedlns) :
- tmpf = '%s_%s_%d' % (GZIP_LOG, NOW.strftime('%y%m%d%H%M%S'), random.randint(0,99))
- while os.path.exists(tmpf) :
- tmpf = '%s_%s_%d' % (GZIP_LOG, NOW.strftime('%y%m%d%H%M%S'), random.randint(0,99))
- f_log = open(tmpf, 'w')
- f_log.writelines(['%s%s' % (i, '\n') for i in remainlns])
- f_log.close()
- try :
- if not remove_file(GZIP_LOG) :
- raise AssertionError, 'cannot remove old log file: %s' % GZIP_LOG
- os.rename(tmpf, GZIP_LOG)
- except Exception, ex:
- print 'rename temp file to old log file name error:', str(ex)
- print ' temp file:', os.path.realpath(tmpf)
- print ' old log file:', os.path.realpath(GZIP_LOG)
- if failedlns != [] :
- f_err = open(GZIP_LOG + ERR_LOG_SUFFIX, 'a')
- f_err.writelines(['%s%s' % (i, '\n') for i in failedlns])
- f_err.close()
- # 删除 path 指定文件,retry 是删除失败时重试的次数,retry_wait 是重试前等待的时间间隔(秒)
- def remove_file(path, retry = 3, retry_wait = 1) :
- if not os.path.exists(path) :
- return True
- removed = False
- i = 0
- while i < retry and not removed :
- i += 1
- try :
- os.remove(path)
- removed = True
- except Exception, ex :
- if not os.path.exists(path) :
- removed = True
- time.sleep(retry_wait)
- return removed
- if __name__ == '__main__' :
- parse_opts()
- # test()
- main()
复制代码 |
|