zoukankan      html  css  js  c++  java
  • Python中logging模块

    1、日志级别

    日志级别

    数值

    Critical

    50

    Error

    40

    Warning

    30

    Info

    20

    Debug

    10

    Notset

    0

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

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

    Debug(),info(),warning(),error(),critical()方法;

    2、格式字符串

    属性

    格式

    描述

    日志消息内容

    %(message)s

    The logged message,computed as msg %args,当调用 formatter.format()时候会被调用

    Asctime

    %(asctime)s

    创建logrecord的可读时间,默认情况下,格式为2003-07-08 00:00:00,000(逗号后面的数字是毫秒部分的时间)

    函数名

    %(funcname)s

    日志调用所在的函数名

    日志级别名称

    %(levelname)s

    消息的级别名称‘debug,info,warning,error,critical’

    日志级别数值

    %(levelno)s

    消息的级别数字,debug,info,warning,error,critical

    行号

    %(lineno)s

    日志调用所在的源码行号

    模块

    %(module)s

    模块(费了那么的名字部分)

    进程ID

    %(process)s

    进程ID

    线程ID

    %(thread)d

    线程ID

    进程名

    %(processname)s

    进程名

    线程名

    %(threadname)s

    线程名称

    funName、threadName、processName都是小驼峰。

    import logging

    FORMAT = '%(asctime)-15s Thread info:%(thread)d %(threadName)s %(message)s'
    logging.basicConfig(format=FORMAT)

    logging.info('{}'.format(20))  #info不显示
    logging.warning('{}'.format(20)) #默认级别的

    2018-06-13 11:01:56,992         Thread info:420 MainThread 20

    上栗info不显示的原因是因为logging.basicConfig(format=FORMAT)  后面的默认值level的值是logging.WARNING 低于此级别的不进行显示处理。

    改造以后

    import logging

    FORMAT = '%(asctime)-15s Thread info:%(thread)d %(threadName)s %(message)s'
    logging.basicConfig(format=FORMAT,level=logging.DEBUG)


    logging.info('1{}'.format(0))  #info不显示
    logging.warning('2{}'.format(0)) #默认级别的
    logging.debug('3{}'.format(0))
    logging.error('4{}'.format(0))
    logging.critical('5{}'.format(0))

    2018-06-13 11:39:28,053         Thread info:6212 MainThread 10

    2018-06-13 11:39:28,053         Thread info:6212 MainThread 20

    2018-06-13 11:39:28,053         Thread info:6212 MainThread 30

    2018-06-13 11:39:28,053         Thread info:6212 MainThread 40

    2018-06-13 11:39:28,053         Thread info:6212 MainThread 50

    格式化字符串是需要定义的。Schools自定义的。打印输出的时候利用extra显示定义的新定义的消息等。

    import logging

    FORMAT = '%(asctime)-15s Thread info:%(thread)d %(threadName)s %(message)s %(school)s'
    logging.basicConfig(format=FORMAT,level=logging.INFO)


    d = {'school':'baidu.com'}
    logging.info('i am %s %s',20,'years old.',extra = d)
    logging.warning('i am %s %s',20,'years old.',extra = d)

    2018-06-13 14:57:40,631         Thread info:8908 MainThread i am 20 years old. baidu.com

    2018-06-13 14:57:40,631         Thread info:8908 MainThread i am 20 years old. baidu.com

    3、修改日期格式

    import logging

    logging.basicConfig(format='%(asctime)s %(message)s',datefmt='%Y/%m/%d %I:%M:%S')
    logging.warning('this event was logged')

    2018/06/13 03:04:38 this event was logged

    可以自己定义时间的格式,利用datefmt=新的时间格式即可以。

    4、输出到文件

    import logging
    logging.basicConfig(format='%(asctime)s %(message)s',filename='test1.log')
    for _ in range(5):
        logging.warning('this is event logged')

    还可以输出日志到文件,只是需要filename指定文件存放地址

    5、Logger类:

    Loggin模块加载的时候,会创建一个root logger,跟logger对象的默认级别是WARNING,调用logging.basicConfig来调整级别,就是对这个跟logger的级别进行修改。

    1)构造

    Logging.getlogger([name=None])

    使用工厂方法返回一个logger实例。

    指定name,返回一个名称为name的logger的实例,如果再次使用相同的名字,就是实例化一个对象,未指定none,返回根logger实例。

    2)层次结构

    Logger是层次结构的,使用.点号分割,如a,a.b或者a.b.c.d,a是a.d的父parent,a.b是a的子child,对于foo来说,名字为foo.bar/foo.bar.bar/foo.bam都是foo的后代。

    import logging

    root = logging.getLogger()
    print(root.name,type(root),root.parent,id(root))


    logger = logging.getLogger(__name__)
    print(logger.name,type(logger),id(logger.parent),id(logger))



    loggerchild = logging.getLogger(__name__+'.child')
    print(loggerchild.name,type(loggerchild),id(loggerchild.parent),id(loggerchild))

    root <class 'logging.RootLogger'> None 283120699768

    __main__ <class 'logging.Logger'> 283120699768 283118806968

    __main__.child <class 'logging.Logger'> 283118806968 283118808872

    3)level级别设置

    import logging

    FORMAT = '%(asctime)-15s Thread info:%(thread)d %(threadName)s %(message)s'
    logging.basicConfig(format=FORMAT,level=logging.DEBUG)

    logger = logging.getLogger(__name__)
    print(logger.name,type(logger))
    print(logger.getEffectiveLevel())

    logger.info('hello')
    logger.setLevel(28)

    print(logger.getEffectiveLevel())
    logger.info('hello2')
    logger.warning('hello3 warning')

    root = logging.getLogger()
    root.info('hello4 info root')

    2018-06-13 15:49:51,076         Thread info:8952 MainThread hello

    __main__ <class 'logging.Logger'>

    2018-06-13 15:49:51,076         Thread info:8952 MainThread hello3 warning

    10

    2018-06-13 15:49:51,076         Thread info:8952 MainThread hello4 info root

    28

    每一个logger创建后,都有一个等效的level。

    Logger对象可以在创建后动态的修改自己的level。

    不指定的话就是标准错误输出。

    6、handler

    Handler:主要工作的。

    Handler控制日志信息的输出的目的地,可以是控制台、文件。

    可以单独设置level   Handler都有独立的level。

    可以单独设置格式

    可以设置过滤器

    Handler类继承。

    Handler

    Streamhandler不指定使用sys.stderr

    filehandler文件

    _stderrhandler 标准输出

    Nullhandler 什么都不做

    输出打印全部靠的是handler,真正干活的也是handler。

    if handlers is None:
        filename = kwargs.pop("filename", None)
        mode = kwargs.pop("filemode", 'a')
        if filename:
            h = FileHandler(filename, mode)
        else:
            stream = kwargs.pop("stream", None)
            h = StreamHandler(stream)
        handlers = [h]

    如果设置文件名,则根logger加一个输出到文件handler;如果没有设置文件名,则为根logger加一个streamhandler,默认输出到sys.stderr

    也就是说,根logger一定会至少有一个handler。

    import logging


    FORMAT = '%(asctime)-15s Thread info:%(thread)d %(threadName)s %(message)s'
    logging.basicConfig(format=FORMAT,level=logging.DEBUG)


    logger = logging.getLogger('test')
    print(logger.name,type(logger))
    logging.info('line 1')

    handler = logging.FileHandler('ll.log','w')
    logger.addHandler(handler)

    logger.info('line 2')

    文件内的内容为line 2  控制台打印输出的内容为line1和line2,原因是因为设置的等级问题,没指定在控制台输出是因为继承的root的类,输出在控制台中。

    7、日志流

    Level的继承

    import logging

    FORMAT = '%(asctime)-15s Thread info:%(thread)d %(threadName)s %(message)s'
    logging.basicConfig(format=FORMAT,level=logging.INFO)
    root = logging.getLogger()

    log1 = logging.getLogger('s')
    log1.setLevel(logging.INFO)

    log2 = logging.getLogger('s.s1')
    log2.warning('log2 warning')

    2018-06-13 16:37:50,650         Thread info:8464 MainThread log2 warning

    logger实例,如果设置了level,就用它和信息的级别比较,否则,继承最近的祖先的level。

    继承关系及信息传递:

    每一个logger实例的level如同入口。让水流进来,如果门槛太高,信息就无法进入,例如log3.warning(‘log3’),如果log3定义的级别高,就不会有信息通过log3

    如果level没有设置,就用父logger的,如果父logger的level没有设置,继续找父的父,最终找到root上面,如果设置了就用他的,如果root没有设置,root的默认值是WARNING,

    消息传递流程:

    1)、如果消息在某个logger对象上产生,这个logger就是当前的logger,首先消息level要和当前的logger的effective比较,如果第一当前的logger的effectivelevel,则流程结束。

    2)、日志记录会交给当前logger的所有handler处理,记录还要和每一个handler的级别分别比较,低的不处理,否则按照handler输出日志记录。

    3)、当前logger的所有handler处理完后,就要看自己的propagate属性,如果是True表示向父logger传达这个日志,否则到此结束流程。

    4)、如果日志记录仪传递到了父logger,不需要和logger的level比较,而是直接交给父的所有handler,父logger成为当前的logger,重复2,3步骤,直到当前的父logger是None退出,也就是说当前logger最后一般是root logger(是否能到root logger更看中间的logger是否允许propagate)。

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

    Logger.basicConfig

    如果root没有handler,就默认创建一个streamhandler,如果设置了filename,就创建一个filehandler,如果设置了format参数,就会用它生成一个formatter对象,并把这个formatter加入到刚刚创建的handler上,然后把这些handler加入到root.handlers列表上,level是设置给root.logger的

    如果root.handlers 列表不能为空,loggingbasicConfig的调用什么都不做。

    import logging


    logging.basicConfig(format='%(name)s %(asctime)s %(message)s ',level=logging.INFO)


    root = logging.getLogger()
    root.setLevel(logging.ERROR)
    print('root',root.handlers)
    h0 = logging.StreamHandler()
    h0.setLevel(logging.WARNING)
    root.addHandler(h0)
    print('root',root.handlers)
    for h in root.handlers:
        print('root handler = {},formatter={}'.format(h,h.formatter))

    log1 = logging.getLogger('s')
    log1.setLevel(logging.ERROR)
    h1 = logging.FileHandler('h1.log')
    h1.setLevel(logging.WARNING)
    log1.addHandler(h1)
    print('log1',log1.handlers)


    log2 = logging.getLogger('s.s1')
    log2.setLevel(logging.CRITICAL)
    h2 = logging.FileHandler('h2.log')
    h2.setLevel(logging.WARNING)
    log2.addHandler(h2)
    print('log2',log2.handlers)

    log3 = logging.getLogger('s.s1.s2')
    log3.setLevel(logging.INFO)
    print(log3.getEffectiveLevel())
    log3.warning(log3)
    print('log3',log3.handlers)

    root [<logging.StreamHandler object at 0x00000088203E9748>]

    root [<logging.StreamHandler object at 0x00000088203E9748>, <logging.StreamHandler object at 0x00000088203FE5F8>]

    root handler = <logging.StreamHandler object at 0x00000088203E9748>,formatter=<logging.Formatter object at 0x00000088203E9780>

    root handler = <logging.StreamHandler object at 0x00000088203FE5F8>,formatter=None

    log1 [<logging.FileHandler object at 0x0000008820E2DDA0>]

    log2 [<logging.FileHandler object at 0x0000008820E2DF28>]

    20

    log3 []

    s.s1.s2 2018-06-13 17:17:43,695 <logging.Logger object at 0x0000008820E2DF60>

    <logging.Logger object at 0x0000008820E2DF60>

    8、Formatter

    Logging的formatter类,允许指定某个格式的字符串,如果提供None,name%(message)s将会作为默认值。

    import logging


    logging.basicConfig(format='%(name)s %(asctime)s %(message)s ',level=logging.INFO)


    root = logging.getLogger()
    root.setLevel(logging.ERROR)
    print('root',root.handlers)
    h0 = logging.StreamHandler()
    h0.setLevel(logging.WARNING)
    root.addHandler(h0)
    print('root',root.handlers)
    for h in root.handlers:
        print('root handler = {},formatter={}'.format(h,h.formatter))

    log1 = logging.getLogger('s')
    log1.setLevel(logging.ERROR)
    h1 = logging.FileHandler('h1.log')
    h1.setLevel(logging.WARNING)
    log1.addHandler(h1)
    print('log1',log1.handlers)


    log2 = logging.getLogger('s.s1')
    log2.setLevel(logging.CRITICAL)
    h2 = logging.FileHandler('h2.log')
    h2.setLevel(logging.WARNING)
    log2.addHandler(h2)
    print('log2',log2.handlers)
    f2 = logging.Formatter('log2 %(name)s %(asctime)s %(message)s')
    h2.setFormatter(f2)
    print('log2 formatter',h2.formatter)
    log2.addHandler(h2)
    print('log2',log2.handlers)

    log3 = logging.getLogger('s.s1.s2')
    log3.setLevel(logging.INFO)
    print(log3.getEffectiveLevel())
    log3.warning(log3)
    print('log3',log3.handlers)

    s.s1.s2 2018-06-13 17:24:13,392 <logging.Logger object at 0x00000033721EF208>

    root [<logging.StreamHandler object at 0x0000003372019780>]

    <logging.Logger object at 0x00000033721EF208>

    root [<logging.StreamHandler object at 0x0000003372019780>, <logging.StreamHandler object at 0x0000003372130710>]

    root handler = <logging.StreamHandler object at 0x0000003372019780>,formatter=<logging.Formatter object at 0x00000033720197B8>

    root handler = <logging.StreamHandler object at 0x0000003372130710>,formatter=None

    log1 [<logging.FileHandler object at 0x00000033721DDEB8>]

    log2 [<logging.FileHandler object at 0x00000033721EF080>]

    log2 formatter <logging.Formatter object at 0x00000033721EF1D0>

    log2 [<logging.FileHandler object at 0x00000033721EF080>]

    20

    log3 []

    9、filter是过滤

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

    import logging


    FORMAT = '%(asctime)-15s Thread info:%(thread)d %(threadName)s %(message)s'
    logging.basicConfig(format=FORMAT,level=logging.DEBUG)

    log1 = logging.getLogger('s')
    log1.setLevel(logging.WARNING)

    h1 = logging.StreamHandler()
    h1.setLevel(logging.INFO)
    fmt1 = logging.Formatter('log1-h1 %(message)s')
    h1.setFormatter(fmt1)
    log1.addHandler(h1)

    log2 = logging.getLogger('s.s1')
    print(log2.getEffectiveLevel())

    h2 = logging.StreamHandler()
    h2.setLevel(logging.INFO)

    fmt2 = logging.Formatter('log2-h2 %(message)s')
    h2.setFormatter(fmt2)

    f2 = logging.Filter('s')
    h2.addFilter(f2)

    log2.addFilter(h2)

    log2.warning('log2 waring ')

    30

    log1-h1 log2 waring

    2018-06-13 17:36:59,798         Thread info:8360 MainThread log2 waring

    消息log2的,他的名字是s.s1,所以过滤器的名字设置为s或者s.s1,消息就可以通过,但是如果使其他的就不能通过,不设置过滤器的名字,所以消息通过。

    总结:过滤器的核心就一句,在logging.filter类的filter方法中

    Record.namem.find(self.name,0,self.nlen) != 0

    本质上是等价于record.name.startswith(filter.name)

  • 相关阅读:
    版本控制
    1121 Reverse the lights(“玲珑杯”线上赛 Round #15 河南专场)
    LightOJ 1055
    LightOJ 1053
    LightOJ 1052
    4512 吉哥系列故事——完美队形I(LCIS)
    ZOJ 2432-Greatest Common Increasing Subsequence
    病毒 (湖南省第八届大学生计算机程序设计竞赛)
    1328 台球碰撞 (湖南省第六届大学生计算机程序设计竞赛)
    zzuli 1332 内部收益率 (湖南省第六届大学生计算机程序设计竞赛)
  • 原文地址:https://www.cnblogs.com/wangchunli-blogs/p/9949900.html
Copyright © 2011-2022 走看看