美文网首页
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