2016-07-29 5 views
0

У меня есть много кода в проекте с заявками на печать и вы хотите быстро найти грязный регистратор этих заявлений на печать и решили пойти по собственному маршруту. Мне удалось собрать регистратор, который печатает как на терминал, так и на файл (с помощью этого сайта), но теперь я хочу добавить простую метку времени для каждого оператора, и у меня возникает странная проблема.Пользовательский логгер с меткой времени в python

Вот мой класс ведения журнала.

class Logger(object): 
    def __init__(self, stream): 
     self.terminal = stream 
     self.log = open("test.log", 'a') 

    def write(self, message): 
     self.terminal.flush() 
     self.terminal.write(self.stamp() + message) 
     self.log.write(self.stamp() + message) 

    def stamp(self): 
     d = datetime.today() 
     string = d.strftime("[%H:%M:%S] ") 
     return string 

Обратите внимание на метод штампа, который затем я пытаюсь использовать в методе записи.

При запуске следующие две строки я получаю неожиданный вывод:

sys.stdout = Logger(sys.stdout) 
print("Hello World!") 

Выход:

[11:10:47] Hello World![11:10:47] 

Это то, что выход также выглядит в лог-файле, однако, я не вижу причин, почему строка, которую я добавляю, добавляется в конец. Может ли кто-нибудь помочь мне здесь?

ОБНОВЛЕНИЕ См. Ответ ниже. Однако для более быстрой ссылки проблема заключается в использовании «print()» в целом; замените его sys.stdout.write после назначения переменной.

Также используйте «протоколирование» для долгосрочных/крупных проектов сразу с места в карьер.

ответ

1

Он вызывает метод .write() вашего потока дважды, потому что в cpython print вызывает поток .write() метод дважды. Первый раз с объектом, а во второй раз он пишет символ новой строки. Например смотреть на line 138 in the pprint module in cpython v3.5.2

def pprint(self, object): 
    self._format(object, self._stream, 0, 0, {}, 0) 
    self._stream.write("\n") # <- write() called again! 

Вы можете проверить это:

>>> from my_logger import Logger # my_logger.py has your Logger class 
>>> import sys 
>>> sys.stdout = Logger(stream=sys.stdout) 
>>> sys.stdout.write('hi\n') 
[14:05:32] hi 

Вы можете заменить print(<blah>) везде в коде с помощью sed.

$ for mymodule in *.py; do 
> sed -i -E "s/print\((.+)\)/LOGGER.debug(\1)/" $mymodule 
> done 

Отъезд Python's Logging builtin module. Он имеет довольно обширную регистрацию, включая включение метки времени во всех форматах сообщений.

import logging 
FORMAT = '%(asctime)-15s %(message)s' 
DATEFMT = '%Y-%m-%d %H:%M:%S' 
logging.basicConfig(format=FORMAT, datefmt=DATEFMT) 
logger = logging.getLogger(__name__) 
logger.setLevel(logging.DEBUG) 

logger.debug('message: %s', 'message') 

Это выводит 2016-07-29 11:44:20 message: message к stdout. Также есть обработчики для отправки вывода в файлы. Существует basic tutorial, advanced tutorial и cookbook of common logging recipes.

В кулинарной книге есть пример использования simultaneous file and console loggers.

import logging 

LOGGER = logging.getLogger(__name__) # get logger named for this module 
LOGGER.setLevel(logging.DEBUG) # set logger level to debug 

# create formatter 
LOG_DATEFMT = '%Y-%m-%d %H:%M:%S' 
LOG_FORMAT = ('\n[%(levelname)s/%(name)s:%(lineno)d] %(asctime)s ' + 
       '(%(processName)s/%(threadName)s)\n> %(message)s') 
FORMATTER = logging.Formatter(LOG_FORMAT, datefmt=LOG_DATEFMT) 

CH = logging.StreamHandler() # create console handler 
CH.setLevel(logging.DEBUG) # set handler level to debug 
CH.setFormatter(FORMATTER) # add formatter to ch 
LOGGER.addHandler(CH) # add console handler to logger 

FH = logging.FileHandler('myapp.log') # create file handler 
FH.setLevel(logging.DEBUG) # set handler level to debug 
FH.setFormatter(FORMATTER) # add formatter to fh 
LOGGER.addHandler(FH) # add file handler to logger 

LOGGER.debug('test: %s', 'hi') 

Это выходы:

[DEBUG/__main__:22] 2016-07-29 12:20:45 (MainProcess/MainThread) 
> test: hi 

как к консоли и файл myapp.log одновременно.

+0

Я знаю, что Python имеет встроенную возможность ведения журнала. В настоящее время мой проект находится в состоянии замораживания, поэтому я не могу совершать серьезных изменений. Мне нужны только быстрые и грязные исправления. До тех пор, пока я не смогу реализовать лучший регистратор с вышеупомянутым модулем, я хочу только исправить мою текущую проблему, если это возможно. Если «logging» не может выводить регулярные операторы печати как на stdout, так и на файл, это не решает мою проблему. – Tristan

+0

Регистраторы Python могут иметь несколько обработчиков, _ie_: и консоль, и файл, одновременно. IMHO Я бы не стал использовать встроенный в журнал Python модуль регистрации _major change_. IMO легко использовать и быстро реализовать. И есть много преимуществ - например, вы можете легко включать и выключать его. ИМО, создающая собственный журнал с нуля, представляет собой гораздо более сложную задачу. :) –

+0

OK! Вы получили меня с тем, насколько подробно этот результат. Тем не менее, мне все еще интересно, почему моя предыдущая реализация сделала бы такую ​​странную вещь. – Tristan

0

Возможно, вам понадобится использовать символ новой строки.

class Logger(object): 
    def __init__(self, stream): 
     self.terminal = stream 
     self.log = open("test.log", 'a') 

    def write(self, message): 
     self.terminal.flush() 
     self.terminal.write(self.stamp() + message + "\n") 
     self.log.write(self.stamp() + message + "\n") 

    def stamp(self): 
     d = datetime.today() 
     string = d.strftime("[%H:%M:%S] ") 
     return string 

В любом случае, использование встроенного регистрационного модуля будет лучше.