How to write custom python logging handler?

Python Programming

Question or problem about Python programming:

How to write custom console log function to output only on the console window log messages on a single line (not append) until the first regular log record.

progress = ProgressConsoleHandler()
console = logging.StreamHandler()
logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG)
logger.addHandler(console)
logger.addHandler(progress)
logger.info('test1')
for i in range(3):
logger.progress('remaining %d seconds' % i)
time.sleep(1)
logger.info('test2')
progress = ProgressConsoleHandler() console = logging.StreamHandler() logger = logging.getLogger('test') logger.setLevel(logging.DEBUG) logger.addHandler(console) logger.addHandler(progress) logger.info('test1') for i in range(3): logger.progress('remaining %d seconds' % i) time.sleep(1) logger.info('test2')
progress = ProgressConsoleHandler()
console  = logging.StreamHandler()  

logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG) 
logger.addHandler(console)  
logger.addHandler(progress)

logger.info('test1')
for i in range(3):
    logger.progress('remaining %d seconds' % i)
    time.sleep(1)   
logger.info('test2')

So that the console output is only three lines:

INFO: test1
remaining 0 seconds...
INFO: test2
INFO: test1 remaining 0 seconds... INFO: test2
INFO: test1
remaining 0 seconds... 
INFO: test2

Any suggestions on the best way on how to implement this?

How to solve the problem:

import logging
class ProgressConsoleHandler(logging.StreamHandler):
"""
A handler class which allows the cursor to stay on
one line for selected messages
"""
on_same_line = False
def emit(self, record):
try:
msg = self.format(record)
stream = self.stream
same_line = hasattr(record, 'same_line')
if self.on_same_line and not same_line:
stream.write(self.terminator)
stream.write(msg)
if same_line:
stream.write('... ')
self.on_same_line = True
else:
stream.write(self.terminator)
self.on_same_line = False
self.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
if __name__ == '__main__':
import time
progress = ProgressConsoleHandler()
console = logging.StreamHandler()
logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG)
logger.addHandler(progress)
logger.info('test1')
for i in range(3):
logger.info('remaining %d seconds', i, extra={'same_line':True})
time.sleep(1)
logger.info('test2')
import logging class ProgressConsoleHandler(logging.StreamHandler): """ A handler class which allows the cursor to stay on one line for selected messages """ on_same_line = False def emit(self, record): try: msg = self.format(record) stream = self.stream same_line = hasattr(record, 'same_line') if self.on_same_line and not same_line: stream.write(self.terminator) stream.write(msg) if same_line: stream.write('... ') self.on_same_line = True else: stream.write(self.terminator) self.on_same_line = False self.flush() except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record) if __name__ == '__main__': import time progress = ProgressConsoleHandler() console = logging.StreamHandler() logger = logging.getLogger('test') logger.setLevel(logging.DEBUG) logger.addHandler(progress) logger.info('test1') for i in range(3): logger.info('remaining %d seconds', i, extra={'same_line':True}) time.sleep(1) logger.info('test2')
import logging
class ProgressConsoleHandler(logging.StreamHandler):
    """
    A handler class which allows the cursor to stay on
    one line for selected messages
    """
    on_same_line = False
    def emit(self, record):
        try:
            msg = self.format(record)
            stream = self.stream
            same_line = hasattr(record, 'same_line')
            if self.on_same_line and not same_line:
                stream.write(self.terminator)
            stream.write(msg)
            if same_line:
                stream.write('... ')
                self.on_same_line = True
            else:
                stream.write(self.terminator)
                self.on_same_line = False
            self.flush()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)
if __name__ == '__main__':
    import time
    progress = ProgressConsoleHandler()
    console  = logging.StreamHandler()  

    logger = logging.getLogger('test')
    logger.setLevel(logging.DEBUG) 
    logger.addHandler(progress)

    logger.info('test1')
    for i in range(3):
        logger.info('remaining %d seconds', i, extra={'same_line':True})
        time.sleep(1)   
    logger.info('test2')

Notice that only one handler is being registered, and the extra keyword argument to let the handler know it should stay on one line. There is more logic in the emit() method to handle changes between messages that should stay on one line and messages that need to have their own line.

Hope this helps!