Logging日志模块

典型的日志记录的步骤是这样的:java

  1. 建立logger
  2. 建立handler
  3. 定义formatter
  4. 给handler添加formatter
  5. 给logger添加handler

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

复制代码
1 import logging 
 2 
 3 # 一、建立一个logger 
 4 logger = logging.getLogger('mylogger') 
 5 logger.setLevel(logging.DEBUG) 
 6 
 7 # 二、建立一个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 # 三、定义handler的输出格式(formatter)
16 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 
17 
18 # 四、给handler添加formatter
19 fh.setFormatter(formatter) 
20 ch.setFormatter(formatter) 
21 
22 # 五、给logger添加handler 
23 logger.addHandler(fh) 
24 logger.addHandler(ch)
复制代码

以后才能够正式的开始记录日志。Java里面的java.util.Logging类差很少也是这样,代码还要更复杂一点。Golang的日志相对写法简单一些,不过没有什么格式,系统记录一条时间,内容格式彻底本身手画。第三方的日志库却是没有接触过,像Java的Log4j,Golang的log4go和seelog等等,不知道用起来会不会简单一点。我一直都记不住这些,由于不太理解logger和handler为何要这样写。一直到此次任务中出现的在我看来至关“诡异”的bug,才深刻理解了一下。json

个人任务是这样的,要作一个日志切割的工具,按天将日志分割开,即天天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到时间。spa

 

叮!时间到。赶忙检查一下结果。一个好消息和一个坏消息。好消息是此次每一个日志都只切割生成了一个新文件,没有生成两个。坏消息是每一个文件里面添加的当天的日期的数量见鬼了。我切割了4条日志,生成的新日志里面就分别写上了1、2、3、四行当天日期。日志

 

此刻个人心里几乎是崩溃的。我开始思考为何会这样。很明显四行日期是调用了4次logger.fatal('datetime.datetime.now().strftime('%Y-%m-%d')) 这个函数。换句话说,我每一次for循环都在这个log里面写了一句话。但是明明每一个for是处理一个日志,下一次for应该是处理下一个日志的,为何会再处理这个日志一次?我忽然想到,logger.addHandler(handler)是每次循环都会运行的,也就是说,logger是同一个logger,添加了4次handler。到第4次循环的时候,这个logger中有4个handler,也就会往4个不一样的日志中添加内容了。呃。code

 

若是是这样的话,那么把上面的程序改改,第一句和最后一句放在循环外,循环内只用中间的三句。此次OK了。回头再看log记录的步骤,也就明白了logger和handler究竟是个什么鬼:logger能够看作是一个记录日志的人,对于记录的每一个日志,他须要有一套规则,好比记录的格式(formatter),等级(level)等等,这个规则就是handler。使用logger.addHandler(handler)添加多个规则,就可让一个logger记录多个日志。至于logging.getLogger()方法得到的root logger和继承关系,能够详见附注的网页,这里我也只是大概明白了什么意思,尚未具体用过。也许未来在框架中使用,要记录较为复杂的日志时候会用到吧。orm

相关文章
相关标签/搜索