pythonloggingpython-daemon

python-daemon and logging: set logging level interactively


I have a python-daemon process that logs to a file via a ThreadedTCPServer (inspired by the cookbook example: https://docs.python.org/2/howto/logging-cookbook.html#sending-and-receiving-logging-events-across-a-network, as I will have many such processes writing to the same file). I am controlling the spawning of the daemon process using subprocess.Popen from an ipython console, and this is how the application will be run. I am able to successfully write to the log file from both the main ipython process, as well as the daemon process, but I am unable to change the level of both by just simply setting the level of the root logger in ipython. Is this something that should be possible? Or will it require custom functionality to set the logging.level of the daemon separately?

Edit: As requested, here is an attempt to provide a pseudo-code example of what I am trying to achieve. I hope that this is a sufficient description.

daemon_script.py

import logging
import daemon 
from other_module import function_to_run_as_daemon

class daemon(object):
    def __init__(self):
         self.daemon_name = __name__
         logging.basicConfig()  # <--- required, or I don't get any log messages
         self.logger = logging.getLogger(self.daemon_name)
         self.logger.debug( "Created logger successfully" )

    def run(self):
        with daemon.daemonContext( files_preserve = [self.logger.handlers[0].stream] )
            self.logger.debug( "Daemonised successfully - about to enter function" )
            function_to_run_as_daemon()

if __name__ == "__main__":
    d = daemon()
    d.run()

Then in ipython i would run something like

>>> import logging
>>> rootlogger = logging.getLogger()
>>> rootlogger.info( "test" )
INFO:root:"test"
>>> subprocess.Popen( ["python" , "daemon_script.py"] )
DEBUG:__main__:"Created logger successfully"
DEBUG:__main__:"Daemonised successfully - about to enter function"
# now i'm finished debugging and testing, i want to reduce the level for all the loggers by changing the level of the handler
# Note that I also tried changing the level of the root handler, but saw no change
>>> rootlogger.handlers[0].setLevel(logging.INFO)
>>> rootlogger.info( "test" )
INFO:root:"test"
>>> print( rootlogger.debug("test") )
None
>>> subprocess.Popen( ["python" , "daemon_script.py"] )
DEBUG:__main__:"Created logger successfully"
DEBUG:__main__:"Daemonised successfully - about to enter function"

I think that I may not be approaching this correctly, but, its not clear to me what would work better. Any advice would be appreciated.


Solution

  • The logger you create in your daemon won't be the same as the logger you made in ipython. You could test this to be sure, by just printing out both logger objects themselves, which will show you their memory addresses.

    I think a better pattern would be be that you pass if you want to be in "debug" mode or not, when you run the daemon. In other words, call popen like this:

    subprocess.Popen( ["python" , "daemon_script.py", "debug"] )
    

    It's up to you, you could pass a string meaning "debug mode is on" as above, or you could pass the log level constant that means "debug", e.g.: subprocess.Popen( ["python" , "daemon_script.py", "10"] ) (https://docs.python.org/2/library/logging.html#levels)

    Then in the daemon's init function use argv for example, to get that argument and use it:

    ...
    import sys
    
    def __init__(self):
         self.daemon_name = __name__
         logging.basicConfig()  # <--- required, or I don't get any log messages
         log_level = int(sys.argv[1])  # Probably don't actually just blindly convert it without error handling
         self.logger = logging.getLogger(self.daemon_name)
         self.logger.setLevel(log_level)
         ...