• Python的logging模块详解


                Python的logging模块详解

                           作者:尹正杰 

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

    一.日志级别

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

    常见的日志级别及其对应的数值如下所示:
      CRITICAL:
        对应数值为50,使用critical()方法调用。
      ERROR:
        对应数值为40,使用error()方法调用
      WARNING:
        对应数值为30,使用warning()方法调用,该级别为默认级别。
      INFO:
        对应数值为20,使用info()方法调用。
      DEBUG:
        对应数值为0,使用debug()方法调用。
      NOTSET:
        对应数值为0。

    二.字符串格式化

    %(message)s:
      日志消息内容。
      The logged message,computed as msg % args.当调用Formatter.format()时设置。
    %(asctime)s:   actime。
      创建LogRecord时的可读时间。默认情况下,它的格式为'2003-08-08 16:49:45,896'(逗号后面的数字是毫秒部分的时间)
    %(funcName)s:
      函数名。
      日志调用所在的函数名。

    %(levelname)s:
      日志级别名称。
      消息的级别名称:'DEBUG','INFO','WARNING','ERROR','CRITICAL'。

    %(levelno)s:
      日记级别数值。
      消息的级别数字:对应DEBUG,INFO,WARNING,ERROR,CRITICAL。

    %(lineno)s:
      行号。
      日志调用所在的源码行号。

    %(module)s:
      模块。
      模块(filename的名字部分)。

    %(process)d:
      进程ID。

    %(thread)d:
      线程ID。

    %(processName)s:
      进程名称。

    %(threadName)s:
      线程名称。

    %(name)s:
      logger名称。

    三.实战案例

    1>.默认级别

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = '%(asctime)-15s	Thread info: %(thread)d %(threadName)s %(message)s'
     9 logging.basicConfig(format=FORMAT)
    10 
    11 logging.info("I am {} years old !".format(20))          #info不显示
    12 logging.warning("I am {} years old !".format(26))       #warning为默认级别
    13 
    14 
    15 
    16 #以上代码执行结果如下:
    17 2019-11-20 11:02:44,759    Thread info: 17076 MainThread I am 26 years old !

    2>.指定日志级别

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = '%(asctime)-15s	Thread info: %(thread)d %(threadName)s %(message)s'
     9 logging.basicConfig(format=FORMAT,level=logging.INFO)       #指定日志级别为INFO级别,即只要日志级别大于或等于INFO级别的消息都会被打印哟。
    10 
    11 logging.info("I am {} years old !".format(20))              #单一字符串,python推荐使用这种格式化字符串
    12 logging.warning("I am %d %s",26,"years old")                #C风格格式化
    13 
    14 
    15 
    16 #以上代码执行结果如下:
    17 2019-11-20 11:13:30,202    Thread info: 17144 MainThread I am 20 years old !
    18 2019-11-20 11:13:30,202    Thread info: 17144 MainThread I am 26 years old

    3>.日志级别和格式化字符串扩展

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = '%(asctime)-15s	Thread info: %(thread)d %(threadName)s %(message)s %(school)s'
     9 logging.basicConfig(format=FORMAT,level=logging.INFO)       #指定日志级别为INFO级别,即只要日志级别大于或等于INFO级别的消息都会被打印哟。
    10 
    11 d = {"school":"哈佛大学"}
    12 logging.info("I am {} 毕业于 ".format(20),extra = d)              #单一字符串,python推荐使用这种格式化字符串
    13 logging.warning("I am %d 毕业于 %s",26,"years old",extra = d)                #C风格格式化
    14 
    15 
    16 
    17 #以上代码执行结果如下:
    18 2019-11-20 11:19:02,328    Thread info: 4960 MainThread I am 20 毕业于  哈佛大学
    19 2019-11-20 11:19:02,328    Thread info: 4960 MainThread I am 26 毕业于 years old 哈佛大学

    4>.修改日期格式

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = '%(asctime)s  %(message)s '
     9 
    10 logging.basicConfig(format=FORMAT,datefmt = "%Y/%m/%d %I:%M:%S")
    11 
    12 logging.warning("This event was logged.")
    13 
    14 
    15 
    16 #以上代码执行结果如下:
    17 2019/11/20 11:22:24  This event was logged. 

    5>.输出到文件

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = '%(asctime)s  %(message)s '
     9 
    10 logging.basicConfig(format=FORMAT,filename="test.log",filemode="w")            #filename设置日志文件,filemode设置读写模式
    11 
    12 for _ in range(10):
    13     logging.warning("This event was logged."

     

    四.Logger类

    1>.构造logger方法

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 a = logging.Logger("hello",20)          #Logger实例的构建,使用Logger类也行,但推荐使用getLogger函数。但Logger类可以指定Logger初始的日志级别。
     9 b = logging.Logger("hello",30)
    10 print(a,id(a))
    11 print(b,id(b))
    12 print(a is b)
    13 
    14 m = logging.getLogger("hello")          #使用工厂方法返回一个Logger实例,指定name,返回一个名称为name的Logger实例。如果再次使用相同的名字,返回同一个实例。背后使用一个字典保证同一个名称返回同一个实例。
    15 n = logging.getLogger("hello")          #
    16 print(m,id(m))
    17 print(n,id(n))
    18 print(m is n)
    19 
    20 s = logging.getLogger()                 #未指定name,返回根Logger实例(logging模块加载的时候,会创建一个全局对象root,它是一个RootLogger实例,即root logger,根logger对象的默认级别是WARNING。调用logging.basicConfig来重新调整级别,就是对这个根Logger的级别进行修改)。
    21 print(s,id(s))
    <Logger hello (INFO)> 2281796100296
    <Logger hello (WARNING)> 2281796100360
    False
    <Logger hello (WARNING)> 2281796104072
    <Logger hello (WARNING)> 2281796104072
    True
    <RootLogger root (WARNING)> 2281798333384
    以上代码执行结果戳这里

    2>.层次结构

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 root = logging.root         #logging模块加载的时候,会创建一个全局对象root logger,它是一个RootLogger实例,即root logger。根logger对象的默认级别是WARNING。
     9 print(root,id(root))
    10 
    11 root = logging.getLogger()                                           #未指定name,返回 root logger
    12 print(root.name,type(root),root.parent)                              #root logger没有父
    13 
    14 parent = logging.getLogger(__name__)                                 #模块级别logger
    15 print(parent.name,type(parent),id(parent.parent),id(parent))
    16 
    17 child = logging.getLogger("{} {}".format(__name__,".child"))         #是root logger的子logger
    18 print(child.name,type(child),id(child.parent),id(child))
    <RootLogger root (WARNING)> 2037677233288
    root <class 'logging.RootLogger'> None
    __main__ <class 'logging.Logger'> 2037677233288 2037675028616
    __main__ .child <class 'logging.Logger'> 2037677233288 2037675028680
    以上代码执行结果戳这里

    3>.level级别设置

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = "%(asctime)-15s	Thread info: %(thread)d %(threadName)s [%(message)s]"
     9 logging.basicConfig(format=FORMAT,level=logging.INFO)
    10 
    11 log = logging.getLogger(__name__)                 #构建一个logger实例对象log。
    12 print(log.name,type(log),log.level)               
    13 log.info("1 info")
    14 print(log.getEffectiveLevel())                    #查看等效level,每一个logger实例,都有一个等效的level(决定着logger实例能输出什么级别的信息)。
    15 
    16 log.setLevel(27)                                  #logger对象在创建后可以动态修改自己的等效level,推荐使用setLevel方法修改logger的级别
    17 print(log.getEffectiveLevel(),log.level)
    18 log.info("2 info")
    19 
    20 log.setLevel(45)                                    #我们将log的等效level的值设置未45,明显高于WARNING(默认等效数字30)和ERROR(默认等效数字40)的级别
    21 print(log.getEffectiveLevel(),log.level)
    22 log.warning("3 warning")
    23 log.error("4 error")
    24 log.critical("5 critical")
    25 
    26 
    27 root = logging.getLogger()
    28 print(root.getEffectiveLevel(),root.level)          #上面2次修改了logger对象log的等效level,但均不会影响根logger对象root,因为这是2个不同的logger对象哟。
    29 root.info("6 root info")
    2019-11-20 18:27:55,829    Thread info: 16140 MainThread [1 info]
    2019-11-20 18:27:55,829    Thread info: 16140 MainThread [5 critical]
    2019-11-20 18:27:55,829    Thread info: 16140 MainThread [6 root info]
    __main__ <class 'logging.Logger'> 0
    20
    27 27
    45 45
    20 20
    以上代码执行结果戳这里

     

    五.Handler类

    1>.什么是Handler

      Handler控制日志信息的输出目的地,可以是控制台,文件。
        
      Handler可以单独设置level
      Handler可以单独设置格式
      Handler可以单独设置过滤器
      每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
        logging.StreamHandler
          使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:StreamHandler([strm]),其中strm参数是一个文件对象。默认是sys.stderr
        logging.FileHandler
          和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:FileHandler(filename[,mode]),filename是文件名,必须指定一个文件名。mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。
        logging.handlers.RotatingFileHandler
          这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]]),其中filename和mode两个参数和FileHandler一样。maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
        logging.handlers.TimedRotatingFileHandler
          这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]]),其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义,interval是时间间隔。when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:(S[秒],M[分],H[小时],D[天],W[每星期(interval==0时代表星期一)],midnight[每天凌晨]
    每个Logger可以附加多个Handler。戳这里查看详情

    2>.Handler类层次

      日志输出其实就是Handler做的,也就是真正干活的是Handler。

      Handler:
        StreamHandler:     #不指定使用sys.stderr
          FileHandler     #文件类型的handler
          _StderrHandler   #标准输出
        NullHandler       #什么都不做。

      如果设置文件名,则为根Logger加一个输出到文件的FileHandler;如果没有设置文件名,则为根Logger加一个StreamHandler,默认输出到sys.stderr,也就是说,根logger一定会至少有一个handler的。

      在logging.basicConfig函数中,如下图所示:

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = "%(asctime)-15s	Thread info: %(thread)d %(threadName)s [%(message)s]"
     9 logging.basicConfig(format=FORMAT,level=logging.WARNING)   #为root Logger设置level
    10 
    11 log = logging.getLogger("test")                            #创建一个Logger实例
    12 print(log.name,log.getEffectiveLevel(),type(log),log.level)
    13 
    14 log.warning("line 1")
    15 
    16 handler = logging.FileHandler("test.log","w")           #创建一个FileHandler对象
    17 log.addHandler(handler)                                 #给Logger对象log绑定咱们刚刚创建的handler
    18 print(handler.get_name,handler.level)                   #创建的Handler的初始level为NOTSET(即为0)。
    19 
    20 log.debug("line 2")
    21 log.info("line 3")
    22 log.warning("line 4")
    23 
    24 handler.setLevel(45)                                    #注意,我们将handler的级别调制到45之前,发行了上面3行消息,handler的级别过了之后,会继续交给root logger来进行级别过滤,由于root logger的级别为WARNING,因此上面的三条信息并不会都被写入文件,仅有WARNING级别会被写入哟。
    25 print(handler.get_name,handler.level)
    26 log.debug("line 5")
    27 log.info("line 6")
    28 log.warning("line 7")
    29 log.error("line 8")
    30 log.critical("line 9")                                  #修改handler级别为45后,只有这一条消息可以从handler放行
    31 
    32 
    33 root = logging.root
    34 print(root.getEffectiveLevel(),root.level)
    35 print(root.name,root.getEffectiveLevel(),type(root),root.level)
    2019-11-20 19:15:39,562    Thread info: 15076 MainThread [line 1]
    2019-11-20 19:15:39,563    Thread info: 15076 MainThread [line 4]
    2019-11-20 19:15:39,563    Thread info: 15076 MainThread [line 7]
    2019-11-20 19:15:39,563    Thread info: 15076 MainThread [line 8]
    2019-11-20 19:15:39,563    Thread info: 15076 MainThread [line 9]
    test 30 <class 'logging.Logger'> 0
    <bound method Handler.get_name of <FileHandler D:LanguagePythonCodeDevopsPython基础8.模块化	est.log (NOTSET)>> 0
    <bound method Handler.get_name of <FileHandler D:LanguagePythonCodeDevopsPython基础8.模块化	est.log (Level 45)>> 45
    30 30
    root 30 <class 'logging.RootLogger'> 30
    以上代码执行结果戳这里
    line 4
    line 9
    test.log文件内容戳这里

    3>.level的继承

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging
     7 
     8 FORMAT = "%(asctime)-15s	Thread info: %(name)s %(levelname)s %(levelno)s   [%(message)s]"
     9 logging.basicConfig(format=FORMAT,level=logging.WARNING)   #为root Logger设置level
    10 
    11 log1 = logging.getLogger("a")
    12 log2 = logging.getLogger("a.b")
    13 
    14 log1.info("1 info")
    15 log2.info("2 info")
    16 
    17 print(log1.level,log1.getEffectiveLevel())      #如果不设置level,则初始level为0
    18 print(log2.level,log2.getEffectiveLevel())
    19 
    20 
    21 print("{0} 我是分割线 {0}".format("*" * 15))
    22 
    23 log1.setLevel(35)                               #如果设置了就优先使用自己的level,否则继承最近的祖先level
    24 log1.info("3 info")
    25 log2.info("4 info")
    26 print(log1.level,log2.getEffectiveLevel())
    27 print(log2.level,log2.getEffectiveLevel())
    28 
    29 print("{0} 我是分割线 {0}".format("*" * 15))
    30 
    31 log2.setLevel(20)                               #消息是否能从该logger实例上输出,就是要看当前的level是否大于等于logger的有效level,否则输出不了。
    32 log1.info("5 info")
    33 log2.info("6 info")
    34 log1.warning("7 warning")
    35 log2.warning("8 warning")
    36 log1.error("9 error")
    37 log2.error("10 error")
    38 print(log1.level,log2.getEffectiveLevel())
    39 print(log2.level,log2.getEffectiveLevel())
    2019-11-20 19:40:47,472    Thread info: a.b INFO 20   [6 info]
    2019-11-20 19:40:47,472    Thread info: a.b WARNING 30   [8 warning]
    2019-11-20 19:40:47,472    Thread info: a ERROR 40   [9 error]
    2019-11-20 19:40:47,472    Thread info: a.b ERROR 40   [10 error]
    0 30
    0 30
    *************** 我是分割线 ***************
    35 35
    0 35
    *************** 我是分割线 ***************
    35 20
    20 20
    以上代码执行结果戳这里

    4>.继承关系及信息传递

    每一个Logger实例的level如同入口,让水流尽力啊,如果这个门槛太高,信息就进不来。例如log.info("1 info"),如果定义log定义的级别高,就不会有信息通过log。
    
    如果level没有设置,就用夫logger的,如果父logger的level没有设置,继续找父的父的。最终可以找到root上,如果root设置了就调用它的,如果root没有设置,root的默认值是WARNING。
    
    消息传递流程如下:
      (1)如果消息在某一个logger对象产生,这个logger就是当前logger,首先消息level要和当前logger的EffectiveLevel比较,如果低于当前logger的EffectiveLevel,则流程结束,否则生成log记录。
      (2)日志记录会交给当前logger的所有handler处理,记录还要和每一个handler的级别分别比较,低的不处理,否则按照handler输出日志记录。
      (3)当前logger的所有handler处理完后,就要看自己的propagete属性,如果是True表示向父logger传递在这个日志记录,否则到此流程结束。
      (4)如果日志记录到了父logger,不需要和父logger的level比较,而是直接交给父的所有handler,父logger成为当前logger。重复2,3步骤,知道当前logger的父logger是None退出,也就是说当前logger最后一般是root logger(是否能到root logger要看中间的logger是否允许propagate)

    logger实例初始的propagate属性为True,即允许向父logger传递消息。

    logger.basicConfig函数说明:
      如果root没有handler,就默认创建一个StreamHandler,如果设置了filename,就创建一个FileHandler。如果设置了format参数,就会用它生成一个Format对象,否则会生成缺省Formatter,并把这个formatter加入到刚才创建的handler上,然后把这些handler加入到root.handlers列表上。level是设置给root logger的。
      如果root.handlers列表不为空,logging.basicConfig的调用什么都不做。

    官方日志流转图如下所示。

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import sys
     7 import logging
     8 
     9 FORMAT = "%(asctime)-15s	Thread info: %(name)s %(levelname)s %(levelno)s   [%(message)s]"
    10 logging.basicConfig(format=FORMAT,level=logging.WARNING)   #为root Logger设置level
    11 
    12 #根logger的操作
    13 root = logging.getLogger()
    14 root.setLevel(logging.ERROR)
    15 print(root.name,root.handlers,root.level)
    16 
    17 #增加handler
    18 h1 = logging.StreamHandler(sys.stdout)
    19 h1.setLevel(logging.WARNING)
    20 root.addHandler(h1)
    21 print(root.name,root.handlers)
    22 for h in root.handlers:
    23     print("root handler = {}, formatter = {}".format(h,h.formatter._fmt if h.formatter else " "))
    24 logging.warning("1 root warning")
    25 logging.error("2 root error")
    26 
    27 
    28 print("{0} 我是分割线 {0}".format("*" * 15))
    29 
    30 #logger a
    31 log1 = logging.getLogger("a")
    32 log1.setLevel(logging.ERROR)
    33 h1 = logging.FileHandler(filename="test.log")
    34 h1.setLevel(logging.WARNING)
    35 log1.addHandler(h1)
    36 log1.warning("3 a warning")
    37 log1.error("4 a error")
    38 print(log1.name,log1.handlers,log1.level)
    39 
    40 print("{0} 我是分割线 {0}".format("*" * 15))
    41 
    42 
    43 #logger a.b
    44 log2 = logging.getLogger("a.b")
    45 log2.setLevel(logging.CRITICAL)
    46 h2 = logging.FileHandler("test2.log")
    47 h2.setLevel(logging.WARNING)
    48 log2.addHandler(h2)
    49 log2.warning("5 a.b warning")
    50 log2.error("6 a.b error")
    51 log2.critical("7 a.b critical")
    52 print(log2.name,log2.handlers,log2.level)
    53 
    54 print("{0} 我是分割线 {0}".format("*" * 15))
    55 
    56 #logger a.b.c
    57 log3 = logging.getLogger("a.b.c")
    58 log3.setLevel(logging.DEBUG)                 #级别最低
    59 print(log3.getEffectiveLevel())              #查看等效级别
    60 log3.debug("8 a.b.c debug")
    61 log3.info("9 a.b.c info")
    62 log3.warning("10 a.b.c warning")
    63 log3.error("11 a.b.c error")
    64 log3.critical("12 a.b.c critical")
    65 print(log3.name,log3.handlers,log3.level)
    2019-11-20 20:33:27,304    Thread info: root ERROR 40   [2 root error]
    2019-11-20 20:33:27,305    Thread info: a ERROR 40   [4 a error]
    2019-11-20 20:33:27,305    Thread info: a.b CRITICAL 50   [7 a.b critical]
    2019-11-20 20:33:27,305    Thread info: a.b.c DEBUG 10   [8 a.b.c debug]
    2019-11-20 20:33:27,305    Thread info: a.b.c INFO 20   [9 a.b.c info]
    2019-11-20 20:33:27,305    Thread info: a.b.c WARNING 30   [10 a.b.c warning]
    root [<StreamHandler <stderr> (NOTSET)>] 40
    2019-11-20 20:33:27,305    Thread info: a.b.c ERROR 40   [11 a.b.c error]
    root [<StreamHandler <stderr> (NOTSET)>, <StreamHandler <stdout> (WARNING)>]
    2019-11-20 20:33:27,305    Thread info: a.b.c CRITICAL 50   [12 a.b.c critical]
    root handler = <StreamHandler <stderr> (NOTSET)>, formatter = %(asctime)-15s    Thread info: %(name)s %(levelname)s %(levelno)s   [%(message)s]
    root handler = <StreamHandler <stdout> (WARNING)>, formatter =  
    2 root error
    *************** 我是分割线 ***************
    4 a error
    a [<FileHandler D:LanguagePythonCodeDevopsPython基础8.模块化	est.log (WARNING)>] 40
    *************** 我是分割线 ***************
    7 a.b critical
    a.b [<FileHandler D:LanguagePythonCodeDevopsPython基础8.模块化	est2.log (WARNING)>] 50
    *************** 我是分割线 ***************
    10
    10 a.b.c warning
    11 a.b.c error
    12 a.b.c critical
    a.b.c [] 10
    以上代码执行结果戳这里
    4 a error
    7 a.b critical
    10 a.b.c warning
    11 a.b.c error
    12 a.b.c critical
    test.log文件内容戳这里
    7 a.b critical
    10 a.b.c warning
    11 a.b.c error
    12 a.b.c critical
    test2.log文件内容戳这里

    六.Formatter类

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import sys
     7 import logging
     8 
     9 FORMAT = "%(asctime)-15s	Thread info: %(name)s %(levelname)s %(levelno)s   [%(message)s]"
    10 logging.basicConfig(format=FORMAT,level=logging.DEBUG)        #为root Logger设置level
    11 
    12 #根logger的操作
    13 root = logging.root             #等效于"root = logging.getLogger()",因为未指定name,返回根Logger实例。
    14 print(root.name,root.handlers,root.level)
    15 
    16 
    17 h1 = logging.StreamHandler(sys.stdout)
    18 root.addHandler(h1)             #为root Logger对象增加handler属性
    19 h1.setLevel(logging.ERROR)
    20 print(root.name,root.handlers)
    21 for h in root.handlers:
    22     print("root handler = {}, formatter = {}".format(h,h.formatter._fmt if h.formatter else " "))
    23 print(h1.level,root.level)
    24 logging.debug("1 root debug")
    25 logging.info("2 root info")
    26 logging.warning("3 root warning")
    27 logging.error("4 root error")
    28 logging.critical("6 root critical")
    29 
    30 """
    31     logging的Format类,它允许指定某个格式的字符串。如果提供None,那么"%(message)s"将会作为默认值。
    32 """
    33 fmt1 = logging.Formatter("{0} %(message)s {0}".format("*" * 15))
    34 h1.setFormatter(fmt1)               #为h1增加一个Formatter
    35 print(h1.level,root.level)
    36 logging.debug("7 root debug")
    37 logging.info("8 root info")
    38 logging.warning("9 root warning")
    39 logging.error("10 root error")
    40 logging.critical("11 root critical")
    2019-11-20 21:01:58,730    Thread info: root DEBUG 10   [1 root debug]
    2019-11-20 21:01:58,730    Thread info: root INFO 20   [2 root info]
    2019-11-20 21:01:58,730    Thread info: root WARNING 30   [3 root warning]
    2019-11-20 21:01:58,730    Thread info: root ERROR 40   [4 root error]
    2019-11-20 21:01:58,730    Thread info: root CRITICAL 50   [6 root critical]
    2019-11-20 21:01:58,730    Thread info: root DEBUG 10   [7 root debug]
    2019-11-20 21:01:58,730    Thread info: root INFO 20   [8 root info]
    2019-11-20 21:01:58,730    Thread info: root WARNING 30   [9 root warning]
    2019-11-20 21:01:58,730    Thread info: root ERROR 40   [10 root error]
    2019-11-20 21:01:58,730    Thread info: root CRITICAL 50   [11 root critical]
    root [<StreamHandler <stderr> (NOTSET)>] 10
    root [<StreamHandler <stderr> (NOTSET)>, <StreamHandler <stdout> (ERROR)>]
    root handler = <StreamHandler <stderr> (NOTSET)>, formatter = %(asctime)-15s    Thread info: %(name)s %(levelname)s %(levelno)s   [%(message)s]
    root handler = <StreamHandler <stdout> (ERROR)>, formatter =  
    40 10
    4 root error
    6 root critical
    40 10
    *************** 10 root error ***************
    *************** 11 root critical ***************
    以上代码执行结果戳这里

    七.Filter类

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import logging,sys
     7 logging.basicConfig(level=logging.INFO, format="%(asctime)s %(name)-10s [%(message)s]")
     8 
     9 # logger a
    10 log1 = logging.getLogger('a')
    11 log1.setLevel(logging.WARNING)
    12 h1 = logging.StreamHandler(sys.stderr)
    13 h1.setLevel(logging.INFO)
    14 f1 = logging.Formatter('log1-h1 %(message)s')
    15 h1.setFormatter(f1)
    16 log1.addHandler(h1)
    17 log1.info("1 log1 info")
    18 log1.warning("2 log1 warning")
    19 
    20 # logger a.b
    21 log2 = logging.getLogger('a.b')
    22 #log2.setLevel(logging.CRITICAL)
    23 print(log2.getEffectiveLevel())                 #继承父logger,就是a的level
    24 h2 = logging.StreamHandler(sys.stdout)
    25 h2.setLevel(logging.INFO)
    26 f2 = logging.Formatter('log2-h2 %(message)s')
    27 h2.setFormatter(f2)
    28 
    29 """
    30 Filter分为2种:
    31     可以为handler增加过滤器,所以在这种过滤器只影响某一个handler,不会影响整个处理流程。
    32     如果过滤器增加到logger上,就会影响流程.
    33 """
    34 filter = logging.Filter("a.b")                  #过滤器,这个过滤器匹配的是logger的名称(匹配方式相当于字符串的"startswith"方法),只有logger的名称和filter.name匹配才能放行,否则拦截
    35 h2.addFilter(filter)                            #h2上增加了该过滤器
    36 print(filter.name, filter.nlen,)                #名字"a.b"名字长度为3
    37 log2.addHandler(h2)
    38 log2.info("3 log 2 info string~~~~~")
    39 log2.warning('4 log2 warning string~~~~~')
    40 log2.error('5 log2 error string~~~~~')
    41 
    42 # logger a.b.c
    43 log3 = logging.getLogger('a.b.c')
    44 print(log3.name, log3.getEffectiveLevel())
    45 log3.warning('6 log3 test warning =====')
    46 log3.error('7 log3 test error ======')
    47 
    48 log4 = logging.getLogger("d")                   #注意,这里的"d"logger对象和"a","a.b","a.b.c"这三个logger对象并不是父子关系,他的父是root logger,由于log4对象没有handler,只能继续向root传递。
    49 log4.warning("8 log4 waring string ******")
    30
    a.b 3
    log2-h2 4 log2 warning string~~~~~
    log2-h2 5 log2 error string~~~~~
    a.b.c 30
    log2-h2 6 log3 test warning =====
    log2-h2 7 log3 test error ======
    log1-h1 2 log1 warning
    2019-11-22 18:12:56,534 a          [2 log1 warning]
    log1-h1 4 log2 warning string~~~~~
    2019-11-22 18:12:56,535 a.b        [4 log2 warning string~~~~~]
    log1-h1 5 log2 error string~~~~~
    2019-11-22 18:12:56,535 a.b        [5 log2 error string~~~~~]
    log1-h1 6 log3 test warning =====
    2019-11-22 18:12:56,535 a.b.c      [6 log3 test warning =====]
    log1-h1 7 log3 test error ======
    2019-11-22 18:12:56,535 a.b.c      [7 log3 test error ======]
    2019-11-22 18:12:56,535 d          [8 log4 waring string ******]
    以上代码执行结果戳这里

    八.按照时间自动截断并保存指定文件个数的案例

     1 #!/usr/bin/env python
     2 #_*_coding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/
     5 #EMAIL:y1053419035@qq.com
     6 
     7 import logging
     8 
     9 from logging import handlers
    10 
    11 logger = logging.getLogger(__name__)
    12 
    13 log_file = "timelog.log"
    14 
    15 #fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
    16 
    17 fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3) #filename定义将信息输入到指定的文件,
    18 # when指定单位是s(秒),interval是时间间隔的频率,单位是when所指定的哟(所以,你可以理解频率是5s);backupCount表示备份的文件个数,我这里是指定的3个文件。
    19 
    20 formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')  #定义输出格式
    21 
    22 fh.setFormatter(formatter) #添加格式化输出
    23 logger.addHandler(fh)
    24 
    25 logger.warning("test1")
    26 logger.warning("test2")
    27 logger.warning("test3")
    28 logger.warning("test4")

    随着调用以上脚本的次数的增加,可能会出现以下的现象:

  • 相关阅读:
    一个白痴用户,抵得上一个3年经验的产品经理!
    Android 实现页面跳转并传递参数教程
    Android 学习笔记
    Android开发中,比较有特色的特性(与iOS相比)
    Android 中的概念大集合
    Eclipse自动补全功能轻松设置 || 不需要修改编辑任何文件
    Eclipse 常用快捷键
    android多设备界面适配的利器:属性weight的妙用
    Android 和 iOS 应用程序开发对比 [持续更新]
    eclipse 大括号 改为C语言风格
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/11823569.html
Copyright © 2020-2023  润新知