This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: python logging handler not used when added after a process is started
Type: Stage:
Components: Extension Modules Versions: Python 3.4
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: ericg97477, vinay.sajip
Priority: normal Keywords:

Created on 2015-07-25 10:29 by ericg97477, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (4)
msg247336 - (view) Author: eric (ericg97477) Date: 2015-07-25 10:29
If I have interpreted the python3 documentation correctly, regardless of where I add the handler to the root logger, my log messages from within a Process should be sent to a file. However, this is not the case.

Here is a complete program which demonstrates the problem:

import logging
import logging.handlers

from multiprocessing import Process
from time import sleep

fileHandler = logging.FileHandler( 'mylog.log' )
fileHandler.setLevel( 5 )

logger = logging.getLogger( None )

def process_logger():

    print( "process waiting" )
    sleep( 5 )
    print( 'process start' )

    logger = logging.getLogger( None )

    for num in range( 1, 10 ):
        logger.critical( "critical: %d" % num )
        sleep(1)

#
# if this is where the handler is added, the critical messages
# will go to the file
#
logger.addHandler( fileHandler )

processLogger = Process( target=process_logger )
processLogger.start()

#
# if this is where the handler is added, the critical messages
# will not go to the file.
#
#logger.addHandler( fileHandler )

print( "started" )

I am using python 3.4.3 on OS X 10.10.4.

My guess as to why this does not work is that when I start the Process, it makes a copy of the current environment and if the handler has not been added by that time, the environment the Process is running in won't have it.

I have three questions:

Why do my messages not always end up in the file regardless of where I call logger.addHandler?

Should my messages always end up in the file?

If they should not, what is the best solution to the general problem of needed to manipulate handlers after a Process has been started?
msg247393 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2015-07-25 21:03
This is not a bug - it's how processes work on POSIX. Multiprocessing on POSIX generally uses the fork system call, which happens when you create a another process via the Process(...) call. At this point, the created process is a copy of the original process. When you add the handler *before* the Process(...) call, the copy also has the handler already added, so process_logger (which is called in the copy) will behave as expected. When you add the handler after the Process(...) call, the handler has not been added in the copy, so process_logger (which is called in the copy) will not behave as expected.

To avoid this sort of problem, ensure that logging is configured as desired in each process (normally, this means doing the logging configuration in code which is called (directly or indirectly) from the target=XXX callable which is passed to Process.
msg247462 - (view) Author: eric (ericg97477) Date: 2015-07-27 12:04
The python documentation says that when one calls logger.getLogger with the same identifier that one gets the same instance of the logger. I would guess that in the case of a Process this is not the case. I would have to assume that the handlers attached to that Process are different as well. So, do you know if pointing the two file handlers at the same file as I am doing is expected to work or not? The documentation would seem to indicate yes, but how loggers work with a Process seems to be a bit unclear in the documentation
msg247463 - (view) Author: Vinay Sajip (vinay.sajip) * (Python committer) Date: 2015-07-27 12:22
Context is crucial. The Python documentation is not wrong, but doesn't belabour the point that it refers to the most common, single-process case. The problem you encountered is not specific to logging: you need to understand all aspects of how forking works and how Python works within the framework of POSIX and forking. It's a non-trivial topic and too much to go into here - suffice to say that in order to get the result you expect, you need (as I said in an earlier comment) to configure logging in code that is called in each process of a multiple-process setup. If you add two handlers to a logger, one before forking and one after forking, then the child process might behave as expected, but logging from the parent process could output multiple copies of the same message. If you don't do any logging in the parent, that might be OK, but it still doesn't feel like the right approach.

You might find it helpful to read my 2010 blog post about logging and multiprocessing:

http://plumberjack.blogspot.co.uk/2010/09/using-logging-with-multiprocessing.html

AFAIK nothing fundamental has changed since then to invalidate the overall thrust of that post.
History
Date User Action Args
2022-04-11 14:58:19adminsetgithub: 68905
2015-07-27 12:22:42vinay.sajipsetmessages: + msg247463
2015-07-27 12:04:12ericg97477setmessages: + msg247462
2015-07-25 21:03:30vinay.sajipsetstatus: open -> closed
resolution: not a bug
messages: + msg247393
2015-07-25 19:45:04ned.deilysetnosy: + vinay.sajip
2015-07-25 10:29:10ericg97477create