为什么在 运行 带有 werkzeug 的 Flask 应用程序时日志记录不起作用?
Why does logging not work when running a Flask app with 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
文件中。我假设 DispatcherMiddleware
或 run_simple
在记录异常之前以某种方式捕获了异常。如果我 运行 只有 app
实例使用 app.run()
错误记录工作正常。
我找到了一个 gist,它讨论了在 Flask 中登录。 andyxning 的评论(评论于 2015 年 4 月 18 日)提到了这一点 - if app.debug is True then all log level above DEBUG will be logged to stderr(StreamHandler)
。
评论还有一个link到flask/logging.py的源代码。 create_logger
方法创建了一个 DebugHandler
的实例,它继承自 StreamHandler
class.
如果你打印app.logger.handlers
你可以看到它有一个对象flask.logging.DebugHandler
。
print app.logger.handlers
[<flask.logging.DebugHandler object at 0x110315090>]
此 DebugHandler 可能在 app.debug is set to true
时使用,因此堆栈跟踪会打印在控制台上。
希望这就是您要找的。
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: explicitly enable or disable the propagation of exceptions. If not set or explicitly set to None this is implicitly true if either TESTING or DEBUG is true.
所以,我设法让 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
这里是一个复制粘贴示例,可重现该问题。
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
文件中。我假设 DispatcherMiddleware
或 run_simple
在记录异常之前以某种方式捕获了异常。如果我 运行 只有 app
实例使用 app.run()
错误记录工作正常。
我找到了一个 gist,它讨论了在 Flask 中登录。 andyxning 的评论(评论于 2015 年 4 月 18 日)提到了这一点 - if app.debug is True then all log level above DEBUG will be logged to stderr(StreamHandler)
。
评论还有一个link到flask/logging.py的源代码。 create_logger
方法创建了一个 DebugHandler
的实例,它继承自 StreamHandler
class.
如果你打印app.logger.handlers
你可以看到它有一个对象flask.logging.DebugHandler
。
print app.logger.handlers
[<flask.logging.DebugHandler object at 0x110315090>]
此 DebugHandler 可能在 app.debug is set to true
时使用,因此堆栈跟踪会打印在控制台上。
希望这就是您要找的。
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: explicitly enable or disable the propagation of exceptions. If not set or explicitly set to None this is implicitly true if either TESTING or DEBUG is true.
所以,我设法让 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