如何使用flask中的请求信息丰富日志消息?

Pat*_*ick 4 python logging flask

我有一个像 REST API 一样使用的小型 Flask 应用程序,它实现了许多这样的方法:

@route('/do/something', methods=['POST'])
def something():
    app.logger.debug("got request to /do/something")
    result = something_implementation(request.json())
    app.logger.debug("result was %s", str(result))
    return flask.Response(result)
Run Code Online (Sandbox Code Playgroud)

我想用来自请求对象的信息自动丰富这些日志消息,例如标头信息、正文部分以及其他任何方便的信息。

我如何以优雅和 Pythonic 的方式做到这一点?

当然,我可以将 app.logger 包装在我自己的函数中并传递请求对象和消息,但必须有一种更好、更简单的方法,我错过了。

Las*_*sus 7

我通常在我的 app.py 文件中包含这样的内容来记录每个请求的调试信息,以及处理标准错误:

# Useful debugging interceptor to log all values posted to the endpoint
@app.before_request
def before():
    values = 'values: '
    if len(request.values) == 0:
        values += '(None)'
    for key in request.values:
        values += key + ': ' + request.values[key] + ', '
    app.logger.debug(values)

# Useful debugging interceptor to log all endpoint responses
@app.after_request
def after(response):
    app.logger.debug('response: ' + response.status + ', ' + response.data.decode('utf-8'))
    return response

# Default handler for uncaught exceptions in the app
@app.errorhandler(500)
def internal_error(exception):
    app.logger.error(exception)
    return flask.make_response('server error', 500)

# Default handler for all bad requests sent to the app
@app.errorhandler(400)
def handle_bad_request(e):
    app.logger.info('Bad request', e)
    return flask.make_response('bad request', 400)v
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你。我已经有类似的东西,但这还不够,我需要记录处理请求时发生的事情。看起来我需要实现一个自定义过滤器:https://docs.python.org/2/howto/logging-cookbook.html#using-filters-to-impart-contextual-information 我只需要找出如何从此过滤器访问当前请求上下文。 (2认同)

Pat*_*ick 6

我已经通过子类化logging.Filter并将其添加到我的处理程序中解决了这个问题。

像这样的东西:

class ContextFilter(logging.Filter):
    '''Enhances log messages with contextual information'''
    def filter(self, record):
        try:
            record.rid = request.rid
        except RuntimeError as exc:
            if str(exc.message) == 'working outside of request context':
                record.rid = ''
            else:
                raise exc
        return True
Run Code Online (Sandbox Code Playgroud)

try/except 子句是请求上下文之外的日志消息工作所必需的。然后像这样使用它:

fileHandler = RotatingFileHandler(app.config['LOGFILE'], maxBytes=20971520,
                                  backupCount=5, encoding='utf-8')
fileHandler.setLevel(logging.DEBUG)
fileHandler.addFilter(ContextFilter())
filefmt = '%(asctime)s [%(filename)s:%(lineno)d] %(rid)s: %(message)s'
fileFormatter = logging.Formatter(filefmt)
fileHandler.setFormatter(fileFormatter)
app.logger.addHandler(fileHandler)
Run Code Online (Sandbox Code Playgroud)

将来我可以在ContextFilter.filter()方法中添加更多字段并在格式化程序配置中使用它们。