Menu Close

Python Web Development with Flask — Logging and Config

Flask is a simple web framework written in Python.

In this article, we’ll look at how to develop simple Python web apps with Flask.

Logging

We can add logging into our Flask app.

For example, we can write:

from flask import Flask, abort
from logging.config import dictConfig

dictConfig({
    'version': 1,
    'formatters': {'default': {
        'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
    }},
    'handlers': {'wsgi': {
        'class': 'logging.StreamHandler',
        'stream': 'ext://flask.logging.wsgi_errors_stream',
        'formatter': 'default'
    }},
    'root': {
        'level': 'INFO',
        'handlers': ['wsgi']
    }
})
app = Flask(__name__)

@app.route('/')
def hello_world():
    app.logger.info('success')
    return 'hello'

to configure our logger and use it.

The dictConfig function lets us configure our logger.

version is an integer value representing the schema version.

formatters has the dictionary top construct a Formatter instance.

filters is a dict which each key is a filter id and each value is a dict describing how to configure the corresponding Filter instance.

handlers is a dict which each key is a handler ID and each value is a dict describing how to configure the corresponding Handler instance.

Injecting Request Information

We can create our own request formatter to add the data we want into our logging messages.

For example, we can write:

from flask import Flask, has_request_context, request
from flask.logging import default_handler
import logging

class RequestFormatter(logging.Formatter):
    def format(self, record):
        if has_request_context():
            record.url = request.url
            record.remote_addr = request.remote_addr
        else:
            record.url = None
            record.remote_addr = None
        return super().format(record)

formatter = RequestFormatter(
    '[%(asctime)s] %(remote_addr)s requested %(url)sn'
    '%(levelname)s in %(module)s: %(message)s'
)
default_handler.setFormatter(formatter)

app = Flask(__name__)

@app.route('/')
def hello_world():
    app.logger.error('error')
    return 'hello'

We create the RequestFormatter class that has the format method.

Inside it, we check if we’re making a request with the has_request_context function.

If it’s true , then we’re making a request.

Then we set the url of the request, and the remote_addr , which is the remote address of the request.

And then we return the formatted record.

Then we create a RequestFormatter instance to format the request data,.

And then we call setFormatter to use the formatter we created.

Since we logged an error in the hello_world function, we’ll see the error logged when we make a request to the route.

And we’ll see something like:

[2020-10-07 16:59:17,625] 127.0.0.1 requested http://localhost:5000/
ERROR in app: error

from the log.

Other Libraries

We can add our loggers with the addHandler method.

For example. we can write:

from flask import Flask, has_request_context, request
from flask.logging import default_handler
import logging

root = logging.getLogger()
root.addHandler(default_handler)
app = Flask(__name__)

@app.route('/')
def hello_world():
    app.logger.error('error')
    return 'hello'

to get the root logger by calling logging.getLogger() .

Then we call root.addHandler method to add the logger we want.

Configuration Basics

We can add our own configuration for our app.

For example, we can write:

from flask import Flask

app = Flask(__name__)
app.config['TESTING'] = True

@app.route('/')
def hello_world():
    return 'hello'

to add the TESTING config to our app.

Conclusion

We can add logging and configuration into our Flask app.

Posted in flask, Python