Bootstrap FreeKB - Flask - dictConfig logger
Flask - dictConfig logger

Updated:   |  Flask articles

Flask uses the MVC (Model View Controller) Framework. Just to make this as obvious as possible, I like my Flask apps to have the following.

  • Model -> models.py
  • View -> views.py
  • Controller -> __init__.py

Let's say your Flask app has a structure like this.

├── main.py
├── my-project (directory)
│   ├── __init__.py
│   ├── home.py
│   ├── foo.py
│   ├── bar.py
│   ├── templates (directory)
│   │   ├── base.html
│   │   ├── home.html
│   │   ├── foo.html
│   │   ├── bar.html

 

And here is a basic example of how to use logging in Flask.

Add the following to __init__.py.

from flask import Flask

def app():
    app = Flask(__name__)
    from .views import views
    app.register_blueprint(views, url_prefix='/')

    return app

 

Add the following to views.py.

from flask import Blueprint
import logging

views  = Blueprint('views', __name__)
logger = logging.getLogger(__name__)

@views.route('/Stage')
def Stage():
    logger.info("Hello World")
    return "I am here"

 

Add the following to main.py.

from website import app <- this line looks for a function named "app" in __init__.py

app = app()

if __name__ == '__main__':
    app.run(debug=True)

 

For example, if running your Flask app in VSCode, you should see the log output in the console.

 

Now let's say you want more fine tuned control over the logger. This is where logging.config comes in handy. In this example, the format and log level is defined in __init__.py.

from flask import Flask
import logging.config

def my_logger():
    LOGGING_CONFIG = { 
        'version': 1,
        'disable_existing_loggers': True,
        'formatters': { 
            'standard': { 
                'format': '%(asctime)s [%(levelname)s]: %(message)s',
                'datefmt': '%Y/%m/%d %H:%M:%S',            
            }      
        },
        'handlers': { 
            'default': { 
                'level': 'WARNING',
                'formatter': 'standard',
                'class': 'logging.StreamHandler',
                'stream': 'ext://sys.stdout'
            }        
        },
        'loggers': { 
            '': {
                'handlers': ['default']
            }
        }   
    }

    logging.config.dictConfig(LOGGING_CONFIG)
    logger = logging.getLogger(__name__)
    return logger

def app():
    app = Flask(__name__)
    from .views import views
    app.register_blueprint(views, url_prefix='/')

    return app

 

Add then views.py imports my_logger.

from flask import Blueprint
from . import my_logger

views  = Blueprint('views', __name__)
logger = my_logger()

@views.route('/Stage')
def Stage():
    logger.info("Hello World")
    return "I am here"

 

And here is an example of logger in __init__.py with both a console handler and log file handler, so that when something like logging.info("Hello World") is used, then "Hello World" will be written to a log file, but the normal requests events such as GET /Stage HTTP/1.1 will NOT be appended to the log file, making the log file much cleaner, only containing the events you create with logging.info(). It's a good idea to use RotatingFileHandler.

from flask import Flask
import logging.config


def my_logger():

    if os == 'Windows':
        log_file = r"C:\Users\johndoe\my.log"
    else:
        log_file = "/var/log/my.log"

    LOGGING_CONFIG = { 
        'version': 1,
        'disable_existing_loggers': True,
        'formatters': { 
            'standard': { 
                'format': '%(asctime)s.%(msecs)03d [%(levelname)s]: %(message)s',
                'datefmt': '%Y-%m-%d %H:%M:%S',            
            },        
        },
        'handlers': { 
            'console': { 
                'level': 'INFO',
                'formatter': 'standard',
                'class': 'logging.StreamHandler',
                'stream': 'ext://sys.stdout'
            },       
            'filelogger': { 
                'level': 'INFO',
                'formatter': 'standard',
                'class': 'logging.handlers.RotatingFileHandler',
                "filename": log_file,
                'mode': 'a',
                'maxBytes': 10000000,
                'backupCount': 5,
            },        
        },
        'loggers': { 
            '': { 
                'handlers': ['console']
            },
            'filelogger': { 
                'handlers': ['filelogger']
            }   
        }   
    }

    logging.config.dictConfig(LOGGING_CONFIG)
    logger = logging.getLogger('filelogger')
    return logger

def app():
    app = Flask(__name__)
    from .views import views
    app.register_blueprint(views, url_prefix='/')

    return app

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter dccb8a in the box below so that we can be sure you are a human.