Logger: A named bucket to which messages can be written for processing
LogRecord: Created by Logger.
Formatter: turn the information in log records into output messages.
Filter: provide additional control over which log records are passed from logger to handler
Handler: Engines that determine what happen to each message in a Logger.
Most applications are configured to log to a file. Use the basicConfig() function to set up the default handler so that debug messages are written to a file.
In [2]:
import logging
LOG_FILENAME = 'logging_example.log'
logging.basicConfig(
filename=LOG_FILENAME,
level=logging.DEBUG,
)
logging.debug('This message should go to the log file')
with open(LOG_FILENAME, 'rt') as f:
body = f.read()
print('FILE:')
print(body)
In [5]:
import glob
import logging
import logging.handlers
LOG_FILENAME = 'logging_rotatingfile_example.log'
# Set up a specific logger with our desired output level
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)
# Add the log message handler to the logger
handler = logging.handlers.RotatingFileHandler(
LOG_FILENAME,
maxBytes=20,
backupCount=5,
)
my_logger.addHandler(handler)
# Log some messages
for i in range(20):
my_logger.debug('i = %d' % i)
# See what files are created
logfiles = glob.glob('%s*' % LOG_FILENAME)
for filename in logfiles:
print(filename)
The most current file is always logging_rotatingfile_example.out, and each time it reaches the size limit it is renamed with the suffix .1. Each of the existing backup files is renamed to increment the suffix (.1 becomes .2, etc.) and the .5 file is erased.
Another useful feature of the logging API is the ability to produce different messages at different log levels. This means code can be instrumented with debug messages, for example, and the log level can be set so that those debug messages are not written on a production system. the table below lists the logging levels defined by logging.
Level | Value |
---|---|
CRITICAL | 50 |
ERROR | 40 |
WARNING | 30 |
INFO | 20 |
DEBUG | 10 |
UNSET | 0 |
All of the previous log messages all have ‘root’ embedded in them because the code uses the root logger. An easy way to tell where a specific log message comes from is to use a separate logger object for each module. Log messages sent to a logger include the name of that logger. Here is an example of how to log from different modules so it is easy to trace the source of the message.
In [9]:
import logging
logging.basicConfig(level=logging.WARNING)
logger1 = logging.getLogger('package1.module1')
logger2 = logging.getLogger('package2.module2')
logger1.warning('This message comes from one module')
logger2.warning('This comes from another module')
The logging module integrates with warnings through captureWarnings(), which configures warnings to send messages through the logging system instead of outputting them directly.
In [10]:
import logging
import warnings
logging.basicConfig(
level=logging.INFO,
)
warnings.warn('This warning is not sent to the logs')
logging.captureWarnings(True)
warnings.warn('This warning is sent to the logs')
In [13]:
import logging
file_hanlder = logging.FileHandler("file_1.log", mode='a', encoding=None, delay=False)
file_hanlder_2 = logging.FileHandler("file_2.log", mode='a', encoding=None, delay=False)
logger = logging.getLogger("mytestlogger")
logger.addHandler(file_hanlder)
logger.addHandler(file_hanlder_2)
logger.critical("test critical message")
In [ ]: