如何通过Django BaseCommand的base_stealth_options配置stdout与stderr?
问题
运行Django命令时,能否通过BaseCommand中的base_stealth_options来设置stdout和stderr?我找不到相关使用文档。例如,我希望在执行python manage.py foo时,将stdout和stderr分别关联到日志的info和error级别。我已尝试编写manage_custom_logging.py实现该功能,但想知道既然存在base_stealth_options,是否有更优的实现方式。
回答
base_stealth_options无法满足该需求
Django源码里的base_stealth_options是用来声明命令的隐藏选项的——这类选项会被命令接收,但不会显示在帮助信息中。它的作用域仅为命令参数处理,和重定向stdout、stderr完全不相关,所以没法用它实现你要的日志关联功能。你的现有实现可行,可做细节优化
你通过替换sys.stdout和sys.stderr的方式已经能达成目标,但可以补充几个细节让代码更健壮:- 保存原始流并在执行后恢复,避免影响后续逻辑:
original_stdout = sys.stdout original_stderr = sys.stderr try: sys.stdout = StreamToLogger(logging.info) sys.stderr = StreamToLogger(logging.error) execute_from_command_line(sys.argv) finally: sys.stdout = original_stdout sys.stderr = original_stderr - 让
StreamToLogger类更通用,支持指定日志器和级别:
使用时可以指定专属日志器:class StreamToLogger(object): def __init__(self, logger, level): self.logger = logger self.level = level def write(self, buf): for line in buf.rstrip().splitlines(): self.logger.log(self.level, line.rstrip()) def flush(self): passsys.stdout = StreamToLogger(logging.getLogger('cmd_stdout'), logging.INFO) sys.stderr = StreamToLogger(logging.getLogger('cmd_stderr'), logging.ERROR)
- 保存原始流并在执行后恢复,避免影响后续逻辑:
针对单命令的Django风格实现
如果不想全局替换流,只想让特定自定义命令生效,可以自定义一个BaseCommand子类,重写execute方法来实现局部流替换:from django.core.management.base import BaseCommand import sys import logging class StreamToLogger(object): def __init__(self, logger, level): self.logger = logger self.level = level def write(self, buf): for line in buf.rstrip().splitlines(): self.logger.log(self.level, line.rstrip()) def flush(self): pass class LoggingBaseCommand(BaseCommand): def execute(self, *args, **options): original_stdout = sys.stdout original_stderr = sys.stderr try: sys.stdout = StreamToLogger(logging.getLogger('cmd_stdout'), logging.INFO) sys.stderr = StreamToLogger(logging.getLogger('cmd_stderr'), logging.ERROR) super().execute(*args, **options) finally: sys.stdout = original_stdout sys.stderr = original_stderr之后你的自定义命令直接继承
LoggingBaseCommand即可,不会影响migrate等Django自带命令的输出行为。
内容的提问来源于stack exchange,提问作者Zuerst
相关产品推荐
相关产品推荐

