![](/base_images/jeremy.jpg)
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