解决办法为:重写FileHandler类,用于多线程中日志按天分割。
之后,Logger定义日志的各种参数(格式等):
实例化日志:
python的多线程为伪多线程,多线程并不能提高文件IO的速度,在读取文件时使用直接读取 for line in open('文件名', 'r') 效率最高,因为此方式为直接读取,不像其它方式要把文件全部加载到内存再读取,所以效率最高。分割时文件时,提前计算好行数,把读取的每固定数量的行数存入新文件,直接读取完成,最后删除旧文件,即可实现文件分割。
示意代码:
line_count = 0index = 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到时间。