zoukankan      html  css  js  c++  java
  • 03-logging日志

    logging模块的日志,我们需要明白四个内容:

    1. 日志收集器
    2. 日志级别
    3. 输出渠道
    4. 日志内容

    1. 日志的级别

    logging模块中,对日志的输出级别有着划分,分别是:DEBUG/INFO/WARNING/ERROR/CRITICAL这五种级别。

    如果你想要设置你的日志输出级别是DEBUG,那么logging模块会全面输入所有的日志;如果设置的日志输出级别是INFO,那么只会输出级别在INFO及以上的日志内容;其余的日志级别输出也是一样的。

    2. 日志收集器:自定义个人的日志收集器

    日志收集器是用来收集日志并输出的,logging中有一个默认的日志收集器,这个默认的日志收集器设置的日志的输出级别是WARNING级别,并且日志的名字是root,输出的格式也是一个默认的格式。

    也就是说,如果你的日志级别是INFO默认的日志收集器是不会输出日志的。

    import logging
    logging.warning("哈哈") # WARNING:root:哈哈
    
    2.1 创建日志收集器
    import logging
    
    # 传入一个名字,作为这个日志收集器的名字
    logger = logging.getLogger("admin")
    

    此时,这个日志收集器没有日志级别,没有输出渠道,没有输出的日志内容格式。

    所以我们需要去设置这些内容。

    2.2 设置日志级别
    import logging
    
    # 创建一个日志收集器
    logger = logging.getLogger("admin")
    
    # 设置输出级别
    logger.setLevel(logging.DEBUG)
    

    定义日志级别的时候,调用setLevel()方法,并传入日志的级别。

    日志级别在logging模块中有专门的常量,用来设置日志级别:

    logging.DEBUG
    logging.INFO
    logging.WARNING
    logging.ERROR
    logging.CRITICAL
    

    设置了日志的级别,但是依然输出不了任何的日志,因为没有设置日志的输出的渠道。

    2.3 设置输出渠道

    日志的输出渠道有两种,一个是控制台输出,一个是文件输出。

    控制台输出:logging.StreamHandler()

    文件输出:logging.FileHandler(filepath)。文件输出路径需要传递一些参数,例如文件路径,编码格式等。

    2.4 设置输出格式

    输出格式在logging的源码中,给出了输出的内容信息:

    %(name)s	        日志收集器的名字
    %(levelno)s	        数字形式的日志级别
    %(levelname)s	    文本形式的日志级别
    %(pathname)s	    调用日志输出函数的模块的完整路径名,可能没有
    %(filename)s	    调用日志输出函数的模块的文件名
    %(module)s	        调用日志输出函数的模块名
    %(funcName)s	    调用日志输出函数的函数名
    %(lineno)d	        调用日志输出函数的语句所在的代码行
    %(created)f	        当前时间,用UNIX标准的表示时间的浮 点数表示
    %(relativeCreated)d	输出日志信息时的,自Logger创建以 来的毫秒数
    %(asctime)s	        字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
    %(thread)d	        线程ID。可能没有
    %(threadName)s	    线程名。可能没有
    %(process)d	        进程ID。可能没有
    %(message)s	        用户输出的消息
    

    设置输出格式:

    fmt = "%(asctime)s %(name)s  %(levelname)s %(filename)s %(lineno)d line %(message)s"
    fortmatter = logging.Formatter(fmt)
    
    2.5 将输出渠道与输出格式进行绑定
    handle = logging.StreamHandler() # 控制台输出
    # logging.FileHandler()   # 文件输出
    
    # 设置输出格式
    fmt = "%(asctime)s %(name)s  %(levelname)s %(filename)s %(lineno)d line %(message)s"
    fortmatter = logging.Formatter(fmt)
    
    # 将输出渠道和输出格式绑定
    handle.setFormatter(fortmatter)
    
    2.6 将输出渠道添加到日志收集器中
    # 设置输出渠道
    handle = logging.StreamHandler() # 控制台输出
    # logging.FileHandler()   # 文件输出
    
    # 设置输出格式
    fmt = "%(asctime)s %(name)s  %(levelname)s %(filename)s %(lineno)d line %(message)s"
    fortmatter = logging.Formatter(fmt)
    
    # 将输出渠道和输出格式绑定
    handle.setFormatter(fortmatter)
    
    # 将设置好的渠道,添加到日志收集器中,完成自定义日志收集器
    logger.addHandler(handle)
    

    这里指的是已经设置好输出格式的输出渠道,将这歌输出渠道添加到日志收集器中,这个自定义的日志收集器就设置好了。

    完整代码:

    import logging
    
    # logging.warning("哈哈")
    
    # 创建一个日志收集器
    logger = logging.getLogger("admin")
    
    # 设置输出级别
    logger.setLevel(logging.DEBUG)
    
    # 设置输出渠道
    handle = logging.StreamHandler() # 控制台输出
    # logging.FileHandler()   # 文件输出
    
    # 设置输出格式
    fmt = "%(asctime)s %(name)s  %(levelname)s %(filename)s %(lineno)d line %(message)s"
    fortmatter = logging.Formatter(fmt)
    
    # 将输出渠道和输出格式绑定
    handle.setFormatter(fortmatter)
    
    # 将设置好的渠道,添加到日志收集器中,完成自定义日志收集器
    logger.addHandler(handle)
    
    logger.debug("haha")
    
    

    同一个日志收集器可以有多个输出渠道,并且每个输出渠道的输出日志级别都可以不相同。

    2.7 对渠道的输出级别进行调控

    当设置了一个输出渠道,那么就可以单独对这个输出渠道进行设置输出的 日志级别。

    但是设置的输出级别,是不能超过自定义的日志收集器的输出级别的。

    # 设置输出渠道
    handle = logging.StreamHandler() # 控制台输出
    # logging.FileHandler()   # 文件输出
    handle.setLevel(logging.INFO)
    

    这样一来,在控制台中,就只会输出INFO级别的日志。

    封装一个属于自己的日志类:

    import logging
    
    
    class MyLogger(object):
    
        def __init__(self, filename=None, level=logging.DEBUG):
            # 初始化一个日志收集器
            self.logger = logging.getLogger("admin")
            # 初始化日志输出格式
            self.fmt = "%(asctime)s %(name)s  %(levelname)s %(filename)s-%(lineno)d line %(message)s"
            # 设置日志收集器级别
            self.logger.setLevel(level)
            self.level = level
            self.filename = filename
            self.handle = None
    
        def private_logger(self, level, msg):
            # 设置输出渠道
            if self.filename:
                self.handle = logging.FileHandler(self.filename, encoding="utf-8")
            else:
                self.handle = logging.StreamHandler()
            # 设置输出格式
            formatter = logging.Formatter(self.fmt)
            # 日志收集器与输出格式绑定
            self.handle.setFormatter(formatter)
            # 将 输出渠道添加到日志收集器中
            self.logger.addHandler(self.handle)
            # 使用反射原理,执行日志输出
            if hasattr(self, level):
                func = getattr(self, level)
                func(msg)
            # 移除添加的输出handle:在执行测试用例的时候,都会调用一次private_logger,而此时每一个logger中都已经有了一个handle,所以重复调用private_logger都会重复向同一个logger中添加同样的handle,造成日志输出重复。
            # 所以需要在private_logger函数的末尾处,移除handle来防止日志重复。
            self.logger.removeHandler(self.handle)
    
        def debug(self, msg):
            self.logger.debug(msg)
    
        def info(self, msg):
            self.logger.info(msg)
    
        def warning(self, msg):
            self.logger.warning(msg)
    
        def error(self, msg):
            self.logger.error(msg)
    
        def critical(self, msg):
            self.logger.critical(msg)
    
        def exception(self, msg):
            self.logger.exception(msg)
    
    logger = MyLogger()
    logger.private_logger("exception", "断言失败")
    # logger.exception()
    
    
    
    

    封装自定义日志类可能出现的问题

    1. 重复输出日志

    日志重复输出:Python Logging日志重复输出问题

    这是因为在执行测试用例的时候,每一次调用封装的日志类,都会在同一个logger中多次添加同一个handle,造成日志输出重复。

    所以在每次执行测试用例之前,都需要先移除logger中已有的handle,再去重新添加handle来防止日志输出重复。

  • 相关阅读:
    bzoj 3209: 花神的数论题 数位dp
    bzoj 1799: [Ahoi2009]self 同类分布 数位dp
    Codeforces 755 F. PolandBall and Gifts 多重背包+贪心
    Educational Codeforces Round 17 D. Maximum path DP
    Codeforces Round #396 (Div. 2) C. Mahmoud and a Message DP
    Codeforces 768 E. Game of Stones 博弈DP
    HDU 2457/POJ 3691 DNA repair AC自动机+DP
    Codefoces 791D. Bear and Tree Jumps 树形DP
    Codeforces 440 D. Berland Federalization 树形DP,记录DP
    Codeforces 709E. Centroids 树形DP
  • 原文地址:https://www.cnblogs.com/Pilaoban/p/13173078.html
Copyright © 2011-2022 走看看