In Python project, good logs is very essentail not only for debugging but also to provide insight to avoid issue and improve performance. In this articles, I will discuss the best practises for logging with Python and provide some code sample in 3 logging methods.
The log level corresponds to the “importance” a log is given: an “error” log should be more urgent then than the “warn” log, whereas a “debug” log should be useful only when debugging the application.
There are six log levels in Python; each level is associated with an integer that indicates the log severity:
import logging
logging.debug('debug message.')
logging.info('informational message.')
logging.debug('message for debugging purposes.')
logging.warning('warning!')
logging.critical('critial!')
The main components of the logging module are loggers, handlers, and formatters.
Programmers can configure logging in three ways:
Creating loggers, handlers, and formatters explicitly using Python code that calls the configuration methods listed above.
Creating a logging config file and reading it using the fileConfig() function.
Creating a dictionary of configuration information and passing it to the dictConfig() function.
import os
import logging
from datetime import datetime
def create_logging():
""" Create logging """
logs_folder = 'logs/'
if not os.path.exists(logs_folder):
os.makedirs(logs_folder)
log_dir = logs_folder + str(datetime.now().strftime('logfile_ws02_%Y%m%d.log'))
logging.basicConfig(filename=log_dir,
level=logging.INFO,
format='%(asctime)s | %(name)s | %(levelname)s | %(message)s')
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s | %(name)s | %(levelname)s | %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
logging.info('Started')
logging.info('Log file : ' + str(log_dir))
create_logging()
logging.debug('debug message.')
logging.info('informational message.')
logging.debug('message for debugging purposes.')
logging.warning('warning!')
logging.critical('critial!')
2020-09-18 04:08:34,780 | root | INFO | Started
2020-09-18 04:08:34,781 | root | INFO | Log file : logs/logfile_ws02_20200918.log
2020-09-18 04:08:34,784 | root | INFO | informational message.
2020-09-18 04:08:34,787 | root | WARNING | warning!
2020-09-18 04:08:34,789 | root | CRITICAL | critial!
Creating a logging config file and reading it using the fileConfig() function.
[loggers]
keys=root
[handlers]
keys=fileHandler, consoleHandler
[formatters]
keys=logFormatter, consoleFormatter
[logger_root]
handlers=fileHandler, consoleHandler
level=NOTSET
[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=consoleFormatter
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=logFormatter
args=(__import__("datetime").datetime.now().strftime('logs/logfile_%%Y%%m%%d.log'), 'a')
[formatter_logFormatter]
format=%(asctime)s | %(name)s | %(levelname)-8s | %(lineno)04d | %(message)s
[formatter_consoleFormatter]
format=%(asctime)s | %(levelname)-8s | %(message)s
import logging
from datetime import datetime
import logging.config
logging.config.fileConfig('logging.conf')
# create logger
logger = logging.getLogger('log-test')
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
logfile_20200829.log
2020-08-29 22:52:13,443 | log-test | DEBUG | 0013 | debug message
2020-08-29 22:52:13,443 | log-test | INFO | 0014 | info message
2020-08-29 22:52:13,443 | log-test | WARNING | 0015 | warn message
2020-08-29 22:52:13,443 | log-test | ERROR | 0016 | error message
2020-08-29 22:52:13,443 | log-test | CRITICAL | 0017 | critical message
import logging
import logging.config
from datetime import datetime
LOGGING_CONFIG = {
'version': 1,
'loggers': {
'': { # root logger
'level': 'NOTSET',
'handlers': ['fileHandler', 'consoleHandler'],
},
'handler_fileHandler': {
'level': 'WARNING',
'propagate': False,
'handlers': ['fileHandler', 'consoleHandler' ],
},
},
'handlers': {
'consoleHandler': {
'level': 'INFO',
'formatter': 'formatter_consoleFormatter',
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
},
'fileHandler': {
'level': 'NOTSET',
'formatter': 'formatter_logFormatter',
'class': 'logging.FileHandler',
'filename': datetime.now().strftime('logs/logfile_%Y%m%d.log'),
'mode': 'a'
}
},
'formatters': {
'formatter_logFormatter': {
'format': '%(asctime)s | %(name)s | %(levelname)-8s | %(lineno)04d | %(message)s'
},
'formatter_consoleFormatter': {
'format': '%(asctime)s | %(levelname)-8s | %(message)s'
},
},
}
# Run once at startup:
logging.config.dictConfig(LOGGING_CONFIG)
# Include in each module:
logger = logging.getLogger('test-log')
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')