How to change Python protocol file descriptor on the fly with different classes and imports

I can’t modify the recording file on the fly.

For example, I have 3 classes

one.py

 import logging class One(): def __init__(self,txt="?"): logging.debug("Hey, I'm the class One and I say: %s" % txt) 

two.py

 import logging class Two(): def __init__(self,txt="?"): logging.debug("Hey, I'm the class Two and I say: %s" % txt) 

config.py

 import logging class Config(): def __init__(self,logfile=None): logging.debug("Reading config") self.logfile(logfile) 

myapp

 from one import One from two import Two from config import Config import logging #Set default logging logging.basicConfig( level=logging.getLevelName(DEBUG), format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', filename=None ) logging.info("Starting with stdout") o=One(txt="STDOUT") c=Config(logfile="/tmp/logfile") # Here must be the code that change the logging configuration and set the filehandler t=One(txt="This must be on the file, not STDOUT") 

If I try loggin.basicConfig() again, this will not work.

+31
python logging configuration
Dec 12 '12 at 12:14
source share
4 answers

Indeed, logging.basicConfig does nothing if the handler is already configured:

This function does nothing if the root registrar has already configured handlers for it.

You will need to replace the current handler in the root log:

 import logging fileh = logging.FileHandler('/tmp/logfile', 'a') formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fileh.setFormatter(formatter) log = logging.getLogger() # root logger for hdlr in log.handlers[:]: # remove all old handlers log.removeHandler(hdlr) log.addHandler(fileh) # set the new handler 

See Configuring logging in the Python HOWTO log.

+41
Dec 12 '12 at 12:25
source share

I found a simpler way than the above “accepted” answer. If you have a reference to the handler, all you have to do is call the close () method and then set the baseFilename property. When you assign baseFilename, be sure to use os.path.abspath (). There is a comment in the library source that indicates that this is necessary. I save my configuration files in a global dict (), so it's easy to save FileHandler reference objects. As you can see below, changing a log file name for a handler on the fly requires only two lines of code.

 import logging def setup_logging(): global config if config['LOGGING_SET']: config['LOG_FILE_HDL'].close() config['LOG_FILE_HDL'].baseFilename = os.path.abspath(config['LOG_FILE']) config['DEBUG_LOG_HDL'].close() config['DEBUG_LOG_HDL'].baseFilename = os.path.abspath(config['DEBUG_LOG']) else: format_str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' formatter = logging.Formatter(format_str) log = logging.getLogger() log.setLevel(logging.DEBUG) # add file mode="w" to overwrite config['LOG_FILE_HDL'] = logging.FileHandler(config['LOG_FILE'], mode='a') config['LOG_FILE_HDL'].setLevel(logging.INFO) config['LOG_FILE_HDL'].setFormatter(formatter) log.addHandler(config['LOG_FILE_HDL']) # the delay=1 should prevent the file from being opened until used. config['DEBUG_LOG_HDL'] = logging.FileHandler(config['DEBUG_LOG'], mode='a', delay=1) config['DEBUG_LOG_HDL'].setLevel(logging.DEBUG) config['DEBUG_LOG_HDL'].setFormatter(formatter) log.addHandler(config['DEBUG_LOG_HDL']) ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(formatter) log.addHandler(ch) config['LOGGING_SET'] = True 
+6
Jan 31 '16 at 21:59
source share

The answer provided by @Martijn Pieters is good. However, snipper code removes all handlers and puts only the file handler back. This will be problematic if your application has handlers added by other modules.

Therefore, the snippet below is designed to replace only the file handler.

The line if isinstance(hdlr,log.FileHander) is the key.

 import logging filehandler = logging.FileHandler('/tmp/logfile', 'a') formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s') filehandler.setFormatter(formatter) log = logging.getLogger() # root logger - Good to get it only once. for hdlr in log.handlers[:]: # remove the existing file handlers if isinstance(hdlr,log.FileHander): log.removeHandler(hdlr) log.addHandler(filehandler) # set the new handler # set the log level to INFO, DEBUG as the default is ERROR logging.setLevel(log.DEBUG) 
+3
Nov 23 '17 at 4:13
source share

I tried to implement the suggestions on this page from @Martijn Pieters in conjunction with @Arun Thundyill Saseendran. I'm too new to be able to comment, so I have to post the adjusted answer. In the isinstance call, I had to use "logging" instead of "log" to access the types (log was an instance), and then "FileHander" should be "FileHandler". I am using Python 3.6.

 import logging filehandler = logging.FileHandler('/tmp/logfile', 'a') formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s') filehandler.setFormatter(formatter) log = logging.getLogger() # root logger - Good to get it only once. for hdlr in log.handlers[:]: # remove the existing file handlers if isinstance(hdlr,logging.FileHandler): #fixed two typos here log.removeHandler(hdlr) log.addHandler(filehandler) # set the new handler # set the log level to INFO, DEBUG as the default is ERROR logging.setLevel(log.DEBUG) 
0
Jan 23 '19 at 22:08
source share



All Articles