使用werkzeug运行Flask应用程序时,为什么日志记录不起作用?

时间:2016-09-22 18:20:56

标签: python flask wsgi werkzeug

所以这是一个复制粘贴示例,可以重现问题。

import logging

from flask import Flask
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware

def app_builder(app_name, log_file):

    app = Flask(app_name)
    app.debug = True

    handler = logging.FileHandler(log_file)
    handler.setLevel(logging.DEBUG)
    app.logger.addHandler(handler)

    return app

def _simple(env, resp):
    resp(b'200 OK', [(b'Content-Type', b'text/plain')])
    return [b'root']

if __name__ == "__main__":

    app = app_builder(app_name='app', log_file='app.log')

    @app.route('/')
    def index():
        return '<a href="/app/error">click for error</a>'

    @app.route('/error')
    def error():
        1/0
        return 'error page'

    app2 = app_builder(app_name='app2', log_file='app2.log')

    @app2.route('/')
    def index():
        return 'you are getting responses from app2'

    app.debug = True
    app2.debug = True

    application = DispatcherMiddleware(_simple, {
        '/app':     app,
        '/app2':    app2
        })

    run_simple(hostname='localhost',
               port=5000,
               application=application,
               use_reloader=True,
               use_debugger=True)

要显示错误导航到http://localhost:5000/app/error,我想知道为什么堆栈跟踪不会显示在app.log文件中。我假设DispatcherMiddlewarerun_simple以某种方式捕获异常,然后才能记录它。如果我使用app仅运行app.run()实例,则错误记录工作正常。

2 个答案:

答案 0 :(得分:1)

我找到了gist,其中谈到了登录烧瓶。 andyxning的评论(2015年4月18日评论)提到了这一点 - if app.debug is True then all log level above DEBUG will be logged to stderr(StreamHandler)

评论还有一个指向flask/logging.py源代码的链接。 create_logger方法创建DebugHandler的实例,该实例继承自StreamHandler类。

如果您打印app.logger.handlers,则可以看到它的对象为flask.logging.DebugHandler

print app.logger.handlers
[<flask.logging.DebugHandler object at 0x110315090>]

这个DebugHandler可能在app.debug is set to true时使用,因此堆栈跟踪会在控制台上打印出来。

希望这就是你要找的东西。

答案 1 :(得分:1)

app.debug = True时不会调用正常的异常处理程序。看着 在Flask的app.py代码中:

def log_exception(self, exc_info):
    """Logs an exception.  This is called by :meth:`handle_exception`
    if debugging is disabled and right before the handler is called.
    ^^^^^^^^^^^^^^^^^^^^^^^^
    The default implementation logs the exception as error on the
    :attr:`logger`.

确实,在设置app.debug = True时,设置了异常传播 显式为True,阻止调用log_exception。以下是文档的摘录(重点是我的):

  

PROPAGATE_EXCEPTIONS:显式启用或禁用异常传播。如果没有设置或明确设置为无,如果TESTING或 DEBUG为真,则隐式为真

所以,我设法让werkzeug调试和日志记录工作愉快 以及一些小调整和以下代码:

import logging

from flask import Flask
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
## NEW CODE HERE
import functools
from flask._compat import reraise

def my_log_exception(exc_info, original_log_exception=None):
    original_log_exception(exc_info)
    exc_type, exc, tb = exc_info
    # re-raise for werkzeug
    reraise(exc_type, exc, tb)
## 

def app_builder(app_name, log_file):
    app = Flask(app_name)
    app.debug = True
    app.config.update(PROPAGATE_EXCEPTIONS=False)

    handler = logging.FileHandler(log_file)
    handler.setLevel(logging.DEBUG)
    app.logger.addHandler(handler)

    ## NEW CODE
    app.log_exception = functools.partial(my_log_exception,  original_log_exception=app.log_exception)
    ##

    return app

# rest of your code is unchanged