Python-logging模块
Posted JerryZao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python-logging模块相关的知识,希望对你有一定的参考价值。
1、日志级别:
日志级别指的是产生日志的事件的严重程度;
设置一个级别后,严重程度低于设置值的日志消息将被忽略 。
2、格式字符串
注意:funcName,threadName,processName 都是小驼峰命名
2、默认级别:
1 import logging 2 3 FORMAT = \'%(asctime)-15s\\t Thread info: %(thread)d %(threadName)s %(message)s\' 4 logging.basicConfig(format=FORMAT) 5 6 logging.info(\'I am {}\'.format(20)) 7 logging.warning(\'I am {}\'.format(20))
1 2018-10-30 13:57:32,714 Thread info: 9568 MainThread I am 20
默认级别是warning,所以低于warning的就无法显示。
3、构建消息:(格式定义使用的是C 风格的)
级别修改为 INFO 级别,两条都显示了
1 import logging 2 3 FORMAT = \'%(asctime)-15s\\t Thread info: %(thread)d %(threadName)s %(message)s\' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 logging.info(\'I am {}\'.format(20)) 7 logging.warning(\'I am {}\'.format(30))
1 2018-10-30 14:00:24,329 Thread info: 8724 MainThread I am 20 2 2018-10-30 14:00:24,329 Thread info: 8724 MainThread I am 30
使用字典,自定义一些显示信息(但是一般不会这么用,要不就直接定义到 FROMAT中)
1 import logging 2 3 FORMAT = \'%(asctime)-15s\\t Thread info: %(thread)d %(threadName)s %(message)s %(school)s\' 4 logging.basicConfig(format=FORMAT, level=logging.WARNING) 5 6 d = {\'school\':\'magedu\'} 7 8 logging.info(\'I am {}\'.format(20), extra=d) 9 logging.warning(\'I am {}\'.format(30), extra=d)
1 2018-10-30 14:04:28,030 Thread info: 10184 MainThread I am 30 magedu
4、修改日期格式:注意定义格式的位置 basicConfig
1 import logging 2 3 FORMAT = \'%(asctime)-15s\\t Thread info: %(thread)d %(threadName)s %(message)s \' 4 logging.basicConfig(format=FORMAT, level=logging.INFO, datefmt="%Y:%m:%d -- %H:%M:%S") 5 6 logging.info(\'I am {}\'.format(20)) 7 logging.warning(\'I am {}\'.format(30))
1 2018:10:30 -- 14:15:49 Thread info: 9864 MainThread I am 20 2 2018:10:30 -- 14:15:49 Thread info: 9864 MainThread I am 30
5、输出到文件: 注意定义格式的位置 basicConfig
1 import logging 2 3 FORMAT = \'%(asctime)-15s\\t Thread info: %(thread)d %(threadName)s %(message)s \' - 是向左靠齐,如果数字小于长度,不会截断 4 logging.basicConfig(format=FORMAT, level=logging.INFO, 5 datefmt="%Y:%m:%d -- %H:%M:%S", 6 filename=\'f:/test.log\' 7 ) 8 9 logging.info(\'I am {}\'.format(20)) 10 logging.warning(\'I am {}\'.format(30))
注:默认是追加模式,也就是追加模式,只为了输出到文件。
6、Logger类:
logging模块加载的时候,会创建一个root logger, 根Logger对象的默认级别是WARNING。
调用 logging.basicConfig 来调整级别,就是对这个根 Logger的级别进行修改
7、构造
logging.getLogger( [name= None) ]
使用工厂方法 返回 一个Logger实例
指定name,返回一个名称为 name 的 Logger实例,如果再次使用相同的名字,是实例化一个对象。
未指定 name, 返回的是 root Logger实例
1 import logging 2 3 FORMAT = \'%(name)s %(asctime)s %(thread)d %(threadName)s %(message)s \' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 logging.info(\'I am {}\'.format(20)) 7 8 log = logging.getLogger() 9 print(log.name) 10 print(logging.root.name) 11 12 log1 = logging.getLogger(\'s\') 13 print(log1.name) 14 15 log2 = logging.getLogger(\'s\') 16 print(log2.name) 17 18 log3 = logging.getLogger(\'s1\') 19 print(log3.name)
1 root 2 root 3 s 4 s 5 s1 6 root 2018-10-30 14:44:44,900 10024 MainThread I am 20
总结:
利用工程函数logging.getLogger(), 如果没有指定名字,就返回root ,如果执行,相当于创建一个新的logger对象,name是自己定义的。
如果在使用 工厂方法,name是之前的,也就是调用之前的logging对象,并没有创建新的 对象
8、层次构造:
Logger是层次结构的,使用 点号分割,如 a -- a.b ---a.b.c , a 是a.b的父,a.b是a的子。
1 import logging 2 3 FORMAT = \'%(name)s %(asctime)s %(thread)d %(threadName)s %(message)s \' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 logging.info(\'I am {}\'.format(20)) 7 8 log = logging.getLogger() 9 print(log.name) 10 print(logging.root.name) 11 12 log1 = logging.getLogger(\'s\') 13 print(log1.name) 14 15 log2 = logging.getLogger(\'s.s1\') 16 print(log2.name) 17 18 print(log2.parent) 19 print(log2.parent.name) 20 print(log2.parent.parent) 21 print(log2.parent.parent.name)
root 2018-10-30 14:52:48,827 5520 MainThread I am 20 root root s s.s1 <Logger s (INFO)> s <RootLogger root (INFO)> root
测试: 级别测试
1 import logging 2 3 FORMAT = \'%(asctime)s %(thread)d %(threadName)s %(message)s \' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 logger = logging.getLogger(__name__) # 创建一个新的logger,未定义级别 7 print(logger.name, type(logger)) 8 print(logger.level) # 新建的 logger 是未定义级别的,所以自己的级别是 0 9 print(logger.getEffectiveLevel()) # 有效级别 也就是从父类流过来的, 20(这里并不是继承) 10 11 logger.debug(\'==== hello ====\') # 不打印,级别小于INFO 12 logger.info(\'==== hello ====\') #输出 13 logger.warning(\'==== hello ====\') # 输出 14 15 16 logger.setLevel(10)# 这里是0,就从父logger来,不是0 就用自己的跟下面的比较 17 print(logger.level) # 30 18 logger.debug(\'==== h1 ====\') # 输出,大于10(debug) 19 logger.info(\'==== h2 ====\') # 20 logger.warning(\'==== h3 ====\') # 输出
1 D:\\python3.7\\python.exe E:/code_pycharm/tt.py 2 2018-10-30 15:09:37,638 8468 MainThread ==== hello ==== 3 __main__ <class \'logging.Logger\'> 4 2018-10-30 15:09:37,638 8468 MainThread ==== hello ==== 5 0 6 2018-10-30 15:09:37,638 8468 MainThread ==== h1 ==== 7 2018-10-30 15:09:37,638 8468 MainThread ==== h2 ==== 8 20 9 10 10 2018-10-30 15:09:37,638 8468 MainThread ==== h3 ==== 11 12 Process finished with exit code 0
1 import logging 2 3 FORMAT = \'%(asctime)s %(thread)d %(threadName)s %(message)s \' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 logger = logging.getLogger(__name__) # 创建一个新的logger,未定义级别 7 print(logger.name, type(logger)) 8 print(logger.level) # 新建的 logger 是未定义级别的,所以自己的级别是 0 9 print(logger.getEffectiveLevel()) # 有效级别 也就是从父类流过来的, 20(这里并不是继承) 10 11 logger.debug(\'==== hello ====\') # 不打印,级别小于INFO 12 logger.info(\'==== hello ====\') #输出 13 logger.warning(\'==== hello ====\') # 输出 14 15 16 logger.setLevel(18)# 这里是0,就从父logger来,不是0 就用自己的跟下面的比较 17 print(logger.level) # 30 18 logger.debug(\'==== h1 ====\') # 输出,大于10(debug) 19 logger.info(\'==== h2 ====\') # 20 logger.warning(\'==== h3 ====\') # 输出 21 print(logger.getEffectiveLevel(), \'===\') 22 23 print(logging.getLogger().getEffectiveLevel())
1 D:\\python3.7\\python.exe E:/code_pycharm/tt.py 2 2018-10-30 15:15:16,786 6624 MainThread ==== hello ==== 3 __main__ <class \'logging.Logger\'> 4 0 5 2018-10-30 15:15:16,786 6624 MainThread ==== hello ==== 6 20 7 18 8 2018-10-30 15:15:16,787 6624 MainThread ==== h2 ==== 9 18 === 10 20 11 2018-10-30 15:15:16,787 6624 MainThread ==== h3 ==== 12 13 Process finished with exit code 0
每一个 logger创建后 ,都有一个等效的level
logger对象可以在创建后动态的修改自己的 level
9、Hander:
Hander 控制 日志信息的输出目的地,可以是控制台,文件
可以单独设置level
可以单独设置格式
可以设置过滤器
Handler 类 继承
Handler:
StreamHandler: # 不指定输出方式,默认是 sys.stderr
FileHandler: #文件
_SterrHandlerr # 标准输出
NullHandler # 什么都不做
日志输出其实是Handler 做的,也就是真正干活的是Handler。
在 logging.basicConfig 中,如下:
1 if handlers is None: 2 filename = kwargs.pop(\'filename\', None) 3 mode = kwargs.pop(\'filemode\',\'a\') 4 if filename: 5 h = FileHandler(filename, mode) 6 else: 7 stream = kwargs.pop(\'stream\', None) 8 h = StreamHandler(stream) 9 handlers = [h]
注:
如果 设置文件名,则为根 logger 加一个输出到文件的Handler;如果没有设置文件名,则为 根logger 加一个StreamHadler,默认输出到sys.stderr
也就是说, 根logger 一定会至少有一个handler的
新创建的logger 是没有 handler的,但是 根handler 是有一个默认的 streamhandler,所以新建的logger就用根logger的。
测试:Handler的默认level
1 import logging 2 3 FORMAT = \'%(asctime)s %(name)s %(message)s\' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 logger = logging.getLogger(__name__) 7 print(logger.name, type(logger)) 8 9 logger.info(\'line ---- 1\') 10 11 handler = logging.FileHandler(\'f:\\\\ll.log\', \'a\') # filename, mode=\'a\', encoding=None, delay=False 12 logger.addHandler(handler) 13 print(logger.handlers) # [<FileHandler f:\\ll.log (NOTSET)>] 14 15 logger.info(\'line --- 2\')
结果可以看出:
默认handler是没有设置的 NOTSET
定义的FileHanfler 是最简单的 就一个message 输出。
logger 这个对象,一个是利用的root的streamhandler 打印到stderr, 一个是自定义的filehandler ,输出到文件
测试:handler的level, 为了方便看文件,使用w 模式
1 import logging 2 3 FORMAT = \'%(asctime)s %(name)s %(message)s\' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 logger = logging.getLogger(__name__) 7 print(logger.name, type(logger)) 8 9 logger.info(\'line ---- 1\') 10 11 handler = logging.FileHandler(\'f:\\\\ll.log\', \'w\') # filename, mode=\'a\', encoding=None, delay=False 12 logger.addHandler(handler) 13 handler.setLevel(50) 14 15 logger.info(\'line --- 2\') 16 print(logger.handlers) # [<FileHandler f:\\ll.log (NOTSET)>]
结果可以看到:
filehandler的level设置为50 ,不影响stderr 输出,只影响了文件输出。
因为logger的输出级别是info,小于 50,所以输出不到文件
10、继承关系 及信息传递:
propagate的使用:
官方日志流转图:
实例:
1 import logging 2 3 FORMAT = \'%(asctime)s %(name)s %(message)s\' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 root = logging.getLogger() 7 root.setLevel(logging.ERROR) 8 print(\'root\', root.handlers) 9 10 h0 = logging.StreamHandler() 11 h0.setLevel(logging.WARNING) 12 13 root.addHandler(h0) 14 print(\'root\', root.handlers) 15 16 for h in root.handlers: 17 print(\'root handler = {}, formatter = {}\'.format(h, h.formatter)) 18 19 \'\'\' 20 root [<StreamHandler <stderr> (NOTSET)>] 21 root [<StreamHandler <stderr> (NOTSET)>, <StreamHandler <stderr> (WARNING)>] 22 root handler = <StreamHandler <stderr> (NOTSET)>, formatter = <logging.Formatter object at 0x000000000224C908> 23 root handler = <StreamHandler <stderr> (WARNING)>, formatter = None 24 \'\'\' 25 ################################################################################ 26 print(\'==================================================\') 27 28 log1 = logging.getLogger(\'s\') 29 log1.setLevel(logging.ERROR) 30 h1 = logging.FileHandler(\'f:/tets.log\') 31 h1.setLevel(logging.WARNING) 32 log1.addHandler(h1) 33 print(\'h1\', log1.handlers) 34 35 print(\'==================================================\') 36 37 log2 = logging.getLogger(\'s.s1\') 38 log2.setLevel(logging.CRITICAL) 39 h2 = logging.FileHandler(\'f:/tets.log\') 40 h2.setLevel(logging.WARNING) 41 log2.addHandler(h2) 42 print(\'h2\', log2.handlers) 43 44 print(\'==================================================\') 45 46 log3 = logging.getLogger(\'s.s1.s2\') 47 log3.setLevel(logging.INFO) 48 print(log3.getEffectiveLevel()) 49 h3 = logging.FileHandler(\'f:/tets.log\') 50 h3.setLevel(logging.WARNING) 51 log3.addHandler(h3) 52 print(\'h3\', log3.handlers)
1 D:\\python3.7\\python.exe E:/code_pycharm/tt2.py 2 root [<StreamHandler <stderr> (NOTSET)>] 3 root [<StreamHandler <stderr> (NOTSET)>, <StreamHandler <stderr> (WARNING)>] 4 root handler = <StreamHandler <stderr> (NOTSET)>, formatter = <logging.Formatter object at 0x0000000001DD73C8> 5 root handler = <StreamHandler <stderr> (WARNING)>, formatter = None 6 ================================================== 7 h1 [<FileHandler f:\\tets.log (WARNING)>] 8 ================================================== 9 h2 [<FileHandler f:\\tets.log (WARNING)>] 10 ================================================== 11 20 12 h3 [<FileHandler f:\\tets.log (WARNING)>] 13 14 Process finished with exit code 0
11、Formatter
logging的Formatter类,它允许指定某个格式的字符串,如果提供None,那么 %(message)s作为默认值
修改上面的实例:
1 import logging 2 3 FORMAT = \'%(asctime)s %(name)s %(message)s\' 4 logging.basicConfig(format=FORMAT, level=logging.INFO) 5 6 root = logging.getLogger() 7 root.setLevel(logging.ERROR) 8 print(\'root\', root.handlers) 9 10 h0 = logging.StreamHandler() 11 h0.setLevel(logging.WARNING) 12 13 root.addHandler(h0) 14 print(\'root\', root.handlers) 15 16 for h in root.handlers: 17 print(\'root handler = {}, formatter = {}\'.format(h, h.formatter)) 18 19 \'\'\' 20 root [<StreamHandler <stderr> (NOTSET)>] 21 root [<StreamHandler <stderr> (NOTSET)>, <StreamHandler <stderr> (WARNING)>] 22 root handler = <StreamHandler <stderr> (NOTSET)>, formatter = <logging.Formatter object at 0x000000000224C908> 23 root handler = <StreamHandler <stderr> (WARNING)>, formatter = None 24 \'\'\' 25 ################################################################################ 26 print(\'==================================================\') 27 28 log1 = logging.getLogger(\'s\') 29 log1.setLevel(logging.ERROR) 30 h1 = logging.FileHandler(\'f:/tets.log\') 31 h1.setLevel(logging.WARNING) 32 print(\'h1 handler = {}, formatter = {}\'.format(h1, h1.formatter)) 33 log1.addHandler(h1) 34 print(\'h1\', log1.handlers) 35 36 print(\'==================================================\') 37 38 log2 = logging.getLogger(\'Python-logging详解(彩色日志扩展,多进程安全等)Python-logging详解(彩色日志扩展,多进程安全等)
如何使用模块化代码片段中的LeakCanary检测内存泄漏?
CTS测试CtsWindowManagerDeviceTestCases模块的testShowWhenLockedImeActivityAndShowSoftInput测试fail项解决方法(代码片段