python日志重复打印

Python日志重复打印问题

用Python的logging模块记录日志时,出现了重复输出日志的问题。这里我是把logger封装了一层:

def init_logger(log_name, file_log_level=logging.DEBUG, stream_log_level=logging.INFO,
                max_bytes=200 * 1024 * 1024, backup_count=10):
    log_dir_path = os.path.join(CONST.PROJECT_DIR, 'logs')
    if not os.path.isdir(log_dir_path):
        os.makedirs(log_dir_path)
    log_file_path = os.path.join(log_dir_path, '{}.log'.format(log_name))
    logger = logging.getLogger(log_name)

    fmt = '[%(name)s]' + '-[%(filename)s:%(lineno)s]' +  \
          '-[%(asctime)s]' + '-[%(levelname)s]' + '-[%(process)d]'  + '-[%(thread)d]' + '\t%(message)s'

    formatter = logging.Formatter(fmt)

    file_handler = handlers.RotatingFileHandler(log_file_path, maxBytes=max_bytes,
                                                backupCount=backup_count, encoding='utf-8')
    file_handler.setLevel(file_log_level)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    stream_handler = logging.StreamHandler()
    stream_handler.setLevel(stream_log_level)
    stream_handler.setFormatter(formatter)
    # logger.addHandler(stream_handler)

    log_queue = Queue()
    queue_handler = handlers.QueueHandler(log_queue)
    # queue_handler.setLevel(stream_log_level)
    # queue_handler.setFormatter(formatter)
    queue_listener = handlers.QueueListener(log_queue, stream_handler)
    logger.addHandler(queue_handler)
    queue_listener.start()

    logger.setLevel(file_log_level)
    logger.propagate = False
    return logger


logger = init_logger(PROJECT_NAME)

其他地方要用到logger直接导入。

logging日志输出重复一般都是因为多次addHandler的问题,代码里调用addHandler的地方只有init_logger,那么肯定是init_logger函数重复调用了,在init_logger后面输出调用栈:

logger = init_logger(PROJECT_NAME)
traceback.print_stack()

从调用栈中看到有两处import了logger这个模块,回溯到上一层调用发现有一处:

from src.common.logger import logger

另一处:

from common.logger import logger

统一成from common.logger import logger,问题解决。

<think>嗯,用户的问题是关于如何在Python中实现日志的保存和打印的最佳实践。首先,我需要回忆一下Python中的logging模块,因为这是处理日志的标准库。我记得logging模块提供了灵活的配置,可以同时将日志输出到控制台和文件,这可能符合用户的需求。 用户提到“保存和打印”,也就是需要日志既输出到文件又显示在控制台上。这时候,应该使用处理程序(Handlers),比如FileHandler和StreamHandler。可能需要配置多个handler,一个用于写入文件,另一个用于控制台输出。同时,还需要设置日志的格式,比如时间、日志级别、消息内容等,这可以通过Formatter类来实现。 另外,日志的级别也很重要。用户可能希望不同级别的日志被记录,比如DEBUG、INFO、WARNING等。需要确保设置合适的级别,避免日志过多或过少。通常建议使用INFO作为默认级别,但根据实际情况调整。 还有,logging模块的单例模式,也就是整个应用中使用同一个logger实例,这样配置一次后各处都能使用。可能需要使用getLogger(__name__)来获取logger对象,这样可以方便地追踪日志的来源模块。 另外,用户可能需要了解如何避免日志文件过大,这时候可以使用RotatingFileHandler或TimedRotatingFileHandler,按大小或时间滚动日志文件,自动分割和备份。这也是最佳实践的一部分,特别是在生产环境中。 还要注意多线程或异步环境下的日志处理,确保线程安全。不过Python的logging模块本身是线程安全的,所以可能不需要额外处理,但需要确认这一点是否正确。 最后,可能需要提供一个完整的配置示例,展示如何同时输出到控制台和文件,设置格式和日志级别,以及如何处理不同的handler。同时,结合用户提供的引用代码中的例子,比如引用[1]中的数据处理流程,可能需要将日志集成到类似的数据处理函数中,例如在data_ingestion或data_processing中添加日志记录。 还要检查用户提供的参考引用,是否有相关的代码或实践可以借鉴。例如,引用[2]中的多线程处理,可能需要考虑日志在多线程中的使用情况,但根据用户的问题,这可能不是重点,但可以提及。 总结步骤应该是: 1. 导入logging模块,配置基本设置。 2. 创建FileHandler和StreamHandler。 3. 设置日志格式,并应用到各个handler。 4. 将handler添加到logger实例中。 5. 设置日志级别。 6. 示例代码展示,如何在函数中使用logging记录信息。 另外,需要回答用户可能的问题,比如如何避免重复日志、如何管理不同模块的日志、如何配置日志文件滚动等。这些可以作为相关问题提出,但用户可能希望直接在回答中找到这些信息。 需要确保回答结构清晰,分步骤说明,并给出代码示例,同时引用提供的参考内容中的代码结构,比如引用[1]中的函数调用流程,将日志集成到其中。</think>在Python中实现日志的保存和打印,推荐使用标准库`logging`模块。以下是分步实现的最佳实践: --- ### 1. **基础配置** 通过`basicConfig`快速配置日志系统,设置格式、级别和输出目标: ```python import logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("app.log"), # 保存到文件 logging.StreamHandler() # 打印到控制台 ] ) ``` --- ### 2. **自定义多处理器** 若需更灵活控制(如不同格式或级别),可手动配置处理器(Handlers): ```python logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # 设置全局最低日志级别 # 文件处理器(保存到文件) file_handler = logging.FileHandler("debug.log") file_handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')) file_handler.setLevel(logging.DEBUG) # 文件记录DEBUG及以上级别 # 控制台处理器(打印到终端) console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) console_handler.setLevel(logging.INFO) # 控制台仅显示INFO及以上级别 logger.addHandler(file_handler) logger.addHandler(console_handler) ``` --- ### 3. **日志滚动管理** 使用`RotatingFileHandler`或`TimedRotatingFileHandler`避免日志文件过大[^1]: ```python from logging.handlers import RotatingFileHandler rotating_handler = RotatingFileHandler( "app.log", maxBytes=5*1024*1024, # 5MB后分割 backupCount=3, # 保留3个备份文件 encoding='utf-8' ) logger.addHandler(rotating_handler) ``` --- ### 4. **在代码中使用** 在数据处理流程(如引用[1]的代码)中集成日志: ```python def data_ingestion(data): try: logger.info("开始数据采集") # 数据采集逻辑 except Exception as e: logger.error(f"数据采集失败: {str(e)}", exc_info=True) raise def data_processing(data): logger.debug(f"当前处理数据量: {len(data)}") # 数据处理逻辑 ``` --- ### 5. **关键注意事项** - **级别控制**:`DEBUG` > `INFO` > `WARNING` > `ERROR` > `CRITICAL` - **线程安全**:`logging`模块原生支持多线程,无需额外处理[^2] - **性能优化**:避免在循环中频繁记录低级别日志(如`DEBUG`) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值