Simon Melouah
Simon Melouah

Reputation: 652

Python Flask log request body through all modules

I'm trying to log the request body of an incoming post request and persist it across all modules being called in the function thereafter. Here's an example of what I'm trying to achieve:

main_app.py

from flask import Flask
from other_file import other_module
import logging

FORMAT = '%(request_body_id)s- %(message)s'
logging.basicConfig(format=FORMAT)
log = logging.getLogger('test_logger')
@app.route('/', methods=['POST'])
def test_function():
   log = logging.LoggerAdapter(log, {'request_body_id': request.body['id']})
   log.info("My message")
   other_module()
   return "foo"

other_file.py

log = logging.getLogger('test_logger')
def other_module():
   log.info("My second message")

What I'm looking for is:

>>> INFO 123456- My message
>>> INFO 123456- My second message

What I get is:

>>> INFO 123456- My message
>>> INFO - My second message

Update: Passing the request body as a parameter to other_module is not an option as there are tonnes of modules being called in the real case that need to output the request source.

Upvotes: 2

Views: 3471

Answers (1)

Danila Ganchar
Danila Ganchar

Reputation: 11223

You can add any additional data into log using logging.Formatter. Just an example:

log.py

import logging
from flask import request


class __RequestFormatter(logging.Formatter):

    def format(self, record):
        # you can set here everything what you need
        # I just added url and id from GET parameter
        record.id = request.args.get('id')
        record.url = request.url
        return super().format(record)

# format of our log record.
# print url and id of record which was set in format()
__stream_handler = logging.StreamHandler()
__stream_handler.setFormatter(__RequestFormatter(
    '[%(asctime)s %(levelname)s] requested: %(url)s, id: %(id)s in %(module)s: %(message)s'
))

logger = logging.getLogger('my_loger')
logger.setLevel(logging.INFO)
logger.addHandler(__stream_handler)

app.py

from flask import Flask

from log import logger
from other_file import other_module

app = Flask(__name__)


@app.route('/test')
def test():
    logger.info('/test was called')
    other_module()
    return 'hi'

other_file.py

from log import logger


def other_module():
   logger.info("My second message")

Now let's call /test?id=example_id, /test?id=example_id2 and check logs:

[2018-09-28 17:40:48,669 INFO] requested: http://127.0.0.1:5000/test?id=example_id, id: example_id in app: /test was called
[2018-09-28 17:40:48,670 INFO] requested: http://127.0.0.1:5000/test?id=example_id, id: example_id in other_file: My second message

[2018-09-28 17:40:51,475 INFO] requested: http://127.0.0.1:5000/test?id=example_id2, id: example_id2 in app: /test was called
[2018-09-28 17:40:51,476 INFO] requested: http://127.0.0.1:5000/test?id=example_id2, id: example_id2 in other_file: My second message

As you can see all messages include id of request. So you can use Formatter to customize everything what you need. Also you can try to use flask-log-request-id.

Hope this helps.

Upvotes: 1

Related Questions