1. Background
Everyone should have encountered this scenario, you found a bug but cannot reproduce it. The development said, I will add a log, and then observe it during the test, and tell me in time if there is a problem.
The log is very important for debugging, but the more the better. Key codes generally need to print logs, which can be quickly debugged when problems occur. In daily use, generally focus on the error log. You can also save the info-level log for subsequent analysis when problems occur.
And the log is generally not kept for a long time, only the most recent log is kept.
2, Log level
The lower the level, the higher
D (Debug): Indicates the log information of the debug level
I (Information): Indicates log information at the information level
W (Warning): indicates the log information of the warning level
E (Error): Indicates the log information of the error level
3. There are two output methods of log
3.1 Console output
import logging from logging import Logger class MyLogger(Logger): def __init__(self): # Set the name of the log and the collection level of the log super().__init__("test_api", logging. DEBUG) # Customize the log format (Formatter), instantiate a log format class fmt_str = '%(asctime)s %(levelname)s %(filename)s : %(funcName)s [line: %(lineno)s] %(message)s' formatter = logging. Formatter(fmt_str) # Instantiate the console channel (StreamHandle) sh = logging. StreamHandler() # Set the log level for console output sh. setLevel(logging. INFO) # Set the log display format in the channel sh. setFormatter(formatter) # Bind the channel to the log collector self. addHandler(sh) sh. close() # Instantiate the MyLogger object, which can be called directly by using log in other files log = MyLogger() if __name__ == '__main__': log. error("this is an error log") log.info("this is an info log") log.debug("this is a debug log") log. warning("this is a warning log")
Result:
Since the level of the console input log is set to INFO, INFO and logs with a higher level than INFO will be output on the console.
2023-05-24 15:15:22,445 ERROR my_logger.py : <module> [line: 69] this is an error log 2023-05-24 15:15:22,445 INFO my_logger.py : <module> [line: 70] this is a info log 2023-05-24 15:15:22,445 WARNING my_logger.py : <module> [line: 72] this is a warning log Process finished with exit code 0
However, in daily use, the general console only outputs logs at the ERROR level. Modify the code here:
sh.setLevel(logging.ERROR)
Result: Execute again, it can be seen that the console only outputs the errorlog
2023-05-24 15:29:20,465 ERROR stream_logger.py : <module> [line: 31] this is an error log Process finished with exit code 0
3.2 File output
Log output to a file.
The code has been running for a long time, and there will be a lot of logs. At this time, one file is definitely not enough, and it does not make much sense to keep the log from too long ago. Therefore, when the log reaches the maximum byte length, several log files will be automatically backed up. And when all log files reach the maximum length, only the latest log is kept. [Reduce the byte length of the file to be smaller, and the effect can be seen after multiple executions]
Use RotatingFileHandler() to automatically backup log files
# When the log reaches the maximum byte length, several log files will be automatically backed up. And when all log files reach the maximum length, only the latest log is kept fh = handlers.RotatingFileHandler(all_log_path_file, maxBytes=10**2, backupCount=5, encoding="utf-8", mode="a")
code show as below:
import logging from logging import Logger, handlers class MyLogger(Logger): def __init__(self): # get log file path all_log_path_file = "test.log" # Set the name of the log and the collection level of the log super().__init__("test_api", logging. DEBUG) # Customize the log format (Formatter), instantiate a log format class fmt_str = '%(asctime)s %(levelname)s %(filename)s : %(funcName)s [line: %(lineno)s] %(message)s' formatter = logging. Formatter(fmt_str) # Instantiate the file channel (FileHandle) ''' Create a file instance, if the api_test.log file does not exist, it will be created automatically; The mode parameter is set to append; in addition, to prevent garbled characters, the encoding parameter is set to utf-8 encoding format ''' # When the log reaches the maximum byte length, 5 log files will be automatically backed up. When all five log files reach the maximum length, only the latest log will be kept. fh = handlers.RotatingFileHandler(all_log_path_file, maxBytes=10**3, backupCount=5, encoding="utf-8", mode="a") # Set the log format output to the file fh. setLevel(logging. DEBUG) # Set the log display format in the channel fh. setFormatter(formatter) # Load the file instance into the logger object self. addHandler(fh) # close the file fh. close() # Instantiate the MyLogger object, which can be called directly by using log in other files log = MyLogger() if __name__ == '__main__': log. error("this is an error log") log.info("this is an info log") log.debug("this is a debug log") log. warning("this is a warning log")
Result:
Open the log file, you can see the printed log.
If you want to adjust the level of file output log, modify here
# Set the log format output to the file, modify it to the error level fh. setLevel(logging. ERROR)
4. Code encapsulation
- Output ERROR level log on the console
- Output DEBUG level log in log file
- Separately output the log of ERROR level in a file
- When the log reaches the maximum byte length, 5 log files will be automatically backed up. When all 5 log files reach the maximum length, only the latest log will be kept
code show as below:
import logging import os from logging import Logger, handlers from config.settings import get_log_path class MyLogger(Logger): def __init__(self): # log_name = '{}.log'.format(time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime())) # log_path_file = os.path.join(get_log_path(), log_name) # get log file path all_log_path_file = os.path.join(get_log_path(), "api_test.log") error_log_path_file = os.path.join(get_log_path(), "error.log") # Set the name of the log and the collection level of the log super().__init__("test_api", logging. DEBUG) # Customize the log format (Formatter), instantiate a log format class fmt_str = '%(asctime)s %(levelname)s %(filename)s : %(funcName)s [line: %(lineno)s] %(message)s' formatter = logging. Formatter(fmt_str) # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # Instantiate the console channel (StreamHandle) sh = logging. StreamHandler() # Set the log level for console output sh. setLevel(logging. ERROR) # Set the log display format in the channel sh. setFormatter(formatter) # Bind the channel to the log collector self. addHandler(sh) # Instantiate the file channel (FileHandle) # fh = logging. FileHandler(log_path_file, mode='a', encoding="utf-8") ''' Create a file instance, if the api_test.log file does not exist, it will be created automatically; The mode parameter is set to append; in addition, to prevent garbled characters, the encoding parameter is set to utf-8 encoding format ''' fh = handlers.RotatingFileHandler(all_log_path_file, maxBytes=10**6, backupCount=5, encoding="utf-8", mode="a") # Set the log format output to the file fh. setLevel(logging. DEBUG) # Set the log display format in the channel fh. setFormatter(formatter) # Load the file instance into the logger object self. addHandler(fh) # When the log reaches the maximum byte length, 5 log files will be automatically backed up. When all five log files reach the maximum length, only the latest log will be kept. fh1 = handlers.RotatingFileHandler(error_log_path_file, maxBytes=10 ** 6, backupCount=5, encoding="utf-8", mode="a") # Set the log format output to the file fh1. setLevel(logging. ERROR) # Set the log display format in the channel fh1. setFormatter(formatter) # Load the file instance into the logger object self. addHandler(fh1) fh. close() fh1. close() sh. close() # Instantiate the MyLogger object, which can be called directly by using log in other files log = MyLogger() if __name__ == '__main__': log. error("this is an error log") log.info("this is an info log") log.debug("this is a debug log") log. warning("this is a warning log")