Python中关于logger的使用问题

现在自己在写一个项目,有一个主入口模块和其他的功能模块(每个模块为单独的一个 python 文件),请问一下,有什么方法能把日志打印到同一个文件输出呢?之前只试过对每个 py 文件单独打一个 log,没试过这么多模块来进行输出到一个日志里面,求解答


Python中关于logger的使用问题
5 回复

Python中关于logger的使用问题

Python的logging模块确实有点绕,我来给你讲清楚怎么正确使用。

核心概念:

  1. Logger - 记录器,你通过它来写日志
  2. Handler - 处理器,决定日志输出到哪里(控制台、文件等)
  3. Formatter - 格式化器,决定日志的显示格式
  4. Filter - 过滤器(可选),用于更精细的控制
  5. Level - 日志级别:DEBUG < INFO < WARNING < ERROR < CRITICAL

标准用法示例:

import logging

# 1. 创建logger
logger = logging.getLogger(__name__)  # 推荐使用模块名
logger.setLevel(logging.DEBUG)  # 设置logger的级别

# 2. 创建handler(控制台输出)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)  # 控制台只显示INFO及以上

# 3. 创建formatter
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
console_handler.setFormatter(formatter)

# 4. 将handler添加到logger
logger.addHandler(console_handler)

# 5. 使用logger
logger.debug('调试信息')  # 不会显示,因为控制台handler级别是INFO
logger.info('普通信息')
logger.warning('警告信息')
logger.error('错误信息')

常见坑点:

  1. 重复日志问题 - 多次调用getLogger()并添加handler会导致重复输出
# 错误示例
logger = logging.getLogger('my_logger')
logger.addHandler(console_handler)
# ... 其他地方又执行了一次
logger.addHandler(console_handler)  # 重复添加!

# 正确做法:检查是否已有handler
if not logger.handlers:
    logger.addHandler(console_handler)
  1. 父子logger继承 - logger有层级关系,子logger默认继承父logger的配置
parent_logger = logging.getLogger('parent')
parent_logger.setLevel(logging.WARNING)

child_logger = logging.getLogger('parent.child')
# child_logger默认继承parent_logger的WARNING级别
  1. basicConfig的坑 - 只能调用一次,且对root logger生效
import logging

# 这个要放在最前面,且只调用一次
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

实际项目中的推荐配置:

# config.py
import logging
import logging.config

LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'INFO',
            'formatter': 'standard',
            'stream': 'ext://sys.stdout',
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'DEBUG',
            'formatter': 'standard',
            'filename': 'app.log',
            'maxBytes': 10485760,  # 10MB
            'backupCount': 5,
        },
    },
    'loggers': {
        '': {  # root logger
            'handlers': ['console', 'file'],
            'level': 'DEBUG',
        },
        'my_module': {
            'handlers': ['file'],
            'level': 'INFO',
            'propagate': False  # 不传递给父logger
        }
    }
}

# 初始化配置
logging.config.dictConfig(LOGGING_CONFIG)

# 在其他模块中直接使用
# module.py
import logging
logger = logging.getLogger(__name__)
logger.info('This works!')

一句话建议: 用dictConfig配置,每个模块用__name__获取logger,避免直接操作root logger。

初始化 logger 的时候日志文件名指定好呀,可以参考一下这个项目中的这个模块有用到 logging 库,所有的日志都写在同一个文件里面 https://github.com/supersu097/mycrawler/blob/master/core/helper.py

同样有个问题,就是怎么样将项目中的不同级别的日志打到不同的文件中

回到顶部