为什么不深入研究代码并查看...
我们登陆的模块是flask.logging.py
,它定义了一个名为 的函数create_logger(app)
。在使用 Flask 解决日志记录问题时,检查该函数将提供一些潜在罪魁祸首的线索。
编辑:此答案适用于版本 1 之前的 Flask flask.logging.py
。从那时起,该模块发生了很大变化。答案仍然有助于解决有关 python 日志记录的一些一般警告和建议,但请注意 Flask 在这方面的一些特性已在版本 1 中得到解决,可能不再适用。
该函数中第一个可能的冲突原因是这一行:
logger = getLogger(app.logger_name)
让我们看看为什么:
该变量app.logger_name
在Flask.__init__()
方法中设置为 的值import_name
,它本身就是 的接收参数Flask(__name__)
。这被app.logger_name
分配了 的值__name__
,这可能是你的主包的名称,让我们在这个例子中称它为'awesomeapp'。
现在,假设您决定手动配置和创建自己的记录器。你认为如果你的项目被命名为“awesomeapp”你也会使用这个名字来配置你的记录器,我认为这很有可能。
my_logger = logging.getLogger('awesomeapp') # doesn't seem like a bad idea
fh = logging.FileHandler('/tmp/my_own_log.log')
my_logger.setLevel(logging.DEBUG)
my_logger.addHandler(fh)
这样做是有道理的……除了一些问题。
当Flask.logger
第一次调用该属性时,它会依次调用该函数flask.logging.create_logger()
,并且会执行以下操作:
logger = getLogger(app.logger_name)
还记得您如何在项目之后命名您的记录器以及如何app.logger_name
共享该名称吗?上面的代码行中发生的事情是,该函数logging.getLogger()
现在已经检索了您之前创建的记录器,并且以下说明将会以一种让您稍后摸不着头脑的方式来处理它。例如
del logger.handlers[:]
噗,您刚刚丢失了之前在记录器中注册的所有处理程序。
函数内发生的其他事情,无需过多介绍。它创建并注册两个logging.StreamHandler
可以吐出到sys.stderr
和/或Response
对象的对象。一个用于日志级别“调试”,另一个用于“生产”。
class DebugLogger(Logger):
def getEffectiveLevel(self):
if self.level == 0 and app.debug:
return DEBUG
return Logger.getEffectiveLevel(self)
class DebugHandler(StreamHandler):
def emit(self, record):
if app.debug and _should_log_for(app, 'debug'):
StreamHandler.emit(self, record)
class ProductionHandler(StreamHandler):
def emit(self, record):
if not app.debug and _should_log_for(app, 'production'):
StreamHandler.emit(self, record)
debug_handler = DebugHandler()
debug_handler.setLevel(DEBUG)
debug_handler.setFormatter(Formatter(DEBUG_LOG_FORMAT))
prod_handler = ProductionHandler(_proxy_stream)
prod_handler.setLevel(ERROR)
prod_handler.setFormatter(Formatter(PROD_LOG_FORMAT))
logger.__class__ = DebugLogger
logger.addHandler(debug_handler)
logger.addHandler(prod_handler)
有了上面的细节,我们应该更清楚为什么我们手动配置的记录器和处理程序在涉及 Flask 时行为不端。不过,新信息为我们提供了新的选择。如果您仍想保留单独的处理程序,最简单的方法是将您的记录器命名为与项目不同的名称(例如my_logger = getLogger('awesomeapp_logger')
)。如果您想与 Flask 中的日志记录协议保持一致,另一种方法是使用与 Flask 类似的方法注册一个logging.FileHandler
对象。Flask.logger
import logging
def set_file_logging_handler(app):
logging_path = app.config['LOGGING_PATH']
class DebugFileHandler(logging.FileHandler):
def emit(self, record):
# if your app is configured for debugging
# and the logger has been set to DEBUG level (the lowest)
# push the message to the file
if app.debug and app.logger.level==logging.DEBUG:
super(DebugFileHandler, self).emit(record)
debug_file_handler = DebugFileHandler('/tmp/my_own_log.log')
app.logger.addHandler(debug_file_handler)
app = Flask(__name__)
# the config presumably has the debug settings for your app
app.config.from_object(config)
set_file_logging_handler(app)
app.logger.info('show me something')