Logging to a single file from multiple processes

Well, my friend, you’re in luck because I’m here to help!
To set the stage, let’s create a simple example of what we want to achieve. We have a main process that starts other processes and each of those processes will log something. Let’s say our main process looks like this:

# Import the necessary modules
import logging # Import the logging module to enable logging functionality
from multiprocessing import Process # Import the Process class from the multiprocessing module to enable multiprocessing functionality

# Define the MainProcess class, which inherits from the Process class
class MainProcess(Process):
    # Define the constructor method for the MainProcess class
    def __init__(self):
        super().__init__() # Call the constructor method of the Process class
        self.logger = logging.getLogger(__name__) # Create a logger object for the MainProcess class using the __name__ attribute

    # Define the run method for the MainProcess class
    def run(self):
        # Perform some actions here
        pass

# Check if the script is being run directly
if __name__ == "__main__":
    p = MainProcess() # Create an instance of the MainProcess class
    p.start() # Start the process by calling the start method

And let’s say our other processes look like this:

# Import the necessary modules
import logging # Import the logging module to enable logging functionality
from multiprocessing import Process # Import the Process class from the multiprocessing module to enable multiprocessing functionality

# Create a class for our other process
class OtherProcess(Process):
    def __init__(self):
        super().__init__() # Call the __init__ method of the parent class to initialize the process
        self.logger = logging.getLogger(__name__) # Create a logger object for this process using the __name__ attribute

    def run(self):
        # Perform some important task and log it
        self.logger.info("I'm doing something important in another process") # Use the logger object to log a message indicating the task being performed

# Check if the script is being run directly
if __name__ == "__main__":
    p = OtherProcess() # Create an instance of the OtherProcess class
    p.start() # Start the process by calling the start() method

Now, if we run this code as is, our logs will be mixed up because each process has its own logger and they all have the same name (the name of the module). To fix that, let’s add a unique identifier to each logger so that we can easily distinguish them. Here’s how:

# Import the necessary libraries
import logging
from multiprocessing import Process

# Create a class for the main process
class MainProcess(Process):
    # Initialize the class
    def __init__(self):
        # Call the parent class constructor
        super().__init__()
        # Create a logger for this process with the name of the module
        self.logger = logging.getLogger(__name__)
        # Set the log level for this logger to INFO
        self.logger.setLevel(logging.INFO)
        # Create a formatter for the log messages
        formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
        # Create a file handler for the log messages
        handler = logging.FileHandler("logs/main_process.log")
        # Set the log level for this handler to INFO
        handler.setLevel(logging.INFO)
        # Set the formatter for this handler
        handler.setFormatter(formatter)
        # Add the handler to the logger
        self.logger.addHandler(handler)

    # Define the run method for the process
    def run(self):
        # Do something here
        pass

# Check if the script is being run directly
if __name__ == "__main__":
    # Create an instance of the MainProcess class
    p = MainProcess()
    # Start the process
    p.start()

And let’s modify our other processes to use the same logger as before but with a unique identifier:

# Import the necessary libraries
import logging  # Import the logging library to create and manage logs
from multiprocessing import Process  # Import the Process class from the multiprocessing library

# Create a class for the other process, inheriting from the Process class
class OtherProcess(Process):
    # Initialize the class
    def __init__(self):
        super().__init__()  # Call the __init__ method of the parent class
        self.logger = logging.getLogger(__name__)  # Create a logger with the name of the current module
        self.logger.setLevel(logging.INFO)  # Set the log level for this logger to INFO
        formatter = logging.Formatter('%(asctime)s %(levelname)s [%(processName)s] %(message)s')  # Create a formatter for the log messages
        handler = logging.FileHandler("logs/other_processes.log")  # Create a file handler to write the logs to a file
        handler.setLevel(logging.INFO)  # Set the log level for this handler to INFO
        handler.setFormatter(formatter)  # Set the formatter for this handler
        self.logger.addHandler(handler)  # Add the handler to the logger

    # Define the run method for the process
    def run(self):
        # Do something here and log it!
        self.logger.info("I'm doing something important in another process")  # Log a message using the logger

# Check if the current module is being run as the main program
if __name__ == "__main__":
    p = OtherProcess()  # Create an instance of the OtherProcess class
    p.start()  # Start the process

In this example, we added a unique identifier to the logger by setting the `processName` attribute of our handler. This will automatically add the name of the current process when logging messages.
And that’s it! Now you can easily distinguish logs from different processes in your log files without having them mixed up.

SICORPS