Overview
The Logging module is a wrapper for Python’s built in logging module. Due to the challenges of multiprocessing logging, each process logs to its own log file, and all the log files for one run are logged to a subdirectory in the logs directory. This document outlines the usage and design process for the Logging module.
Usage
Each process wishing to log must import the following modules:
The
logger
class withfrom modules.logger import logger
Import the built in
inspect
module withimport inspect
Create a logger in the __init__
function for a module (TODO: determine where to create the logger in main) with self.__create_logger_result, self.__logger = logger.logger.create("name")
. Replace “name” with the desired name of the logger - this will also be the name of the log_file. It is suggested to name the logger after the process doing the logging.
We don’t want to take down a process if logger creation fails, so we won’t handle the failed case, but we will only log if the result is True
.
The logger supports the five default logging levels, in increasing order of severity: debug
, info
, warning
, error
, critical
.
The logger takes a log message and the frame as input. The frame is an object from the inspect
module, containing information about the current code being run - of which we use the line, function, and file.
To log a message, use the following template, replace debug
with the desired logger:
if self.__create_logger_result: frame = inspect.currentframe() self._logger.debug("log message", frame)
Design Choice
There are several challenges with multiprocessing logging:
Using the default
logging
module:If multiple processes attempt to log to the same file, it will corrupt the file
We cannot call a global logger directly from a subprocess
Since we are in a multiprocessing environment, calling
get_logger
() with the name of the desired logger does not give us the desired logger, it creates a new one
Since we cannot have a global logger, one solution is to initialize a logger in each process, but this introduces a bug
If a logger is initialized in each process, each time the file handler is set, it overwrites the existing file
e.g. if
main
initializes a logger to log toexample.log
, thenvideo_input
initializes a logger to log to log to also log toexample.log
, it erases any logs already made bymain
Another solution is to pass a logger to each process, but it is undesirable to change the function signatures of every module wishing to log to include the logger in the input
Using a custom module:
The custom module would have a logging worker which is started in main along with the other workers
It would have an input queue of log messages and other information (frame and log level)
This solves all the bugs above, however, we still need to pass the queue into every module wishing to log, which is again undesirable
Further reading on multiprocessing logging: