Python中的logger和handler到底是个什么鬼
最近的任务经常涉及到日志的记录,特意去又学了一遍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到时间。
叮!时间到。赶紧检查一下结果。一个好消息和一个坏消息。好消息是这次每个日志都只切割生成了一个新文件,没有生成两个。坏消息是每个文件里面添加的当天的日期的数量见鬼了。我切割了4条日志,生成的新日志里面就分别写上了一、二、三、四行当天日期。
此刻我的内心几乎是崩溃的。我开始思考为什么会这样。很明显四行日期是调用了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个不同的日志中添加内容了。呃。
如果是这样的话,那么把上面的程序改改,第一句和最后一句放在循环外,循环内只用中间的三句。这次OK了。回头再看log记录的步骤,也就明白了logger和handler到底是个什么鬼:logger可以看做是一个记录日志的人,对于记录的每个日志,他需要有一套规则,比如记录的格式(formatter),等级(level)等等,这个规则就是handler。使用logger.addHandler(handler)添加多个规则,就可以让一个logger记录多个日志。至于logging.getLogger()方法获得的root logger和继承关系,可以详见附注的网页,这里我也只是大概明白了什么意思,还没有具体用过。也许将来在框架中使用,要记录较为复杂的日志时候会用到吧。
Python中的logger和handler到底是个什么鬼的更多相关文章
- python中的logger模块
logger 提供了应用程序可以直接使用的接口handler将(logger创建的)日志记录发送到合适的目的输出filter提供了细度设备来决定输出哪条日志记录formatter决定日志记录的最终输出 ...
- python中的logger模块详细讲解
logger 提供了应用程序可以直接使用的接口handler将(logger创建的)日志记录发送到合适的目的输出filter提供了细度设备来决定输出哪条日志记录formatter决定日志记录的最终输出 ...
- (转)python中的*args和**kw到底是个啥。看下面的例子就会懂了
先来看个例子: def foo(*args, **kwargs): print 'args = ', args print 'kwargs = ', kwargs print '----------- ...
- Python中的@函数装饰器到底是什么?
在解释@函数装饰器之前,先说一下,类中的类方法和静态方法. 在Python中完全支持定义类方法.静态方法.这两种方法很相似,Python它们都使用类来调用(ps:用对象调用也可以). 区别在于:Pyt ...
- python中的日志,logger用法
python中自带logger模块,实现方法有两种,一般使用第二种,更灵活 方法一: import logging # 通过logging.basicConfig完成 logging.basicCon ...
- python 中__name__ = '__main__' 的作用,到底干嘛的?
python 中__name__ = 'main' 的作用,到底干嘛的? 有句话经典的概括了这段代码的意义: "Make a script both importable and execu ...
- python中的cls到底指的是什么
python中的cls到底指的是什么,与self有什么区别? 2018年07月31日 11:13:09 rs勿忘初心 阅读数:7769 作者:秦风链接:https://www.zhihu.com/ ...
- Python 中的数字到底是什么?
花下猫语:在 Python 中,不同类型的数字可以直接做算术运算,并不需要作显式的类型转换.但是,它的"隐式类型转换"可能跟其它语言不同,因为 Python 中的数字是一种特殊的对 ...
- Python 中的元类到底是什么?这篇恐怕是最清楚的了
类作为对象 在理解元类之前,您需要掌握 Python 的类.Python 从 Smalltalk 语言中借用了一个非常特殊的类概念. 在大多数语言中,类只是描述如何产生对象的代码段.在 Python ...
随机推荐
- 查看Linux下系统资源占用常用命令
一 top命令 1.作用top命令用来显示执行中的程序进程,使用权限是所有用户. 2.格式top [-] [d delay] [q] [c] [S] [s] [i] [n] 3.主要参数d:指定更新的 ...
- SSH项目搭建(五)——web.xml文件配置
上一章写到pom.xml有一个报错,说找不到web.xml文件.确实是这样的,因为我们用maven搭建的web层里就是没有这个文件.我们能看到,webapp文件夹里是空的. 没有,就想办法把它弄出来. ...
- matlab reshape()、full()
一.reshape() 对于这个函数,就是重构矩阵. (1)要求:重构前后的矩阵元素个数一致.如3*4矩阵可以重构成2*6,2*3*2等. (2)重构方法:先按列将矩阵转换为向量,然后在向量的基础之上 ...
- stm32 DAC配置
VDDA 和 VSSA 为 DAC 模块模拟部分的供电,而 Vref+则是 DAC 模块的参考电压.DAC_OUTx 就是 DAC 的 输出通道了 (对应 PA4 或者 PA5 引脚). 由第一张图可 ...
- [LeetCode&Python] Problem 476. Number Complement
Given a positive integer, output its complement number. The complement strategy is to flip the bits ...
- Gym 101745 D.Stamp Stamp Stamp
题目网页链接: http://codeforces.com/gym/101745/problem/D 思路:首先可以确保能够成功染色的字符串都是结果串的子串,那么O(n^2)枚举子串之后dp转移即可. ...
- 【java规则引擎】《Drools7.0.0.Final规则引擎教程》第4章 4.3 日历
日历 日历可以单独应用于规则中,也可以和timer结合使用在规则中使用.通过属性calendars来定义日历.如果是多个日历,则不同日历之间用逗号进行分割. 在Drools中,日历的概念只是将日历属性 ...
- LG2731 骑马修栅栏 Riding the Fences
题意 John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经过一个栅栏.你必须编一个程序,读入栅栏网络的描述,并计算出一条修栅栏的路径,使每个栅栏都恰好被经过一次.John能从任何一个顶点( ...
- ElasticSearch 5.0 简介
参考:http://blog.csdn.net/wzhg0508/article/details/52063676 Elasticsearch 5.0 简介(medcl微信直播实录) 大家好,非常高兴 ...
- dbt macro 说明
macro是SQL的片段,可以像模型中的函数一样调用.macro可以在模型之间重复使用SQL,以符合DRY(不要重复自己)的工程原理. 此外,共享包可以公开您可以在自己的dbt项目中使用的macro. ...