python logging module

When it comes to logging, whether writing framework code or business code is inseparable from logging, which can bring us great help in locating problems.

The easiest way to record a log is to add a print where you want to record. I believe both novices and old birds often do this. There is no problem doing this in simple code or small projects. However, for some larger projects, sometimes it is necessary to check the history log to locate a problem. It is inappropriate to use print.

The log printed by print has no time, does not know the location of the log record, and has no readable log format. It is not possible to output the log to the specified file.... Unless you repeat all this yourself.

The best practice is to use the built-in logging module, because the logging module provides developers with very rich functions.



For example, the above figure uses the logging module of the standard library to record the generated log, including the specific time of the log, the module in which the log occurs, the log level and the specific content of the log, etc

How to use it? Let's take an example



Import the logging module, and then directly use the logging message recording method provided by logging.

log level

Log levels are divided into the following five levels



log levelUsage scenario
DEBUG The debug level is used to record detailed information to facilitate problem location and debugging. We generally do not open debug in the production environment
INFO It is used to record the information of key code points so that the code can execute as expected. The production environment usually sets the INFO level
WARNING Record some unexpected situations, such as insufficient disk
ERROR Information recorded when some functions cannot function properly due to a more serious problem
CRITICAL Information recorded when a serious error occurs that prevents the application from continuing to run

The importance of the log level increases step by step. python provides five corresponding level methods. By default, the log level is warning, and log information lower than warning will not be output.

From the code above, you can see that logging The log contents after logging are printed in the standard output stream, that is, the command line window, but logging The logs recorded by debug and info will not be printed.

Modify log level

How to make debug level information output?

Of course, the default log level should be modified. You can use logging before logging Basicconfig method to set the log level

import logging
logging.basicConfig( level=logging.DEBUG)
logging.debug("this is debug")"this is info")
logging.error("this is error")

When the debug level is set, all log information will be output

DEBUG:root:this is debug
INFO:root:this is info
ERROR:root:this is error

Log to file

The previous log will output the log to the standard output stream by default, which is only output in the command line window. After the program is restarted, there is no place to find the historical log, so it is a very common requirement to permanently record the log content. Also, configure the function logging Basicconfig can specify where the log is output

import logging
logging.basicConfig(filename="test.log", level=logging.INFO)
logging.debug("this is debug")"this is info")
logging.error("this is error")

Here I specify the log output to the file test In log, the log level is specified as INFO. The contents recorded in the last file are as follows:

INFO:root:this is info
ERROR:root:this is error

Each time you re run, the log will be appended later. If you want to overwrite the previous log before each run, you need to specify filemode='w ', which is the same as the parameter used by the open function to write data to the file.

Specify log format

The default output format includes three parts: log level, the name of the logger, and the log content. The middle is connected with ":. If we want to change the log format, such as adding date and time and displaying the name of the logger, we can specify the format parameter to set the log format

import logging
logging.basicConfig(format='%(asctime)s %(levelname)s %(name)s %(message)s')
logging.error("this is error")





2021-12-15 07:44:16,547 ERROR root this is error

The log format output provides many parameters. In addition to the time, log level, log message content, and the name of the logger, you can also specify the thread name, process name, and so on



So far, that's all the basic usage of the log module. It can also meet most application scenarios. More advanced methods can help you better deal with logs


The logging described earlier, In fact, they are created through an instance object called Logger. Each Logger has a name. When logging directly, the system will create a Logger named root by default. This Logger is the root Logger. The Logger supports hierarchy. Sub recorders usually do not need to set the log level and Handler separately (described later), if the child recorder is not set separately, its behavior will be delegated to the parent.

The logger name can be any name, but the best practice is to use the module name directly as the logger name. Named as follows

logger = logging.getLogger(__name__)

By default, the logger adopts a hierarchical structure, and the previous period is arranged in the hierarchy of the namespace as a separator. The logger below the hierarchy list is a child of the logger higher in the list. For example, there is a recorder called foo, and the name is foo bar,, and foo BAM recorders are children of foo.

│  │
│  │
│  │  
│  ├─bam
│  │  │
│  │  │  
│  │          
│  ├─bar
│  │  │
│  │  │  
│  │  ├─baz
│  │  │  │
│  │  │  │  


import foo
from foo import bar
from foo import bam
from import baz

if __name__ == '__main__':

import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)"this is foo")

Here, I only set foo the level of this recorder to INFO

import logging

logger = logging.getLogger(__name__)"this is bar")

Other sub modules are like bar Py similar code does not set the log level, and the final output is

INFO:foo:this is foo is bar
INFO:foo.bam:this is bam is baz

