Here is a basic example of how to get started with logging.
#!/usr/bin/python3
import logging
logging.debug('debug message') # <- will NOT appear in console output
logging.info('info message') # <- will NOT appear in console output
logging.warning('warning message') # <- will appear in console output
logging.error('error message') # <- will appear in console output
logging.critical('critical message') # <- will appear in console output
Which should output the following.
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
Since logging is such a common task across nearly all of your Python scripts, it almost always makes sense to create a logging module that can be imported into your various Python scripts.
For example, if using Python version 2, here is what you could put into your logging module such as logger.py. This will always append events to a log file and optionally display the events on the console. This also includes os.path.dirname to get the absolute path the the directory that will contain the log file and os.makedirs to create the directory if it does not exit.
#!/usr/bin/python
import logging
from logging.handlers import RotatingFileHandler
import sys
def return_logger(log_file, console):
logger = logging.getLogger()
# Set Default Log Level
# DEBUG - print/log critical, error, warning, info, debug events
# INFO - print/log critical, error, warning, info events
# WARNING - print/log critical, error, warning events
# ERROR - print/log critical, error events
# CRITICAL - print/log critical events
logger.setLevel(logging.INFO)
format = logging.Formatter(fmt="[%(asctime)s %(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
dirname = os.path.dirname(log_file)
if not os.path.exists(dirname):
os.makedirs(dirname)
fileHandler = logging.FileHandler(log_file)
fileHandler = RotatingFileHandler(log_file, maxBytes=10000000, backupCount=10)
fileHandler.setFormatter(format)
logger.addHandler(fileHandler)
if console == True:
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(format)
logger.addHandler(consoleHandler)
return logger
def destroy_logger(logger):
handlers = logger.handlers[:]
for handler in handlers:
logger.removeHandler(handler)
handler.close()
And here is what you could have in your child Python scripts, where the logging module is imported, used and then destroyed.
#!/usr/bin/python
import os
import re
import sys
sys.path.append("/path/to/the/directory/that/has/your/logger/module")
from logger import return_logger
log_file = os.path.basename(__file__)
log_file = re.sub(".py", ".log", log_file)
# True is used so that the events are displayed on the console
logger = return_logger(log_file, True)
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
destroy_logger(logger)
Here is how you can set different log formats.
#!/usr/bin/python3
import logging
import sys
log_file = "my.log"
def return_logger(log_file, frmt):
logger = logging.getLogger()
logger.setLevel(logging.INFO)
try:
frmt
except NameError:
format = logging.Formatter(fmt="[%(asctime)s %(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
else:
if frmt == "minimal":
format = logging.Formatter(fmt="%(message)s", datefmt="")
else:
format = logging.Formatter(fmt="[%(asctime)s %(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
dirname = os.path.dirname(log_file)
if not os.path.exists(dirname):
os.makedirs(dirname)
fileHandler = logging.FileHandler(log_file)
fileHandler.setFormatter(format)
logger.addHandler(fileHandler)
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(format)
logger.addHandler(consoleHandler)
return logger
def destroy_logger(logger):
handlers = logger.handlers[:]
for handler in handlers:
logger.removeHandler(handler)
handler.close()
logger = return_logger(log_file, 'standard')
logging.info("Hello")
destroy_logger(logger)
logger = return_logger(log_file, 'minimal')
logging.info("World")
destroy_logger(logger)
If using Python version 3, here is how to append to a log file. No output will appear on the console. The log level is set to DEBUG so that all log level events are appended to the log file.
#!/usr/bin/python
import logging
logging.basicConfig(filename='/path/to/example.log', encoding='utf-8', level=logging.DEBUG)
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
Here is how you can control the format of the log file.
#!/usr/bin/python
import logging
logging.basicConfig(
filename='/path/to/example.log',
encoding='utf-8',
format='[%(asctime)s %(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.DEBUG)
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
Which should produce the following.
[2023-01-06 00:04:04 DEBUG] debug message
[2023-01-06 00:04:04 INFO] info message
[2023-01-06 00:04:04 WARNING] warning message
[2023-01-06 00:04:04 ERROR] error message
[2023-01-06 00:04:04 CRITICAL] critical message
The following can be used to print stdout to the console and to write to the log file.
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
Did you find this article helpful?
If so, consider buying me a coffee over at