Печать в STDOUT и файл журнала при удалении цветовых кодов ANSI - PullRequest
7 голосов
/ 24 мая 2010

У меня есть следующие функции для раскрашивания экранных сообщений:

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

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

Я использую их следующим образом:

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

Я хочу записать вывод в файл (дополнительнов STDOUT) БЕЗ цветовых кодов ANSI, надеюсь, без необходимости добавлять вторую строчку «logging» к каждому оператору print.

Причина в том, что если вы просто python program.py > out, тогда файл outесть коды цвета ANSI, которые выглядят ужасно, если вы откроете их в текстовом редакторе.

Любой совет?

Ответы [ 3 ]

10 голосов
/ 24 мая 2010

Функция sys.stdout.isatty может помочь:

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

Это фактически одно из немногих применений, о которых я могу подумать, чтобы использовать аргумент по умолчанию, который не установлен на None, потому что аргументы по умолчанию оцениваются во время компиляции в Python, а не во время выполнения, как в C ++ ...

Кроме того, поведение может быть явно переопределено, если вам действительно это нужно, хотя это не позволяет вам манипулировать самим stdout, когда он перенаправляется. Есть ли причина, по которой вы не используете модуль logging (возможно, вы об этом не знали)?

6 голосов
/ 24 мая 2010

Если вы хотите печатать как на терминал, так и в файл журнала, то я бы предложил использовать модуль регистрации. Вы даже можете определить пользовательский форматировщик, поэтому регистрация в файле может очистить коды терминала:

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 печать только на терминал.

test.py -l test.out печатает как на терминал, так и в файл test.out.

Во всех случаях текст на терминале имеет цветовые коды, а протоколирование - нет.

1 голос
/ 26 января 2017

Ответ unubtu ниже велик, но я думаю, что MyFormatter нуждается в незначительной модификации для обеспечения форматирования в методе format ()

class MyFormatter(logging.Formatter):
        def format(self,record):
            msg = super(MyFormatter, self).format(record)
            return plain(msg)
...