Basic component

  • 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.

Logging to a File

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)


FILE:
DEBUG:root:This message should go to the log file

Rotating Log Files


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)


logging_rotatingfile_example.log.4
logging_rotatingfile_example.log.1
logging_rotatingfile_example.log.5
logging_rotatingfile_example.log
logging_rotatingfile_example.log.2
logging_rotatingfile_example.log.3

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.

Verbosity Levels

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.

Logging Levels
Level Value
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
UNSET 0

Naming Logger Instances

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')

Integration with the warnings 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')


/home/scott/.virtualenvs/tf35/lib/python3.5/site-packages/ipykernel_launcher.py:8: UserWarning: This warning is not sent to the logs
  

Multiple Handlers


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 [ ]: