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)>]
测试handler级别

 

 

      结果可以看到:

        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)
View Code 
 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详解(彩色日志扩展,多进程安全等)

python-logging用法

如何使用模块化代码片段中的LeakCanary检测内存泄漏?

如何有条件地将 C 代码片段编译到我的 Perl 模块?

CTS测试CtsWindowManagerDeviceTestCases模块的testShowWhenLockedImeActivityAndShowSoftInput测试fail项解决方法(代码片段