如何使用structlog获取多个配置相互独立的日志记录器
问题原因
structlog.configure 修改的是全局默认配置,所有通过 structlog.get_logger() 无参创建的日志实例,默认都会共享这套全局处理器链。你在创建logger2之后调用configure修改全局规则,之前创建的logger1也会读取新的全局配置,自然就会输出JSON格式,不存在配置隔离。
实现方案
不要在代码运行中途修改全局配置,根据你的使用场景二选一即可:
方案1:创建完全独立的日志实例(推荐,适配差异大的双日志需求)
直接用 structlog.wrap_logger 给两类日志分别绑定独立的处理器链、独立的输出目标,完全不依赖全局配置,从根源上避免配置互相影响。
import structlog from structlog.processors import ( add_log_level, TimeStamper, ConsoleRenderer, JSONRenderer ) # 1. 配置面向用户的控制台stderr日志:人类可读格式 console_logger_processors = [ add_log_level, TimeStamper(fmt="%Y-%m-%d %H.%M"), ConsoleRenderer(), ] logger1 = structlog.wrap_logger( structlog.PrintLogger(file=open("/dev/stderr", "w", encoding="utf-8")), processors=console_logger_processors ) # 2. 配置统计用JSON日志:输出到指定文件 json_logger_processors = [ JSONRenderer(), ] logger2 = structlog.wrap_logger( structlog.PrintLogger(file=open("stats_output.json", "a", encoding="utf-8")), processors=json_logger_processors ) # 测试输出 logger1.info('make something that needs to be logged', x=1, y=2, z='abc') logger2.info('structured_output', a=[1, 2, 3], b={'a': 1}) logger1.info('still no json output, great!')
运行后输出完全符合预期:
- logger1始终输出带时间戳、日志级别的可读格式到stderr
- logger2始终输出纯JSON格式到指定统计文件
- 两个实例的配置完全独立,后续修改任意一方的处理器都不会影响另一方
方案2:全局路由分流(适配大部分日志用统一格式、少数特殊日志用JSON的场景)
如果不想为每个logger单独传配置,可以在程序启动时一次性配置全局处理器,根据logger名称分流到不同的渲染逻辑,后续创建logger时只需要指定不同名称即可。
import structlog from structlog.processors import ( add_log_level, TimeStamper, ConsoleRenderer, JSONRenderer ) # 预定义两类渲染器 console_render_chain = [ add_log_level, TimeStamper(fmt="%Y-%m-%d %H.%M"), ConsoleRenderer() ] json_render = JSONRenderer() def log_router(logger, method_name, event_dict): # 按logger名称分流 log_name = event_dict.pop("_logger_name", "") if log_name == "stats": return json_render(logger, method_name, event_dict) # 默认走控制台可读格式 for proc in console_render_chain: event_dict = proc(logger, method_name, event_dict) return event_dict # 程序启动阶段只配置一次全局规则,后续禁止修改 structlog.configure(processors=[log_router]) # 按名称创建不同用途的logger logger1 = structlog.get_logger("user_console") logger2 = structlog.get_logger("stats") # 测试输出效果和方案1完全一致 logger1.info('make something that needs to be logged', x=1, y=2, z='abc') logger2.info('structured_output', a=[1, 2, 3], b={'a': 1}) logger1.info('still no json output, great!')
注意事项
- 禁止在程序运行中途调用
structlog.configure修改全局配置,这是导致日志格式串台的核心原因 - 如果JSON日志需要输出到文件,不要和控制台日志共用同一个输出流,避免内容混在一起难以解析
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

