Back to: Python Tutorials For Beginners and Professionals
Customized Logging in Python
In this article, I am going to discuss Customized Logging in Python with examples. Please read our previous article where we discussed Logging Module in Python. At the end of this article, you will understand the following pointers in detail.
- Root Logger in Python Logging Module
- Problems with root logger
- Customized Logging in Python
- Steps for creating a custom logger
Root Logger in Python Logging Module
In all the above examples, the logger we have initialized is root logger. When we use basicConfig() method, then, by default we are initializing the root logger.
In general, it is advised not to use the root logger. Instead, we should define and customize our own logger for each module or package. The examples shown above are only for basic understanding of what a logger is.
Problems with root logger:
- Once we set basic configuration then that configuration is final, and we cannot change it in the course of the program.
- It will always work for only one handler at a time, either console or file, but not both simultaneously.
- It is not possible to configure a logger with different configurations at different levels.
To overcome these problems, we should go for our own customized loggers.
Customized Logging in Python:
In python, the logging module has mainly four components: loggers, handlers, filters and formatters. Loggers are the objects of the logging module with which we handle the logging functionality. Handlers are those which specify where the logging should go to i.e console or files etc. Filters are those with which we can tell the logger what logs to record i.e levels of logging. Formatters are those which are used to customize the log messages.
Steps for creating a custom logger
Step1: Create a logger
First we need to create a logger, which is nothing but an object to the logger class. We can create this by using getLogger() method. After creating the logger object we have to set the log level using setLevel() method.
logger = logging.getLogger(‘demologger’)
logger.setLevel(logging.INFO)
We can give any name to the logger as we wish. In the above example, a logger with name ‘demologger’ will be created.
Step2: Creating handler
The next step is to create a handler object and set the logging level. There are several types of Handlers like StreamHandler, FileHandler etc. If we use StreamHandler then log messages will be printed to the console. If we use FileHandler, then the log messages will be printed into file.
For Stream Handler,
consoleHandler = logging.StreamHandler()
consoleHandler.setLevel(logging.INFO)
For File Handler,
fileHandler = logging.FileHandler(‘test.log’)
fileHandler.setLevel(logging.INFO)
Step3: Creating Formatter
The next step is to create a formatter object.
formatter = logging.Formatter(‘%(asctime)s – %(name)s – %(levelname)s:
%(message)s’, datefmt=’%d/%m/%Y %I:%M:%S %p’)
Step4: Adding Formatter to Handler
Now we have to add the Formatter (object) to Handler (object) using setFormatter() method.
consoleHandler.setFormatter(formatter)
Step5: Adding Handler object to the Logger
Then the handler object should be added to the logger object using addHandler() method.
logger.addHandler(fileHandler)
logger.addHandler(streamHandler)
Step6: Writing the log messages
The last step is writing the log messages to the file using the methods and logger object which we created.
- logger.debug(‘debug message’)
- logger.info(‘info message’)
- logger.warn(‘warn message’)
- logger.error(‘error message’)
- logger.critical(‘critical message’)
Points to note:
- We have set the logging level for the logger object and the handler object as well.
- If we haven’t set any level for the logger object then, by default, the logger object will be set to WARNING level.
- If we haven’t set any level for the handler object then, by default, the logger object’s level will be considered for the handler object also.
- If we are not satisfied with logger level, then we can set log level explicitly at handler level.
- If we have set different log levels for the logger and handler then, the handler level should be supported by the logger. i.e logger log level should be lower than handler level. If this is not satisfied, the only logger log level will be considered.
For example,
logger → DEBUG
handler → INFO ⇒ Valid and INFO level will be considered for the handler
logger → INFO
handler → DEBUG ⇒ Invalid and INFO level will be considered for the handler
Program: Customized Logging in Python (demo9.py)
import logging class LoggerDemoConsole: def testLog(self): logger = logging.getLogger('demologger') logger.setLevel(logging.INFO) consoleHandler = logging.StreamHandler() consoleHandler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s%(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S%p') consoleHandler.setFormatter(formatter) logger.addHandler(consoleHandler) logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message') demo = LoggerDemoConsole() demo.testLog()
Output:
If we want to use class name as logger name, then we have to create logger object as follows
Program: class name as logger name in Python (demo10.py)
import logging class LoggerDemoConsole: def testLog(self): #logger = logging.getLogger('demologger') logger = logging.getLogger(LoggerDemoConsole.__name__) logger.setLevel(logging.INFO) consoleHandler = logging.StreamHandler() consoleHandler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s%(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S%p') consoleHandler.setFormatter(formatter) logger.addHandler(consoleHandler) logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message') demo = LoggerDemoConsole() demo.testLog()
Output:
Program: using file handler in Python (demo11.py)
import logging class LoggerDemoConsole: def testLog(self): #logger = logging.getLogger('demologger') logger = logging.getLogger(LoggerDemoConsole.__name__) logger.setLevel(logging.INFO) fileHandler = logging.FileHandler("demo.log",mode='a') fileHandler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s%(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S%p') fileHandler.setFormatter(formatter) logger.addHandler(fileHandler) logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message') demo = LoggerDemoConsole() demo.testLog() print("Done")
Output:
File demo.log
In the next article, I am going to discuss Multithreading in Python. Here, in this article, I try to explain Customized Logging in Python with Examples. I hope you enjoy this Customized Logging in Python with Examples article. I would like to have your feedback. Please post your feedback, question, or comments about this article.