This is because foo If the log level of bar recorder is not set, the ancestor with daily log level will be found upward. Here, the level of foo of the parent recorder is INFO. If foo is not set, the root recorder root will be found. The default level of root is warning.

Processor (Handler)

The recorder is responsible for recording the log, but the recorder doesn't care where the log is finally recorded, but gives it to another guy, the Handler, to handle it.

For example, for a flash project, you may record the INFO level log to a file and the ERROR level log to standard output, Send some key logs (such as orders or serious errors) to an email address to inform the boss. At this time, your recorder adds multiple different processors to process different message logs, so as to send them to a specific location according to the importance of messages.



Python has built-in many practical processors, including:

1. StreamHandler standard stream processor, which sends messages to standard output stream and error stream
2. FileHandler is a file processor that sends messages to files
3. RotatingFileHandler is a file processor. After the file reaches the specified size, a new file is enabled to store logs
4. TimedRotatingFileHandler is a file processor that rotates log files at specific time intervals

Processor operation



Handler provides four methods for developers to use. You can find that logger can set level and handler can also set level. Through setLevel, messages of different levels recorded by the recorder can be sent to different places.

import logging
from logging import StreamHandler
from logging import FileHandler

logger = logging.getLogger(__name__)

# Set to DEBUG level

# Standard stream processor, set to level WARAING
stream_handler = StreamHandler()

#File processor, set the level to INFO
file_handler = FileHandler(filename="test.log")

logger.debug("this is debug")"this is info")
logger.error("this is error")
logger.warning("this is warning")

After running, the log output in the command line window is:

this is error
this is warning

The log contents output in the file are:

this is info
this is error
this is warning

Although we set the level of the logger to debug, the message recorded by debug is not output, because the level I set for both handlers is higher than debug, so this message is filtered out.


Formatter has been introduced in the previous part of the article, but it is through logging Basicconfig. In fact, the formatter can also be set on the Handler in the form of an object. The formatter can specify the output format of the log, whether to display the time, what the time format is, whether to display the level of the log, whether to display the name of the recorder, etc. messages can be formatted and output through a formatter.

import logging
from logging import StreamHandler

logger = logging.getLogger(__name__)

# Standard stream processor
stream_handler = StreamHandler()

# Create a formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# Function in handler upper
#Add processor
logger.addHandler(stream_handler)"this is info")
logger.error("this is error")
logger.warning("this is warning")

Note that the formatter can only work on the processor. Set the formatter through the setFromatter method of the processor. Moreover, a handler can only set one formatter. It's a one-to-one relationship. The relationship between logger and handler is one to many. A logger can add multiple handlers. Both handler and logger can set the log level.




Go back to the beginning, logging What does the basicconfig () method do for us? Now you can probably guess. Let's see what the python source code says

Do basic configuration for the logging system.

This function does nothing if the root logger already has handlers configured. It is a convenience method intended for use by simple scripts to do one-shot configuration of the logging package.

The default behaviour is to create a StreamHandler which writes to sys.stderr, set a formatter using the BASIC_FORMAT format string, and add the handler to the root logger.

A number of optional keyword arguments may be specified, which can alter the default behaviour.

1. Create a root logger
2. Set the log level of root to warning
3. Adding a StreamHandler processor to the root logger
4. Set up a simple formatter for the processor


These two lines of code are actually equivalent to:

import sys
import logging
from logging import StreamHandler
from logging import Formatter

logger = logging.getLogger("root")
handler = StreamHandler(sys.stderr)
formatter = Formatter(" %(levelname)s:%(name)s:%(message)s")

logging. The basicconfig method is equivalent to making the most basic configuration for the log system, which is convenient for developers to access and use quickly. It must be called before recording logs. However, if the root logger has specified other processors, and you call basciConfig at this time, this method will fail and it will do nothing.

Log configuration

For log configuration, in addition to writing the configuration directly into the code described above, you can also put the configuration information separately in the configuration file to separate the configuration from the code.

Log configuration file logging conf






format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

Load profile

import logging
import logging.config

# load configuration

# establish logger
logger = logging.getLogger()

#Application code
logger.debug("debug message")"info message")
logger.warning("warning message")
logger.error("error message")


2021-12-23 00:02:07,019 - root - DEBUG - debug message
2021-12-23 00:02:07,019 - root - INFO - info message
2021-12-23 00:02:07,019 - root - WARNING - warning message
2021-12-23 00:02:07,019 - root - ERROR - error message

Keywords: Python

Added by runfastrick on Fri, 31 Dec 2021 18:47:05 +0200