• Logger.addHandler() and$_{Logger.removeHandler()}$ add and remove handler objects from the logger object. Handlers are covered in more detail in Handlers . • Logger.addFilter() and$_{Logger.removeFilter()}$ add and remove filter objects from the logger object. Filters are covered in more detail in filter. • Logger.debug() , Logger.info() , Logger.warning() , Logger.error() , and Logger. critical() all create log records with a message and a level that corresponds to their respective method names. The message is actually a format string, which may contain the standard string substitution syntax of %s ,$_{%d}$ ,$_{%f}$ , and so on. The rest of their arguments is a list of objects that correspond with the substitution fields in the message. With regard to$_{**kwargs}$ , the logging methods care only about a keyword of$_{exc_info}$ and use it to determine whether to log exception information. • Logger.exception() creates a log message similar to Logger.error() . The difference is that Logger.exception() dumps a stack trace along with it. Call this method only from an exception handler. • Logger.log() takes a log level as an explicit argument. This is a little more verbose for logging messages than using the log level convenience methods listed above, but this is how to log at custom log levels. • The$_{setLevel()}$ method, just as in logger objects, specifies the lowest severity that will be dispatched to the appropriate destination. Why are there two$_{setLevel()}$ methods? The level set in the logger determines which severity of messages it will pass to its handlers. The level set in each handler determines which messages that handler will send on. • setFormatter() selects a Formatter object for this handler to use. • addFilter() and$_{removeFilter()}$ respectively configure and deconfigure filter objects on handlers. 8 There are very few methods in a handler for application developers to concern themselves with. The only handler methods that seem relevant for application developers who are using the built-in handler objects (that is, not creating custom handlers) are the following configuration methods: The standard library includes quite a few handler types (see Useful Handlers ); the tutorials use mainly $_{StreamHandler}$and$_{FileHandler}$ in its examples. $_{Handler}$objects are responsible for dispatching the appropriate log messages (based on the log messages’ severity) to the handler’s specified destination. Logger objects can add zero or more handler objects to themselves with an addHandler() method. As an example scenario, an application may want to send all log messages to a log file, all log messages of error or higher to stdout, and all messages of critical to an email address. This scenario requires three individual handlers where each handler is responsible for sending messages of a specific severity to a specific location. Child loggers propagate messages up to the handlers associated with their ancestor loggers. Because of this, it is unnecessary to define and configure handlers for all the loggers an application uses. It is sufficient to configure handlers for a top-level logger and create child loggers as needed. (You can, however, turn off propagation by setting the propagate attribute of a logger to$_{False}$.) Loggers have a concept of effective level . If a level is not explicitly set on a logger, the level of its parent is used instead as its effective level. If the parent has no explicit level set, its parent is examined, and so on - all ancestors are searched until an explicitly set level is found. The root logger always has an explicit level set ($_{WARNING}$ by default). When deciding whether to process an event, the effective level of the logger is used to determine whether the event is passed to the logger’s handlers. getLogger() returns a reference to a logger instance with the specified name if it is provided, or$_{root}$ if not. The names are period-separated hierarchical structures. Multiple calls to getLogger() with the same name will return a reference to the same logger object. Loggers that are further down in the hierarchical list are children of loggers higher up in the list. For example, given a logger with a name of$_{foo}$, loggers with names of$_{foo.bar}$ , foo.bar.baz , and$_{foo.bam}$ are all descendants of$_{foo}$. 2.3 Handlers With the logger object configured, the following methods create log messages: You don’t need to always call these methods on every logger you create. See the last two paragraphs in this section.