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


    本文内容:

    • logging模块的介绍
    • logging模块的基础使用
    • logging模块的扩展使用
    • logging中的Filter
    • 使用配置文件配置logging和logger
    • 小技巧
    • 想要了解更多?不如看看官方文档。

    首发日期:2018-07-05


    logging模块的介绍:

    • 它是一个python标准库,所以它的通用性很高,所有的python模块都可以与它合作参与日志记录。

    日志级别:

    基本 中文意义 触发情况
    DEBUG 调试 调试时期
    INFO 提示 正常运行时
    WARINING 警告 现在可运行,但未来可能发生错误时(例如未来存储空间可能不足)
    ERROR 错误 当程序发生错误,无法执行某些功能时
    CRITICAL 严重的、致命的 当程序发生严重错误,无法继续运行时

    默认是WARNING。

    image

    基本类:

    • Loggers :日志器,负责开放接口来调用功能,比如它负责添加Handlers和Filters 。有默认的Loggers 对象
    • Handlers  :负责日志记录的传输目的地,比如有FileHandler(写入目标为文件)和StreamHandler(写入目标为流,默认为标准输出流)
    • Filters :负责过滤哪些日志是要输出的 。
    • Formatters :负责对日志输出格式的格式化。

    logging模块的基础使用:

    • 基础使用使用就是使用默认logger对象的使用。
    1. 设置logging,调用logging.basicConfig()来配置日志信息。 【由这个来看就知道,它是“通用型的,只能设置一次的”,如果不同部分想使用不同的日志记录,需要使用logger对象(下面的扩展使用)
      • 可设置的参数:filename日志文件名,filemode打开文件的方式,format日志的输出格式,datefmt日期输出格式,style设置format的类型,level日志记录的最低级别,stream输出流(不与filename并存,filename优先),handlers日志处理对象(默认是根处理对象),
      • 一般使用的参数:filename日志文件名,format日志的输出格式,level日志记录的最低级别,stream设置输出流
        • filename是日志文件名,就是一个普通文件名
        • format是日志的输出格式,设置方法下面讲
        • level的设置值为debug等值,使用方法为logging.DEBUG,logging.INFO,logging.WARNING,logging.ERROR,logging.CRITICAL
        • style影响format的类型,它的值有'%','{','$',默认是'%',不同的style可以识别以下不同的message标识符:%(message)s、{message}、$message
    2. 输出日志信息:
      • 调试级别日志信息:logging.debug(信息)
      • 提示级别信息:logging.info(信息)
      • 警告基本信息:loggin.warning(信息)
      • 错误级别信息:logging.error(信息)
      • 严重级别信息:logging.critical(信息)

     

    信息输出的格式化(指的是logging.info等函数里面的信息):

    这个表述可能不是很清晰,但意义类似程序报错信息,(假如)普通的异常信息只有一个报错原因,(那么为了方便观看)可能还需要一些如错误地点,错误事件等信息,而这些附加的统一的时间不应该由生产错误信息的部分来添加(可能有很多个模块),而应该将这个信息给专门做这事的部分来处理(交个formatter来处理)

    1.支持普通字符串%格式化,例如:

    logging.info('Started %s'%tag)

    2.支持普通字符串format格式化,例如:

    logging.info('{} started '.format(tag))

    3.logging自带的,例如:

    logging.info('%s start in', tag) logging.info('%s start in %s',tag,address)

    format设置方法:

    • 常用特殊字符:
      • message是日志信息
      • levelname日志信息等级
      • asctime是字符串形式的日期时间
      • name是logger的名字
      • levelno是数字形式的日志信息等级
      • module是调用日志输出函数的模块名
      • funcName是调用日志输出函数的函数名
      • lineno是调用日志输出函数的代码行数

    根据不同的style,可以使用%(message)s或{message}或$message类似的格式来标注指定位置使用指定信息来取代。

    • 默认格式:
      • asctime 使用%(asctime)s
      • funcName使用%(funcName)s
      • levelname使用%(levelname)s
      • message使用%(message)s
      • lineno使用%(lineno)d
      • module使用%(module)s
      • name使用%(name)s

    官方文档:

    https://docs.python.org/3.6/library/logging.html#logrecord-attributes

     

     

    datefmt日期输出格式的设置方法:

    设置format中特殊字符asctime(日期时间)的输出格式

    • 特殊字符:
      • %y 两位数的年份表示(00-99)
      • %Y 四位数的年份表示(000-9999)
      • %m 月份(01-12)
      • %d 月内中的一天(0-31)
      • %H 24小时制小时数(0-23)
      • %I 12小时制小时数(01-12)
      • %M 分钟数(00=59)
      • %S 秒(00-59)

    使用自己想要的分隔符和顺序来定义日期时间的格式,例如:

    datefmt='%m/%d/%Y %I:%M:%S %p'

    使用小例子:

    不使用format的:

    import
    logging def show(): print("wechat running...") return "wechat" def main(): logging.basicConfig(filename='myapp.log', level=logging.INFO) tag=show() logging.info('Started %s'%tag) logging.info('Finished %s'%tag) if __name__ == '__main__'
    :
        main()

    使用format和datefmt的:

    import
    logging def show(): print("wechat running...") return "wechat" def main(): logging.basicConfig(filename='myapp.log', format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p',level=logging.INFO) tag=show() logging.info('%s start in', tag) logging.info('%s Finished',tag) if __name__ == '__main__'
    :
        main()

    PS:虽然上面没有说到logger对象,handler对象(默认方向是标准输出流),formatter对象,但实际上,它是有默认的。不要因为默认值而搞错。所以不建议混杂基础版的和扩展版的使用。


    logging模块的扩展使用:

    1.导入模块:

    import logging

     

    2.获取logger对象:

    logger = logging.getLogger("AppName")【这里根据不同的名字定义不同的logger对象,默认为root。】

     

    在模块中使用时,官方文档中有一个这样的代码,有点意思:

    logger = logging.getLogger(__name__)

    3.设置最低日志输出级别:

    logger.setlevel()

    例如:

    logger.setLevel(logging.INFO)

    4.创建并绑定handler:

    handler用于处理日志信息的输出方向,可以添加多个handler,代表同时向多个方向输出信息

    • 创建handler:

    输出方向为文件,使用FileHandler,例如:

    logging.FileHandler("test.log")

    输出方向为流,使用StreamHandler,例如:

    logging.StreamHandler(sys.stdout)

    PS:想了解更多Handler,可以自己查看官方文档https://docs.python.org/3.6/howto/logging.html#useful-handlers

     

    • 绑定handler,使用addHandler():

    例如:

    logger.addHandler(handler)
    • 绑定后如果想解绑handler,使用removeHandler():

    例如:

    logger.removeHandler(handler)

     

    5.定义handler的输出格式formatter并绑定到handler上,formatter的设置方法类似上面基础使用中的format:

    • 创建:

    例如:

    formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')

     

    • 绑定:

    handler.setFormatter(formatter) 或handler.formatter=formatter

    6.将handle绑定到logger对象上。

    logger.addHandler(file_handler)

    logger.addHandler(console_handler)

     

     

    7.输出日志:

    调试级别: logger.debug(信息)

    提示级别: logger.info(信息)

    警告级别: logger.warn(信息)

    错误级别:

    logger.error(信息)

    logger.exception(信息)【与error不同的是,还附带堆栈信息,一般用在发生异常时】

    严重级别:

    logger.fatal(信息) 【fatal是critical的别名】

    logger.critical(信息)

     

     

    使用示例:

    import
    logging def demo(): #获取logger对象 logger=logging.getLogger("WeChat") #设置日志等级 logger.setLevel(logging.DEBUG) #创建绑定handler handler=logging.FileHandler('wechat.log') logger.addHandler(handler) # 创建绑定formatter formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') formatter.datefmt = '%m/%d/%Y %I:%M:%S %p' #可选的 handler.setFormatter(formatter) #尝试输出错误信息 logger.debug("debug message") logger.info("info message") logger.warning("warining message") logger.error("error message") logger.critical("critical message") if __name__=="__main__"
    :
        demo()

    补充:

    • 如果你不想新建handler和formatter,可以使用basicConfig方式(可以使用basicConfig来配置所有的logger对象的handler和formatter),当要注意混杂风险。【basicConfig和handler必须至少存在一个,因为默认的logger对象也是需要初始化的
    • logging模块中还有一个filter,由于它涉及的内容较多,单独列在下面讲。

    logging中的Filter:

    • Filter用来过滤日志信息,例如你想输出A类信息,但不想输出C类信息,就可以进行过滤
    • 而由于所有的信息都有经过过滤器,也可以使用过滤器来增加一些信息。

    使用方法1:建立子类

    下面的例子可能不是很符合应用,仅用于举例:

    过滤非允许用户的日志信息:

    import
    logging import sys class ContextFilter(logging.Filter): def filter(self, record): if record.role=="admin" : return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter f = ContextFilter() logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

    官网版的加信息版本:

    import
    logging from random import choice class ContextFilter(logging.Filter): """
    
        This is a filter which injects contextual information into the log.
    
        Rather than use actual contextual information, we just use random
        data in this demo.
        """
    
        USERS 
    = ['jim', 'fred', 'sheila'] IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1'] def filter(self, record): record.ip = choice(ContextFilter.IPS) record.user = choice(ContextFilter.USERS) return True if __name__ == '__main__': levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) logging.basicConfig(level=logging.DEBUG, format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') a1 = logging.getLogger('a.b.c') a2 = logging.getLogger('d.e.f') f = ContextFilter() a1.addFilter(f) a2.addFilter(f) a1.debug('A debug message') a1.info('An info message with %s', 'some parameters') for x in range(10): lvl = choice(levels) lvlname = logging.getLevelName(lvl) a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')

    使用方法2:使用filter函数

    python3.2后,可以使用filter函数来做到上面方法1的效果

    例子1:

    import
    logging import sys def myfilter(record): if record.role == "admin": return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter f = logging.Filter() f.filter=myfilter logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

    例子2,利用lambda:

    logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter
    
    #
    f = ContextFilter() f = logging.Filter() f.filter=lambda record: record.role=="admin"
    
    logger.addFilter(f)
    
    logger.info(
    'An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

    使用配置文件配置logger对象:

     注意:logging默认使用的logger对象叫做root  

    config文件配置方式:
     
    import
    logging import logging.config logging.config.fileConfig('logging.conf') # create logger logger = logging.getLogger('simpleExample') # 'application' code logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message')

    文件内容:

    [loggers] keys=root,simpleExample [handlers] keys=consoleHandler [formatters] keys=simpleFormatter [logger_root] level=DEBUG handlers=consoleHandler [logger_simpleExample] level=DEBUG handlers=consoleHandler qualname=simpleExample propagate=0 [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=simpleFormatter args=(sys.stdout,) [formatter_simpleFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt=

    image

    PS:也支持YAML方式,这里不讲述


    小技巧:

    如果留意到过滤器例子的话,你可以发现

    在formatter内可以附加参数:

    输出信息时,附加一个参数extra,附加的参数可以被formatter使用

    import
    logging import sys class ContextFilter(logging.Filter): def filter(self, record): if record.role=="admin" : return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #创建绑定fiter f = ContextFilter() logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被过滤掉了

    想要了解更多?不如看看官方文档。

    https://docs.python.org/3.6/library/logging.html


  • 相关阅读:
    python 基础2.5 循环中continue与breake用法
    python 基础 2.4 while 循环
    python 基础 2.3 for 循环
    python 基础 2.2 if流程控制(二)
    python 基础 2.1 if 流程控制(一)
    python 基础 1.6 python 帮助信息及数据类型间相互转换
    python 基础 1.5 python数据类型(四)--字典常用方法示例
    Tornado Web 框架
    LinkCode 第k个排列
    LeetCode 46. Permutations
  • 原文地址:https://www.cnblogs.com/progor/p/9269230.html
Copyright © 2011-2022 走看看