Python version 3.13.7 on Windows 11 Enterprise
I am running a FileHandler and StreamHandler using a QueueHandler for my pyton script. The main process logs go to both the stream and file, but the logs for the two subprocesses using mutiprocessing.Pool only go to the file.
I placed a third pass that runs the subprocess outside of the multiprocess to make sure it wasn't a coding error in my subprocess, and it functions as expected.
I put a print command into the subprocess to see if it was the StreamHandler or QueueHandler malfunctioning. The print does not function during multiprocessing, but will display for the third pass outside of the multiprocess.
I know I am capturing everything in the log file (except the print commands), but I am running a multi-step subprocess with large data sets using this setup and would like to see where the process is without having to constantly open the log file. All the documentation and tutorials I have been able to find point me to this setup.
Everything works correctly when writing to the log file, just not the stream output. How do I make the subprocess logging commands go to the the stream (command window) in addition to the log file while using multiprocessing.Pool?
stream output:
INFO | 2026-06-29 09:26:41 | Running: test.py
INFO | 2026-06-29 09:26:41 | Start processing
INFO | 2026-06-29 09:26:46 | Starting test3
test3 yo we here!
INFO | 2026-06-29 09:26:46 | Finished test3
INFO | 2026-06-29 09:26:46 | End processing
file output:
2026-06-29 09:26:41 | INFO | Main | 100 | Running: test.py
2026-06-29 09:26:41 | INFO | Main | 108 | Start processing
2026-06-29 09:26:41 | INFO | workerProcess | 79 | Starting test1
2026-06-29 09:26:41 | INFO | workerProcess | 83 | Finished test1
2026-06-29 09:26:41 | INFO | workerProcess | 79 | Starting test2
2026-06-29 09:26:41 | INFO | workerProcess | 83 | Finished test2
2026-06-29 09:26:46 | INFO | workerProcess | 79 | Starting test3
2026-06-29 09:26:46 | INFO | workerProcess | 83 | Finished test3
2026-06-29 09:26:46 | INFO | Main | 118 | End processing
Test.py
import logging
import multiprocessing
from logging.handlers import QueueHandler
import sys
import time
import myLogger
myLogger.Main(sys.argv[1], "TEST")
def logging_process(queue):
logger = logging.getLogger('app')
while True:
message = queue.get()
if message is None:
break
def workerProcess(Args):
queue, outputDir, rFC = Args
# Set logging queue
logger = logging.getLogger('app')
logger.addHandler(QueueHandler(queue))
logger.info("Starting {}".format(rFC))
print("{} yo we here!".format(rFC))
# Export to final geodatabase
logger.info("Finished {} ".format(rFC))
def Main(outputDir):
# Start logging fuction
with multiprocessing.Manager() as manager:
queue = manager.Queue()
logger = logging.getLogger('app')
logger.addHandler(QueueHandler(queue))
logger_proc = multiprocessing.Process(target=logging_process, args =(queue,))
logger_proc.start()
try:
logger.info("Running: test.py")
# Determine number of processing pools
processes = []
for rFC in ('test1', 'test2'):
processes.append((queue, outputDir, rFC))
# Start threads
logger.info("Start processing")
with multiprocessing.Pool(4) as pool:
pool.map(workerProcess, processes)
pool.close()
pool.join
time.sleep(5)
workerProcess((queue, outputDir, 'test3'))
# Declare running time
logger.info("End processing")
except Exception as e:
logger.exception(e)
logger.error("error", stack_info=True)
raise
# End logging function
queue.put(None)
logger_proc.join() # Always join started processes
if __name__ == "__main__":
# Running Main Program
Main(sys.argv[1])
myLogger.py
import logging
import os
import sys
def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
logger.critical("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
def Main(log_path, log_name):
# Create and set log path
if not os.path.exists("{}".format(log_path)):
os.mkdir("{}".format(log_path))
status_log_target = os.path.join(log_path, "{}_status.log".format(log_name))
# Set up the logger format
logger = logging.getLogger('app')
logger.setLevel(logging.DEBUG)
sh = logging.StreamHandler(sys.stdout)
sh.setLevel(logging.INFO)
shortFMT = logging.Formatter(fmt="%(levelname)-8s | %(asctime)s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", style='%')
sh.setFormatter(shortFMT)
fh = logging.FileHandler(status_log_target)
fh.setLevel(logging.DEBUG)
longFMT= logging.Formatter(fmt="%(asctime)s | %(levelname)-8s | %(funcName)-15s| %(lineno)-4d | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", style='%')
fh.setFormatter(longFMT)
logger.addHandler(fh)
logger.addHandler(sh)
# Handle exceptions
sys.excepthook = handle_exception
if __name__ == "__main__":
Main(sys.argv[1], sys.argv[2])