美文网首页
python logging 用法(一)

python logging 用法(一)

作者: 田丰w | 来源:发表于2024-01-28 18:23 被阅读0次

    抽象组成

    1. Logger: 写日志接口,把要记录的日志发给它就好,要不要打印,打到哪里,用什么格式都被封装进去了.
    2. Handler: 用于封装一个日志写出方向
    • 写console的handler: logging.StreamHandler()
    • 写文件的handler: 如 handlers.TimedRotatingFileHandler
    1. Formatter: 用于定义一个日志打印格式, 绑定在一个handler上
      其中,%(asctime)s用于控制日志中时间在哪个位置显示,
      时间格式由datefmt参数控制,但毫秒不在asctime中控制;
      %(msecs)d 用于毫秒部分的显示控制,d是显示几位毫秒
      日志格式: https://docs.python.org/3.11/library/logging.html#logrecord-attributes
      时间格式: https://docs.python.org/3.11/library/time.html#time.strftime
    2. Filter: 用于定义一个日志过滤条件

    这几个之间具有这样的组合关系


    image.png

    logger执行流程

    logging 执行流程

    Logger 和 Handler 都可以 setLevel, 都可以 addFilter

    日志等级(不过多展开了)

    • 是个整数, 越大等级越高
    • 默认设置打印等级后,等于和高于打印等级的日志会被打印
    • logging. NOTSET < logging.DEBUG < logging.INFO < logging.WARNING < logging.ERROR < logging.CRITICAL

    logger层级(todo: 下一篇)

    其中名称为 "root" 的 logger 比较特殊,是根 logger

    用法Demo

    import logging
    import os
    import sys
    from logging import handlers
    
    # 日志目录
    log_dir = os.getenv("app_logs", "./logs/")
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    
    info_log_name = "info.log"
    error_log_name = "error.log"
    
    # 日志格式
    log_fmt = "%(asctime)s.%(msecs)03d [%(process)d-%(thread)d] %(filename)s:%(lineno)d %(funcName)s " \
              "[%(levelname)s] %(message)s"
    date_fmt = "%Y-%m-%d %H:%M:%S"
    formatter = logging.Formatter(fmt=log_fmt, datefmt=date_fmt)
    
    
    # filter
    
    # 只保留非错误级别的日志
    class NormalLogFilter(logging.Filter):
        def __init__(self, name):
            super().__init__(name=name)
    
        def filter(self, record: logging.LogRecord) -> bool:
            if record.levelno < logging.ERROR:
                return True
            return False
    
    
    # handler
    
    # 打印到控制台(默认输出到标准错误流 sys.stderr)
    console_handler = logging.StreamHandler(stream=sys.stdout)
    console_handler.setFormatter(formatter)
    console_handler.setLevel(logging.DEBUG)
    
    # info 日志打印到文件
    info_log_file_handler = handlers.TimedRotatingFileHandler(
        filename=os.path.join(log_dir, info_log_name), when="midnight", backupCount=15, encoding="utf-8")
    info_log_file_handler.setFormatter(formatter)
    info_log_file_handler.setLevel(logging.INFO)
    normal_filter = NormalLogFilter("normalFilter")
    info_log_file_handler.addFilter(normal_filter)
    
    # error 日志打印到文件
    error_log_file_handler = handlers.TimedRotatingFileHandler(
        filename=os.path.join(log_dir, error_log_name), when="midnight", backupCount=15, encoding="utf-8")
    error_log_file_handler.setFormatter(formatter)
    error_log_file_handler.setLevel(logging.ERROR)
    
    # 生成 logger
    logger = logging.getLogger("root")
    logger.addHandler(console_handler)
    logger.addHandler(info_log_file_handler)
    logger.addHandler(error_log_file_handler)
    logger.setLevel(logging.INFO)
    
    
    # ========= test code ======== #
    
    def _log_use_test():
        logger.setLevel(logging.DEBUG)
        logger.debug("dddebug")
        logger.info("iiinfo")
        logger.warning("wwwarning")
        logger.error("eeerror")
        logger.critical("cccritical")
        logger.info("占位符用法: %s:%d, 哈哈哈:%f", "词语", 12, 3.01)
        word, idx, weight = "中文", 23, 5.23
        logger.info(f"占位符用法: {word}:{idx}, 哈哈哈:{weight}")
    
        try:
            12 / 0
        except Exception as e:
            # 使用 logging 参数输出异常
            logger.error("Houston, we have a %s", "major problem", exc_info=True)
    
        try:
            12 / 0
        except Exception as e:
            # 直接使用 logging 的 exception 函数输出异常堆栈信息
            logger.exception("Houston, we have another %s. error= {}".format(e), "major problem")
    
        try:
            12 / 0
        except Exception as e:
            import traceback
            s = traceback.format_exc()
            # 使用 logging + traceback 模块输出异常
            logging.info("traceback: {}".format(s))
    
    if __name__ == "__main__":
        _log_use_test()
    
    

    生成的日志格式如下

    2024-01-29 17:35:11.666 [18827-4788831744] log_conf.py:76 _log_use_test [DEBUG] dddebug
    2024-01-29 17:35:11.667 [18827-4788831744] log_conf.py:77 _log_use_test [INFO] iiinfo
    2024-01-29 17:35:11.669 [18827-4788831744] log_conf.py:78 _log_use_test [WARNING] wwwarning
    2024-01-29 17:35:11.669 [18827-4788831744] log_conf.py:79 _log_use_test [ERROR] eeerror
    2024-01-29 17:35:11.670 [18827-4788831744] log_conf.py:80 _log_use_test [CRITICAL] cccritical
    2024-01-29 17:35:11.670 [18827-4788831744] log_conf.py:81 _log_use_test [INFO] 占位符用法: 词语:12, 哈哈哈:3.010000
    2024-01-29 17:35:11.671 [18827-4788831744] log_conf.py:83 _log_use_test [INFO] 占位符用法: 中文:23, 哈哈哈:5.23
    2024-01-29 17:35:11.671 [18827-4788831744] log_conf.py:89 _log_use_test [ERROR] Houston, we have a major problem
    Traceback (most recent call last):
      File "/Users/admin/git-repo/log_conf.py", line 86, in _log_use_test
        12 / 0
    ZeroDivisionError: division by zero
    2024-01-29 17:35:11.673 [18827-4788831744] log_conf.py:95 _log_use_test [ERROR] Houston, we have another major problem. error= division by zero
    Traceback (most recent call last):
      File "/Users/admin/git-repo/log_conf.py", line 92, in _log_use_test
        12 / 0
    ZeroDivisionError: division by zero
    2024-01-29 17:35:11.673 [18827-4788831744] log_conf.py:103 _log_use_test [INFO] traceback: Traceback (most recent call last):
      File "/Users/admin/git-repo/log_conf.py", line 98, in _log_use_test
        12 / 0
    ZeroDivisionError: division by zero
    

    相关文章

      网友评论

          本文标题:python logging 用法(一)

          本文链接:https://www.haomeiwen.com/subject/gjevodtx.html