Logging is a very important feature and requirement while we are working on any type of project, either small or large. Because with the help of log messages, we could identify the issue in running applications and could solve it with less effort.
Python came up with the default logging module that we could use to implement logging in python applications such as core python project/ flask project etc.
For example:
import logging logger = logging.getLogger(testproject) or logger = logging.getLogger() logger.info(‘This is info level message’) logger.error(‘This is error level message’) logger.warning(‘This is warning level message’) logger.debug(‘This is debug level message’)
But sometimes, we need custom implementations:
- Such as, instead of writing messages on console, we want to write messages on logging files.
- Might need to log additional information to each log file
- Might need to file rotation of logs file
- Might need to apply custom filter etc.
So, here I am sharing, like how we can achieve the above points within the Flask project.
Let’s suppose your project structure is:
- Project-Folder
- app
- __init__.py
- moduleA
- moduleB
- config
- __init__.py
- default.py
- deployment.py
- production.py
- Instance
- default.py
- development.py
- main.py
- uwsgi.py
- Requirments.txt
- gitignore
- app
Step 1: Let’s create a logger_mod.py file under your project root folder.
- Project-Folder
- logger_mod.py
Step 2: Define your custom filter that will add additional information to each log.
class CustomFilter(logging.Filter): def filter(self, record): record.appName = 'my-application-name' return True
Step 3: Define your logging dictConfig structure
logging_configuration = { 'version': 1, "disable_existing_loggers": False, 'formatters': { 'default': { 'format': '[%(asctime)s] %(levelname)s - APP:%(appName)s - MODULE:%(module)s - FUNCTION:%(funcName)s - LINE:%(lineno)d : %(message)s', } }, 'filters': { 'additional': { '()': CustomFilter } }, 'handlers': { 'console': { 'class': 'logging.StreamHandler', 'formatter': 'default', 'level': 'INFO', 'stream': 'ext://sys.stdout' }, "info_file": { "class": "logging.handlers.RotatingFileHandler", "formatter": "default", "filename": app.config['APPLICATION_LOG_PATH'] + "/info.log", "maxBytes": 10000, "backupCount": 10, "delay": "True", 'level': 'INFO', }, "error_file": { "class": "logging.handlers.RotatingFileHandler", "formatter": "default", "filename": app.config['APPLICATION_LOG_PATH'] + "/error.log", "maxBytes": 10000, "backupCount": 10, "delay": "True", 'level': 'ERROR', } }, 'loggers': { 'testProject': { 'handlers': ['console', 'info_file', 'error_file'], 'level': 'INFO', 'filters': ['additional'], 'propagate': False } } }
Step 4: Configure custom logging to project
def setup_logging(): # Create a logs folder if it does not exist. if not os.path.exists(app.config['APPLICATION_LOG_PATH']): os.makedirs(app.config['APPLICATION_LOG_PATH']) dictConfig(logging_configuration) # Disable flask internal logger. logging.getLogger('werkzeug').disabled = True
Step 4: Apply custom logging to the project. Flask main.py file as above structure.
import os # Set configuration environment variable, to load defined config. os.environ['APP_CONFIG_FILE'] = 'development.py' from app import app as application from logging_setup import setup_logging if __name__ == "__main__": setup_logging() application.run(debug=True, host='0.0.0.0', port=5000)
Final code that you need to apply as file wise:
#### logger_mod.py import os import logging from logging.config import dictConfig from app import app class CustomFilter(logging.Filter): def filter(self, record): record.appName = 'my-application-name' return True logging_configuration = { 'version': 1, "disable_existing_loggers": False, 'formatters': { 'default': { 'format': '[%(asctime)s] %(levelname)s - APP:%(appName)s - MODULE:%(module)s - FUNCTION:%(funcName)s - LINE:%(lineno)d : %(message)s', } }, 'filters': { 'additional': { '()': CustomFilter } }, 'handlers': { 'console': { 'class': 'logging.StreamHandler', 'formatter': 'default', 'level': 'INFO', 'stream': 'ext://sys.stdout' }, "info_file": { "class": "logging.handlers.RotatingFileHandler", "formatter": "default", "filename": app.config['APPLICATION_LOG_PATH'] + "/info.log", "maxBytes": 10000, "backupCount": 10, "delay": "True", 'level': 'INFO', }, "error_file": { "class": "logging.handlers.RotatingFileHandler", "formatter": "default", "filename": app.config['APPLICATION_LOG_PATH'] + "/error.log", "maxBytes": 10000, "backupCount": 10, "delay": "True", 'level': 'ERROR', } }, 'loggers': { 'testProject': { 'handlers': ['console', 'info_file', 'error_file'], 'level': 'INFO', 'filters': ['additional'], 'propagate': False } } } def setup_logging(): # Create logs folder if does not exist. if not os.path.exists(app.config['APPLICATION_LOG_PATH']): os.makedirs(app.config['APPLICATION_LOG_PATH']) dictConfig(logging_configuration) # Disable flask internal logger. logging.getLogger('werkzeug').disabled = True #### main.py import os # Set configuration environment variable, to load defined config. os.environ['APP_CONFIG_FILE'] = 'development.py' from app import app as application from logging_setup import setup_logging if __name__ == "__main__": setup_logging() application.run(debug=True, host='0.0.0.0', port=5000) ### test.py import logging logger = logging.getLogger('testProject') logger.info(‘This is info level message’) logger.error(‘This is error level message’)