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('s.s1')
39 log2.setLevel(logging.DEBUG)
40 h2 = logging.FileHandler('f:/tets.log')
41 h2.setLevel(logging.WARNING)
42 
43 print('log2 formatter', h2.formatter)
44 f2 = logging.Formatter('log2 %(name)s %(asctime)s %(message)s')
45 h2.setFormatter(f2)
46 log2.addHandler(h2)
47 log2.info('log2----')
48 print('log2 formatter', h2.formatter)
49 print('h2', log2.handlers)
log2设置了formatter,没有设置 返回None

 

D:\python3.7\python.exe E:/code_pycharm/tt2.py
root [<StreamHandler <stderr> (NOTSET)>]
root [<StreamHandler <stderr> (NOTSET)>, <StreamHandler <stderr> (WARNING)>]
root handler = <StreamHandler <stderr> (NOTSET)>, formatter =  <logging.Formatter object at 0x0000000001D773C8>
root handler = <StreamHandler <stderr> (WARNING)>, formatter =  None
==================================================
h1 handler = <FileHandler f:\tets.log (WARNING)>, formatter =  None
h1 [<FileHandler f:\tets.log (WARNING)>]
==================================================
log2 formatter None
log2 formatter <logging.Formatter object at 0x0000000002A09128>
h2 [<FileHandler f:\tets.log (WARNING)>]
2018-10-30 17:14:11,489 s.s1 log2----

Process finished with exit code 0

 

    如何设置格式:

 1 log2 = logging.getLogger('s.s1')
 2 log2.setLevel(logging.DEBUG)
 3 h2 = logging.FileHandler('f:/tets.log')
 4 h2.setLevel(logging.WARNING)
 5 
 6 print('log2 formatter', h2.formatter)
 7 f2 = logging.Formatter('log2 %(name)s %(asctime)s %(message)s')
 8 h2.setFormatter(f2)
 9 log2.addHandler(h2)
10 log2.info('log2----')
11 print('log2 formatter', h2.formatter)
12 print('h2', log2.handlers)

 

     

12、Filter 过滤

  可以为handler增加过滤器,所以这种过滤器只影响某一个handler, 不会影响整个处理流程,但是,如果过滤器增加到logger上,就会影响流程。

  

 1 import logging
 2 
 3 FORMAT = '%(asctime)s %(name)s %(message)s'
 4 logging.basicConfig(format=FORMAT, level=logging.INFO)
 5 
 6 log1 = logging.getLogger('s')
 7 log1.setLevel(30)
 8 
 9 # h1 = logging.FileHandler('f:/0.log', 'w')
10 h1 = logging.StreamHandler()
11 h1.setLevel(logging.INFO)
12 
13 fmt1 = logging.Formatter('------log1 - h1 %(message)s')
14 h1.setFormatter(fmt1)
15 log1.addHandler(h1)
16 
17 ############# log 2 #########
18 log2 = logging.getLogger('s.s1')
19 print(log2.getEffectiveLevel())
20 
21 h2 = logging.StreamHandler()
22 h2.setLevel(logging.INFO)
23 
24 fmt2 = logging.Formatter('log2 -h2 %(message)s')
25 h2.setFormatter(fmt2)
26 
27 f2 = logging.Filter('p')
28 h2.addFilter(f2)
29 
30 log2.addHandler(h2)
31 
32 log2.warning('-----log2 warning')
测试
------log1 - h1 -----log2 warning
2018-10-30 17:53:22,143 s.s1 -----log2 warning
30

 

 

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

posted @ 2018-10-30 18:07  JerryZao  阅读(281)  评论(0编辑  收藏  举报