I have the following functions for colorizing my screen messages:
def error(string):
return '\033[31;1m' + string + '\033[0m'
def standout(string):
return '\033[34;1m' + string + '\033[0m'
I use them as follows:
print error('There was a problem with the program')
print "This is normal " + standout("and this stands out")
I want to log the output to a file (in addition to STDOUT) WITHOUT the ANSI color codes, hopefully without having to add a second "logging" line to each print
statement.
The reason is that if you simply python program.py > out
then the file out
will have the ANSI color codes, which look terrible if you open in a plain text editor.
Any advice?
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)