• Python-logging模块


    1、日志级别:

      

      日志级别指的是产生日志的事件的严重程度;

      设置一个级别后,严重程度低于设置值的日志消息将被忽略 。

    2、格式字符串 

      

      注意:funcName,threadName,processName 都是小驼峰命名

    2、默认级别: 

    1 import logging
    2 
    3 FORMAT = '%(asctime)-15s	 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	 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	 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	 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	 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.7python.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.7python.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.7python.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:	ets.log (WARNING)>]
     8 ==================================================
     9 h2 [<FileHandler f:	ets.log (WARNING)>]
    10 ==================================================
    11 20
    12 h3 [<FileHandler f:	ets.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.7python.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:	ets.log (WARNING)>, formatter =  None
    h1 [<FileHandler f:	ets.log (WARNING)>]
    ==================================================
    log2 formatter None
    log2 formatter <logging.Formatter object at 0x0000000002A09128>
    h2 [<FileHandler f:	ets.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

      

      

    为什么要坚持,想一想当初!
  • 相关阅读:
    为什么qt成为c++界面编程的第一选择 老夏课堂
    升级 package.json 内所有包的版本号
    小米 pro 双硬盘设置引导盘
    react 疑问集锦
    jmeter 基础使用
    vmware ubuntu 看不到网卡或连接不到网络
    如何在 Windows 11 使用旧的(或完整的)右键菜单
    hbuilder x 连接夜神模拟器
    当初为什么报 软件工程 这个专业?
    sparky 一个趋势图的JavaScript插件
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9877028.html
Copyright © 2020-2023  润新知