Printing to STDOUT and log file while removing ANSI color codes

无人久伴 提交于 2019-12-04 05:03:35

The sys.stdout.isatty function might be able to help:

from sys import stdout

def error(string, is_tty=stdout.isatty()):
    return ('\033[31;1m' + string + '\033[0m') if is_tty else string

def standout(string, is_tty=stdout.isatty()):
    return ('\033[34;1m' + string + '\033[0m') if is_tty else string

That's actually one of the few uses I can think of to use a default argument that isn't set to None because default arguments are evaluated at compile time in Python rather than at runtime like in C++...

Also the behaviour can be explicitly overridden if you really need to, though that doesn't let you manipulate stdout itself when it's redirected. Is there any reason why you're not using the logging module (perhaps you didn't know about it)?

If you wish to print to both the terminal and to a log file, then I'd suggest using the logging module. You can even define a custom formatter, so logging to the file can purge the terminal codes:

import optparse
import logging

def error(string):
    return '\033[31;1m' + string + '\033[0m'

def standout(string):
    return '\033[34;1m' + string + '\033[0m'

def plain(string):
    return string.replace('\033[34;1m','').replace('\033[31;1m','').replace('\033[0m','')

if __name__=='__main__':
    logging.basicConfig(level=logging.DEBUG,
                        format='%(message)s',
                        filemode='w')
    logger=logging.getLogger(__name__)    
    def parse_options():    
        usage = 'usage: %prog [Options]'
        parser = optparse.OptionParser()
        parser.add_option('-l', '--logfile', dest='logfile', 
                          help='use log file')
        opt,args = parser.parse_args()
        return opt,args
    opt,args=parse_options()
    if opt.logfile:
        class MyFormatter(logging.Formatter):
            def format(self,record):
                return plain(record.msg)
        fh = logging.FileHandler(opt.logfile)
        fh.setLevel(logging.INFO)
        formatter = MyFormatter('%(message)s')
        fh.setFormatter(formatter)
        logging.getLogger('').addHandler(fh)

    logger.info(error('There was a problem with the program'))
    logger.info("This is normal " + standout("and this stands out"))

test.py prints only to the terminal.

test.py -l test.out prints to both the terminal and to the file test.out.

In all cases, the text to the terminal has color codes, while the logging has none.

unubtu's answer below is great but I think MyFormatter needs a minor modification to enforce formatting in the format() method

class MyFormatter(logging.Formatter):
        def format(self,record):
            msg = super(MyFormatter, self).format(record)
            return plain(msg)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!