Flask-Log-Request-Id is an extension for Flask that can parse and handle the request-id sent by request processors like Amazon ELB, Heroku Request-ID or any multi-tier infrastructure as the one used at microservices. A common usage scenario is to inject the request_id in the logging system so that all log records, even those emitted by third party libraries, have attached the request_id that initiated their call. This can greatly improve tracing and debugging of problems.
The easiest way to install it is using pip
from PyPI
pip install flask-log-request-id
Flask-Log-Request-Id provides the current_request_id()
function which can be used at any time to get the request id of the initiated execution chain.
from flask_log_request_id import RequestID, current_request_id [...] RequestID(app) @app.route('/') def hello(): print('Current request id: {}'.format(current_request_id()))
In the following example, we will use the RequestIDLogFilter
to inject the request id on all log events, and a custom formatter to print this information. If all these sounds unfamiliar please take a look at python's logging system
import logging import logging.config from random import randint from flask import Flask from flask_log_request_id import RequestID, RequestIDLogFilter def generic_add(a, b): """Simple function to add two numbers that is not aware of the request id""" logging.debug('Called generic_add({}, {})'.format(a, b)) return a + b app = Flask(__name__) RequestID(app) # Setup logging handler = logging.StreamHandler() handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - level=%(levelname)s - request_id=%(request_id)s - %(message)s")) handler.addFilter(RequestIDLogFilter()) # << Add request id contextual filter logging.getLogger().addHandler(handler) @app.route('/') def index(): a, b = randint(1, 15), randint(1, 15) logging.info('Adding two random numbers {} {}'.format(a, b)) return str(generic_add(a, b))
The above will output the following log entries:
2017-07-25 16:15:25,912 - __main__ - level=INFO - request_id=7ff2946c-efe0-4c51-b337-fcdcdfe8397b - Adding two random numbers 11 14 2017-07-25 16:15:25,913 - __main__ - level=DEBUG - request_id=7ff2946c-efe0-4c51-b337-fcdcdfe8397b - Called generic_add(11, 14) 2017-07-25 16:15:25,913 - werkzeug - level=INFO - request_id=None - 127.0.0.1 - - [25/Jul/2017 16:15:25] "GET / HTTP/1.1" 200 -
Flask-Log-Request-Id comes with extras to forward the context of current request_id to the workers of celery tasks. In order to use this feature you need to enable the celery plugin and configure the Celery
instance. Then you can use current_request_id()
from inside your worker
from flask_log_request_id.extras.celery import enable_request_id_propagation from flask_log_request_id import current_request_id from celery.app import Celery import logging celery = Celery() enable_request_id_propagation(celery) # << This step here is critical to propagate request-id to workers app = Flask() @celery.task() def generic_add(a, b): """Simple function to add two numbers that is not aware of the request id""" logging.debug('Called generic_add({}, {}) from request_id: {}'.format(a, b, current_request_id())) return a + b @app.route('/') def index(): a, b = randint(1, 15), randint(1, 15) logging.info('Adding two random numbers {} {}'.format(a, b)) return str(generic_add.delay(a, b)) # Calling the task here, will forward the request id to the workers
You can follow the same logging strategy for both web application and workers using the RequestIDLogFilter
as shown in example 1 and 2.
This will be useful while integrating with frontend where in you can get the request id from the response (be it 400 or 500) and then trace the request in logs.
from flask_log_request_id import current_request_id @app.after_request def append_request_id(response): response.headers.add('X-REQUEST-ID', current_request_id()) return response
The following parameters can be configured through Flask's configuration system:
Configuration Name | Description |
---|---|
LOG_REQUEST_ID_GENERATE_IF_NOT_FOUND | In case the request does not hold any request id, the extension will generate one. Otherwise current_request_id will return None. |
LOG_REQUEST_ID_LOG_ALL_REQUESTS | If True, it will emit a log event at the request containing all the details as werkzeug would done along with the request_id . |
LOG_REQUEST_ID_G_OBJECT_ATTRIBUTE | This is the attribute of Flask.g object to store the current request id. Should be changed only if there is a problem. Use current_request_id() to fetch the current id. |
See the LICENSE file for license rights and limitations (MIT).