You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

服务器端Tornado自定义日志与内置日志统一输出实现方案

问题根因
  • 服务器运行时触发了Tornado多进程模式(server.start(0)仅在非Windows环境执行),你调用tornado.options.parse_command_line()时默认会触发Tornado的日志自动初始化逻辑,直接覆盖了你之前通过logging.basicConfig配置的根日志设置
  • 你通过os.chdir修改工作目录的方式不可靠,多进程fork后子进程的工作目录可能发生变化,导致后续日志写入路径不符合预期
  • 多进程场景下,基础的logging.basicConfig配置在子进程中会失效,只有主进程初始化阶段的日志能正常写入
解决方案

步骤1:关闭Tornado自动日志配置

调用tornado.options.parse_command_line时显式指定logging=None,禁止Tornado修改已有的日志配置。

步骤2:调整日志初始化逻辑

直接构造日志文件的绝对路径,避免修改工作目录;显式给根日志添加FileHandler,同时保证Tornado三类日志的传播属性开启,默认情况下Tornado日志的传播属性为开启,会自动把日志上报到根日志,写入同一个文件。

修改后的代码示例

自定义日志模块

import os
import logging

def create_logger():
    """
    创建全局日志配置,所有日志(含Tornado内置日志)都会写入同一个文件
    :return: bool - 初始化成功返回True
    """
    # 直接构造日志文件绝对路径,避免修改工作目录
    base_dir = os.path.dirname(os.path.abspath(__file__))
    log_dir = os.path.normpath(os.path.join(base_dir, os.pardir, os.pardir, 'logs'))
    # 自动创建不存在的日志目录
    os.makedirs(log_dir, exist_ok=True)
    log_path = os.path.join(log_dir, "PythonLogger.log")

    # 获取根日志
    root_logger = logging.getLogger()
    # 清空原有Handler,避免配置冲突
    for handler in root_logger.handlers[:]:
        root_logger.removeHandler(handler)
    
    # 显式配置文件Handler
    file_handler = logging.FileHandler(log_path, mode='a', encoding='utf-8')
    formatter = logging.Formatter('%(asctime)s %(message)s')
    file_handler.setFormatter(formatter)
    root_logger.addHandler(file_handler)
    
    # 设置全局日志级别
    root_logger.setLevel(logging.NOTSET)

    # 显式配置Tornado三类日志的级别和传播属性
    for log_name in ["tornado.access", "tornado.application", "tornado.general"]:
        tornado_log = logging.getLogger(log_name)
        tornado_log.setLevel(logging.NOTSET)
        tornado_log.propagate = True

    root_logger.info('El logger está inicializado')
    return True

def log_info_message(msg):
    """
    打印info级别日志
    :param msg: 日志内容
    :return: None
    """
    logging.getLogger().info(msg)

启动代码修改

if __name__ == '__main__':
    # 日志初始化要放在所有逻辑最前面
    create_logger()
    log_info_message('Initiating Python application')

    # 关键配置:禁止Tornado自动覆盖日志配置
    tornado.options.parse_command_line(logging=None)

    server = tornado.httpserver.HTTPServer(test.app)
    server.listen(options.port)

    try:
        if 'Windows_NT' not in os.environ.values():
            server.start(0)
        tornado.ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        tornado.ioloop.IOLoop.instance().stop()
注意事项

多进程场景下多个进程同时写同一个日志文件可能出现日志乱序、内容截断的问题,如果对日志完整性要求很高,建议改为单进程采集日志,或使用支持多进程安全的日志Handler,或者给每个进程分配独立的日志文件。


内容的提问来源于stack exchange,提问作者MartinHN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 10:15:02