web-dev-qa-db-ja.com

リダイレクトPython 'print'出力をロガーに出力

Python stdoutへの印刷に 'Print'を使用するスクリプトがあります。最近、Python Loggerでログを作成したいと思います。したがって、ロギングが有効になっている場合、これらのprintステートメントはロガーに送られます。これらのprintステートメントを変更または削除したくありません。

「log.info( "some info msg")」を実行してログを記録できます。私はこのようなことをしたいです:

if logging_enabled:
  sys.stdout=log.info
print("test")

ロギングが有効になっている場合、log.info( "test")を実行したかのように "test"を記録する必要があります。ロギングが有効になっていない場合、「test」が画面に出力されるだけです。

これは可能ですか?同様の方法でstdoutをファイルに送信できることを知っています( ログファイルへの出力のリダイレクト を参照)

25
Rauffle

次の2つのオプションがあります。

  1. ログファイルを開き、sys.stdoutを関数ではなく、それで置き換えます。

    log = open("myprog.log", "a")
    sys.stdout = log
    
    >>> print("Hello")
    >>> # nothing is printed because it goes to the log file instead.
    
  2. Printをログ関数に置き換えます。

    # 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
    
20
C0deH4cker

もう1つの方法は、writeへの呼び出しをロガーのlogメソッドに変換するオブジェクトでロガーをラップすることです。

フェリーベンダーはまさにこれを行い、 GPLライセンスの下で提供されます in a post on 彼のウェブサイト

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後で復元する必要がある場合に置き換える前に、このスレッドで他の人が述べたように。

11
Cory Klein

もちろん、次のように、標準出力に出力することも、ログファイルに追加することもできます。

# 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!')
11
mgmalheiros

より簡単なオプション、

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

ロガーを定義したら、これを使用して、印刷の複数のパラメーターがあっても、印刷をロガーにリダイレクトします。

print = lambda *tup : logger.info(str(" ".join([str(x) for x in tup]))) 
2
Mikus

本当に別の方法でそれを行う必要があります。設定に応じて、printステートメントなどを使用するようにロギング構成を調整します。 printの動作を上書きしないでください。将来導入される可能性のある設定の一部(たとえば、ユーザーまたはモジュールを使用する他のユーザー)が実際にstdoutに出力することがあります。問題が発生します。

ログメッセージを適切なストリーム(ファイル、stdoutまたはその他のファイルに似たもの)にリダイレクトするハンドラーがあります。 StreamHandler と呼ばれ、loggingモジュールにバンドルされています。

だから基本的にあなたがやるべきだ、あなたがしたくないと言ったことをやる:私の意見では、printステートメントを実際のログに置き換えます。

2
Tadeck