一尘不染

如何将Flask出色的调试日志消息写入生产环境中的文件?

flask

我有一个Flask应用程序,该应用程序运行良好并会偶尔出现错误,当与debug=True以下命令一起运行时可见:

if __name__ == '__main__':
    app.run(debug=True)

我收到有用的错误消息,例如:

Traceback (most recent call last):
  File "./main.py", line 871, in index_route

KeyError: 'stateIIIII'

我在生产环境中运行应用程序时(使用Lighttpd + fastcgi)将这样的错误消息保存到文件中。

寻找不同的StackOverflow问题后(http://flask.pocoo.org/docs/errorhandling/,http://docs.python.org/2/library/logging.html等); Flask邮件列表;和一些博客,似乎没有简单的方法可以将所有重大错误消息发送到文件中-我需要使用Python日志记录模块自定义内容。所以我想出了以下代码。

在我的应用程序文件的顶部,我有各种导入,然后是:

app = Flask(__name__)

if app.debug is not True:   
    import logging
    from logging.handlers import RotatingFileHandler
    file_handler = RotatingFileHandler('python.log', maxBytes=1024 * 1024 * 100, backupCount=20)
    file_handler.setLevel(logging.ERROR)
    app.logger.setLevel(logging.ERROR)
    app.logger.addHandler(file_handler)

然后,我将每个路由的代码放入try / except语句中,并使用traceback找出错误来自哪一行,并显示一条不错的错误消息:

def some_route():
    try:
        # code for route in here (including a return statement)

    except:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        app.logger.error(traceback.print_exception(exc_type, exc_value, exc_traceback, limit=2))
        return render_template('error.html')

然后在文件末尾删除该debug=True语句。虽然我认为我不需要这样做,因为当应用程序在生产环境中运行时,它是由fastcgi服务器(?)运行的。我的应用程序代码的最后两行如下所示:

if __name__ == '__main__':
    app.run()

我正在努力使这个工作。我认为我管理的最好的方法是使用(app.logger.error(‘test message’))将一条错误日志消息保存在文件中,但是它只会打印一条消息。直接忽略在该错误之后立即记录另一个错误的尝试。


阅读 838

收藏
2020-04-07

共1个答案

一尘不染

我不知道为什么它不起作用,但是我可以说出它是怎么做的。

首先,你不需要设置app.logger的级别。因此删除此行app.logger.setLevel()

你想要保存异常并为每个视图返回错误页面。在任何地方编写此代码都是很多工作。Flask提供了一种执行此操作的方法。定义这样的错误处理程序方法。

    @app.errorhandler(500)
    def internal_error(exception):
        app.logger.error(exception)
        return render_template('500.html'), 500

每当视图引发异常时,都会调用此方法并将异常作为参数传递。Python日志记录提供了异常方法,该方法用于保存对异常的完整追溯。

由于这可以处理所有异常,因此你甚至无需将代码放在try / except块中。但是,如果你想在调用错误处理程序之前执行某些操作(例如,回滚会话或事务),请执行以下操作:

    try:
        #code
    except:
        #code
        raise

如果你希望为日志文件中的每个条目添加日期和时间,则可以使用以下代码(代替问题中提供的类似代码)。

if app.debug is not True:   
    import logging
    from logging.handlers import RotatingFileHandler
    file_handler = RotatingFileHandler('python.log', maxBytes=1024 * 1024 * 100, backupCount=20)
    file_handler.setLevel(logging.ERROR)
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    file_handler.setFormatter(formatter)
    app.logger.addHandler(file_handler)
2020-04-07