Подтвердить что ты не робот

Перенаправить вывод 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 в файл аналогичным образом (см. перенаправление отпечатков в файл журнала)

4b9b3361

Ответ 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" в том же каталоге, ничего не будет на консоли/стандартный вывод)

чтобы напечатать ошибку вывода/информацию как в файле, так и в консоли, удалите две строки выше.

Счастливое Кодирование Ура !!!