I want to create a middleware function in Flask that logs details from the request and the response. The middleware should run after the Response is created, but before it is sent back. I want to log:
GET
, POST
, or PUT
)Some options I've found (that don't quite work for me):
before_request
and after_request
decorators. If I could access the request data in after_request
, my problems still won't be solved, because according to the documentationIf a function raises an exception, any remaining
after_request
functions will not be called.
after_this_request
decorator described on this page, which decorates an arbitrary function (defined inside the current view function) and registers it to run after the current request. Since the arbitrary function can have info from both the request and response in it, it partially solves my problem. The catch is that I would have to add such a decorated function to every view function; a situation I would very much like to avoid.@app.route('/') def index(): @after_this_request def add_header(response): response.headers['X-Foo'] = 'Parachute' return response return 'Hello World!'
Any suggestions?
My first answer is very hacky. There's actually a much better way to achieve the same result by making use of the g object
in Flask. It is useful for storing information globally during a single request. From the documentation:
The g name stands for “global”, but that is referring to the data being global within a context. The data on g is lost after the context ends, and it is not an appropriate place to store data between requests. Use the session or a database to store data across requests.
This is how you would use it:
@app.before_request
def gather_request_data():
g.method = request.method
g.url = request.url
@app.after_request
def log_details(response: Response):
g.status = response.status
logger.info(f'method: {g.method}\n url: {g.url}\n status: {g.status}')
return response
@app.before_request
and store it in the g
object.@app.after_request
. You can still refer to the information you stored in the g
object from step 1. Note that you'll have to return the response at the end of this function.