The level of logging
- CRITICAL = 50
- FATAL = CRITICAL
- ERROR = 40
- WARNING = 30
- WARN = WARNING
- INFO = 20
- DEBUG = 10
- NOTSET = 0
import logging
- When the import Logging code is created, a Logger object is created with the name root
- Root = RootLogger(WARNING) Creates a Logger object whose log level is WARNING and whose name is root as the default logger
- Add two attributes root and Manager for the Logger class. The manager object mainly manages Logger objects and forms a parent-child relationship.
Get Logger object
- Get it from the logging.getLogger() method
- When name is not passed, the root Logger object is returned
- When name is passed, the Manager object getLogger is looked up
- 1. From the above analysis, you can see that there is already a logger named root in the Manager object
- 2. The Manager has a loggerDict dictionary that maintains mappings between names and Logger objects, such as root: Logger object address.
- 3. If the name you pass is not in loggerDict, a Logger object is created and added to loggerDict, pointing to a parent Logger object (parent property in Logger class).
- 4. If you pass ‘A.B.C’ as a dot-delimit string name, in addition to ‘A.B.C ‘: Logger objects to LoggerDict,’ A ‘: PlaceHolder objects and’ a.B ‘: PlaceHolder objects will be added. The next access creates a Logger object for ‘A’ or ‘a.b’ and maintains the parent-child relationship
- 5. The manager object maintains a parent-child reference. Root is the parent Logger, and since the parent property is None, a Logger with the name ‘a’ is the parent of a Logger with the name ‘a.b’, and ‘A.b’ is the parent of ‘A.B.C.’
- 6. Returns when the passed name exists in the Manager’s loggerDict
Logging.getlogger () gets a Logger instance without passing in a name. By default, you get root Logger. If you pass in a name, no Logger instance is created, maintained by loggerDict in Manager, and the parent-child relationship is maintained
Log output
import logging
logging.info("info")
logging.warning("warning")
Copy the code
- The above two lines of code briefly explain why info is not output, but warning can be output
- From these three lines of code, you know that the logging.info method actually uses the info method of root Logger
- Handlers are a list of handlers, which are the objects that actually handle the logging
- When no processor is defined, the baseConfig() method is first used for initialization
- The parameters that the method can pass in are available from the method help document
- Filename: logs are output to error output by default. If this parameter is specified, logs are output to a file
- Filemode: open filemode, append by default
- Format: Log output format, the default format in the above is not useful, because there is no timestamp, there is no log output format, the following list is commonly used, how to use it
- Style: It doesn’t work
- Level: Sets the level of the root Logger object
- Stream: Since the default streamHandler is used to output the diary to error output, you can customize the streamHandler instead
- Handlers: Custom handlers list
- Force: Remove handlers from the Handlers list (added after python3.8)
- The format format
The property name | describe |
---|---|
%(message)s | The message body |
%(asctime)s | Log creation time |
%(funcName)s | The function name |
%(levelname)s | The level of logging |
%(levelno)s | Log Level Number |
%(lineno)d | The line Numbers |
%(module)s | The line Numbers |
%(process)d | The process id |
%(thread)d | Thread id |
%(processName)s | The process of |
%(threadName)s | The thread of |
%(name)s | The Logger instance name |
-
Take a look at the basicConfig() process
- Handlers are initialized when root.handlers are empty. If basicConfig() is executed, it will not be executed because a Handler object is added to the Handlers list
- The stream and filename arguments cannot be passed at the same time
- FileHanlder or streamHandler is created from a value that was not passed to filename. If you look at the instantiation of the streamHandler class and find that no stream value was passed to the stream, the default value is error. Handler level is 0.
- _STYLES is a dictionary, style can only be ‘%’,'{‘,’$’, the default style is BASIC_FORMAT
- The handler is then formatted, and the root Logger adds the handler
- Finally, log level is set, and an error is reported if there are any other parameters
- After executing the basicConfig method, return to logging.info and call the info method of root Logger
- This is the first level of log output
- The Disabled property in the Logger class should set whether the logging object is enabled or not
- _cache is a dictionary that records whether different levels are used, for example: INFO: False, WARNING: True
- Self.manager.disable Defaults to 0 (NOTSET)
- The getEffectiveLevel method returns a valid level for the Logger object. If it has one, it returns it. If it does not, it looks up the parent Logger and returns the first valid level. For example, Logger a has a level of 30, and Logger a.b has a valid level of 30 if no level is set.
- Return to isEnabledFor (); check whether the level of the log passed in is larger than that of the Logger set. For example, if the level of the log passed in is INFO, and the level of the root is WARNING, the value 20 of INFO is less than WARNING30, so return False
- When isEnabledFor returns True, the self._log method is executed, noting the last two lines. The makeRecord method encapsulates the information, and the Handle method handles the record information
- Handle method
-
The callHandlers method passes encapsulated messages to all handlers, and processes messages only when the handler level is greater than the record level, according to the ratio of handler level to record level. Propagate represents the propagation attribute, which passes the Record to the parent Logger for processing. The default is True, the root Logger has no parent.
-
Finally, an official graph represents the log output flow
-
Summarize the steps
- 1. The level of the Logger object must be greater than or equal to the level you passed in before the next step
- 2. Encapsulate the information. If it is not filtered out, it is handed to all handlers
- 3. Check whether the handler level is greater than or equal to the record level
- 4. Whether the propagate for Logger is True, if the propagate for Logger is True, the handler of the parent Logger will be called to process the record, the logic is the same as the previous steps
In actual combat
import logging logFormat = '{"timeStamp": %(asctime)s, "level": %(levelname)s, "message": %(message)s}' logging.basicConfig(level=logging.INFO, Format =logFormat) # Root Logger root = logging.getLogger() # parent Logger root log1 = logging.getLogger("a") # Propagate = False # The parent Logger is a log2 = logging.getLogger('a.b') logging.info("root ") Logger info msg") log1.info("log1 Logger info msg") log2.info("log2 Logger info msg")Copy the code
- Initialize the root Logger using the basicConfig method
- Log1 Logger is output by the handler that calls root. Similarly, log1 and log2 have valid level INFO (root level).
- Propagate = False log1 and log2 will not output when executing log1.propagate = False, log2 information will not be output when executing log2.propagate = False
import logging logFormat = '{"timeStamp": %(asctime)s, "level": %(levelname)s, "message": %(message)s}' logging.basicConfig(level=logging.INFO, Logger root = logging.getLogger() # create handler myHandler = logging.FileHandler("./log.txt", mode="w", encoding="utf=8") fileFormat = '{"logType": "file","timeStamp": %(asctime)s, "level": %(levelname)s, "message": %(message)s}' fileFormater = logging.Formatter(fileFormat) myHandler.setFormatter(fileFormater) MyHandler. SetLevel (logging.warning) # addHandler root.addHandler(myHandler) # test root.info("test root logger MSG ") root.warning("test warning logger msg")Copy the code
- Simply define a file output handler
- The console outputs info and wanring information, but only warning information is displayed in log.txt because info is smaller than warning
- More handler types are available in the Logging package in hadlers.py
- Take a look at the handler for cutting log files based on time
import logging from logging.handlers import TimedRotatingFileHandler logFormat = '{"timeStamp": %(asctime)s, "level": %(levelname)s, "message": %(message)s}' logging.basicConfig(level=logging.INFO, Logger root = logging.getLogger() # create handler myHandler = TimedRotatingFileHandler("./log.txt", when="s", interval=5) fileFormat = '{"logType": "file","timeStamp": %(asctime)s, "level": %(levelname)s, "message": %(message)s}' fileFormater = logging.Formatter(fileFormat) myHandler.setFormatter(fileFormater) MyHandler. SetLevel (logging.warning) # addHandler root.addHandler(myHandler) # test root.info("test root logger MSG ") root.warning("test warning logger msg")Copy the code
- Much like the previous FileHandler, but a new file is created every 5s