python 多线程中 日志按天分割

Python028

python 多线程中 日志按天分割,第1张

python 的 logging 模块, 在多线程应用中, logging.hanlders.TimedRotatingFileHandler 不能正常按日期分割。

解决办法为:重写FileHandler类,用于多线程中日志按天分割。

之后,Logger定义日志的各种参数(格式等):

实例化日志:

python的多线程为伪多线程,多线程并不能提高文件IO的速度,在读取文件时使用直接读取 for line in open('文件名', 'r')  效率最高,因为此方式为直接读取,不像其它方式要把文件全部加载到内存再读取,所以效率最高。分割时文件时,提前计算好行数,把读取的每固定数量的行数存入新文件,直接读取完成,最后删除旧文件,即可实现文件分割。

示意代码:

line_count = 0

index = 0

fw = open('part'+str(index)+'.log', 'w')

for line in open('filename.log', 'r'):

    fw.write(line)

    line_count += 1

    # 假设每10000行写一个文件

    if line_count > 10000:

        fw.close()

        index += 1

        fw = open('part'+str(index)+'.log', 'w')

fw.close()

最近的任务经常涉及到日志的记录,特意去又学了一遍logging的记录方法。跟java一样,python的日志记录也是比较繁琐的一件事,在写一条记录之前,要写好多东西。典型的日志记录的步骤是这样的:

创建logger

创建handler

定义formatter

给handler添加formatter

给logger添加handler

写成代码差不多就是酱婶的(这个是照别的网页抄的,参考附注):

1 import logging

2

3 # 1、创建一个logger

4 logger = logging.getLogger('mylogger')

5 logger.setLevel(logging.DEBUG)

6

7 # 2、创建一个handler,用于写入日志文件

8 fh = logging.FileHandler('test.log')

9 fh.setLevel(logging.DEBUG)

10

11 # 再创建一个handler,用于输出到控制台

12 ch = logging.StreamHandler()

13 ch.setLevel(logging.DEBUG)

14

15 # 3、定义handler的输出格式(formatter)

16 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

17

18 # 4、给handler添加formatter

19 fh.setFormatter(formatter)

20 ch.setFormatter(formatter)

21

22 # 5、给logger添加handler

23 logger.addHandler(fh)

24 logger.addHandler(ch)

之后才可以正式的开始记录日志。Java里面的java.util.Logging类差不多也是这样,代码还要更复杂一点。Golang的日志相对

写法简单一些,不过没有什么格式,系统记录一条时间,内容格式完全自己手画。第三方的日志库倒是没有接触过,像Java的Log4j,Golang的

log4go和seelog等等,不知道用起来会不会简单一点。我一直都记不住这些,因为不太理解logger和handler为什么要这样写。一直到这

次任务中出现的在我看来相当“诡异”的bug,才深入理解了一下。

我的任务是这样的,要做一个日志切割的工具,按天将日志分割开,即每天0点产生一个新日志,将旧日志改名。并且,将超过3个月的日志删除掉,以保证磁盘空间不会被log占满。程序要求可以切割多个目录中的不同日志,具体路径由json中配置。

这里用到了logging.handlers类中的TimedRotatingFileHandler方法,用以获得一个handler。大概的写法为:

1 logger = logging.getLogger() #获得logger

2 handler = logging.handlers.TimedRotatingFileHandler(logfile, 'S', 1, 0) #切割日志

3 handler.suffix = '%Y%m%d' #切割后的日志设置后缀

4 logger.addHandler(handler) #把logger添加上handler

5 logger.fatal(datetime.datetime.now().strftime('%Y-%m-%d')) #在新日志中写上当天的日期

这里我没有设置level和formatter。因为只是分割,对新日志没有什么影响。TimedRotatingFileHandler函数的方

法见附注,或查看python的源码,这个函数是python写的,可以找到定义。这里我使用的是每秒生成一个新的日志文件,之后用Crontab在每天

0点调度,然后用for循环处理json中的每一个日志文件。

但是奇怪的是,每次运行程序,第一个切割的日志生成一个分割后的文件,而后面的都生成两个新日志。百思不得其解。后检查代码觉得,可能是程序中设置

的时间太短了,每秒生成一个文件,有可能一秒钟处理不完,就生成了两个。虽然这个说法没有什么科学根据,但是还是把

TimedRotatingFileHandler中的第三个参数改成了60,即每60秒生成一个文件。完成,静静的等待crontab到时间。