Перенаправить вывод Python 'print' в Logger
У меня есть Python script, который использует Print для печати в stdout. Недавно я добавил регистрацию через Python Logger и хотел бы сделать так, чтобы эти операторы печати отправлялись в журнал, если ведение журнала включено. Я не хочу изменять или удалять эти операторы печати.
Я могу войти, выполнив 'log.info( "some info msg" )'. Я хочу иметь возможность сделать что-то вроде этого:
if logging_enabled:
sys.stdout=log.info
print("test")
Если ведение журнала включено, "тест" должен регистрироваться, как если бы я сделал log.info( "test" ). Если ведение журнала не включено, "тест" следует просто распечатать на экране.
Возможно ли это? Я знаю, что я могу направить stdout в файл аналогичным образом (см. перенаправление отпечатков в файл журнала)
Ответы
Ответ 1
У вас есть два варианта:
-
Откройте файл журнала и замените sys.stdout на него, а не на функцию:
log = open("myprog.log", "a")
sys.stdout = log
>>> print("Hello")
>>> # nothing is printed because it goes to the log file instead.
-
Замените печать на функцию журнала:
# If you're using python 2.x, uncomment the next line
#from __future__ import print_function
print = log.info
>>> print("Hello!")
>>> # nothing is printed because log.info is called instead of print
Ответ 2
Конечно, вы можете печатать на стандартный вывод и добавлять к файлу журнала, например:
# Uncomment the line below for python 2.x
#from __future__ import print_function
import logging
logging.basicConfig(level=logging.INFO, format='%(message)s')
logger = logging.getLogger()
logger.addHandler(logging.FileHandler('test.log', 'a'))
print = logger.info
print('yo!')
Ответ 3
Еще один способ заключается в том, чтобы обернуть регистратор в объект, который переводит вызовы на write
в метод logger log
.
Ferry Boender делает именно это, предоставленный в соответствии с лицензией GPL в a post на его веб-сайт:
import logging
import sys
class StreamToLogger(object):
"""
Fake file-like stream object that redirects writes to a logger instance.
"""
def __init__(self, logger, log_level=logging.INFO):
self.logger = logger
self.log_level = log_level
self.linebuf = ''
def write(self, buf):
for line in buf.rstrip().splitlines():
self.logger.log(self.log_level, line.rstrip())
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s:%(levelname)s:%(name)s:%(message)s',
filename="out.log",
filemode='a'
)
stdout_logger = logging.getLogger('STDOUT')
sl = StreamToLogger(stdout_logger, logging.INFO)
sys.stdout = sl
stderr_logger = logging.getLogger('STDERR')
sl = StreamToLogger(stderr_logger, logging.ERROR)
sys.stderr = sl
Это позволяет легко маршрутизировать весь вывод в регистратор по вашему выбору. Если необходимо, вы можете сохранить sys.stdout
и/или sys.stderr
, как упоминалось другими в этом потоке, прежде чем заменять его, если вам нужно восстановить его позже.
Ответ 4
Гораздо более простой вариант,
import logging, sys
logging.basicConfig(filename='path/to/logfile', level=logging.DEBUG)
logger = logging.getLogger()
sys.stderr.write = logger.error
sys.stdout.write = logger.info
Ответ 5
Вы действительно должны сделать это другим путем: настроив конфигурацию ведения журнала на использование операторов print
или что-то еще, в зависимости от настроек. Не перезаписывайте поведение print
, так как некоторые параметры, которые могут быть введены в будущем (например, вами или кем-то другим, использующим ваш модуль), могут фактически выводить его на stdout
, и у вас будут проблемы.
Существует обработчик, который должен перенаправить ваши сообщения журнала в соответствующий поток (файл, stdout
или что-то еще подобное файлу). Он называется StreamHandler
, и он связан с модулем logging
.
Итак, в основном, на мой взгляд, вы должны делать то, что вы заявили, что не хотите делать: замените операторы print
фактическим протоколированием.
Ответ 6
После того, как вы определили свой регистратор, используйте его, чтобы перенаправить печать на регистратор даже с несколькими параметрами печати.
print = lambda *tup : logger.info(str(" ".join([str(x) for x in tup])))
Ответ 7
Для метода, который работает с 2.x см. здесь:
Цитирование
"Второй метод привлек мое внимание, когда я перечитал Learning Python во второй раз. Он включает перенаправление инструкции печати непосредственно следующим образом:
print >>output, "wello horld"
в котором вывод является записываемым объектом.
Ответ 8
Ниже приведено описание отлично работает внутри моего кода PySpark. Если кому-то нужно в случае понимания ->
import os
import sys
import logging
import logging.handlers
log = logging.getLogger(__name_)
handler = logging.FileHandler("spam.log")
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
log.addHandler(handler)
sys.stderr.write = log.error
sys.stdout.write = log.info
(регистрирует каждую ошибку в "spam.log" в том же каталоге, ничего не будет в консоли /stdout)
(будет регистрировать всю информацию в "spam.log" в том же каталоге, ничего не будет на консоли/стандартный вывод)
чтобы напечатать ошибку вывода/информацию как в файле, так и в консоли, удалите две строки выше.
Счастливое Кодирование
Ура !!!