Formatting Flask app logs in json

9.9k views Asked by At

I'm working with a Python/Flask application and trying to get the logs to be formatted (by line) in json.

Using the python-json-logger package, I've modified the formatter for the app.logger as follows:

from pythonjsonlogger import jsonlogger
formatter = jsonlogger.JsonFormatter(
    '%(asctime) %(levelname) %(module) %(funcName) %(lineno) %(message)')
app.logger.handlers[0].setFormatter(formatter)

This works as expected. Any messages passed to app.logger are correctly formatted in json.

However the application is also automatically logging all requests. This information shows up in stdout as follows:

127.0.0.1 - - [19/Jun/2015 12:22:03] "GET /portal/ HTTP/1.1" 200 -

I want this information to be formatted in json as well. I've been looking for the logger/code that is responsible for creating this output with no success.

Where is this output generated? Are the mechanisms to change the formatting of this logged information?

2

There are 2 answers

0
Martijn Pieters On

When you use the app.logger attribute for the first time, Flask sets up some log handlers:

  • a debug logger that is set to log level DEBUG and that filters on app.debug being true.
  • a production logger that is set to ERROR.

You can remove those handlers again yourself, by running:

app.logger.handlers[:] = []

However, the log line you see is not logged by Flask, but by the WSGI server. Both the built-in Werkzeug server (used when you use app.run()) and various other WSGI servers do this. Gunicorn for example uses the default Python logger to record access.

The built-in WSGI server should never be used in production (it won't scale well, and is not battle-hardened against malicious attackers).

For Gunicorn, you can disable log propagation to keep the logging separate:

logging.getLogger('gunicorn').propagate = False
0
Caner On

Flask internally uses werkzeug server. Those logs are printed by it, not flask. You can access to werkzeug logger with logging.getLogger('werkzeug') and configure as you wish. For example:

werkzeug = logging.getLogger('werkzeug')
if len(werkzeug.handlers) == 1:
    formatter = logging.Formatter('%(message)s', '%Y-%m-%d %H:%M:%S')
    werkzeug.handlers[0].setFormatter(formatter)