オンザフライのロギングfileHandleの変更を実行できません。
たとえば、3つのクラスがあります
_one.py
_
_import logging
class One():
def __init__(self,txt="?"):
logging.debug("Hey, I'm the class One and I say: %s" % txt)
_
_two.py
_
_import logging
class Two():
def __init__(self,txt="?"):
logging.debug("Hey, I'm the class Two and I say: %s" % txt)
_
_config.py
_
_import logging
class Config():
def __init__(self,logfile=None):
logging.debug("Reading config")
self.logfile(logfile)
_
myapp
_from one import One
from two import Two
from config import Config
import logging
#Set default logging
logging.basicConfig(
level=logging.getLevelName(DEBUG),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename=None
)
logging.info("Starting with stdout")
o=One(txt="STDOUT")
c=Config(logfile="/tmp/logfile")
# Here must be the code that change the logging configuration and set the filehandler
t=One(txt="This must be on the file, not STDOUT")
_
loggin.basicConfig()
を再試行すると、機能しません。
確かに、 logging.basicConfig
は、ハンドラーが既にセットアップされている場合、nothingを行います。
ルートロガーにすでにハンドラーが設定されている場合、この関数は何もしません。
ルートロガーの現在のハンドラーをreplaceする必要があります。
import logging
fileh = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fileh.setFormatter(formatter)
log = logging.getLogger() # root logger
for hdlr in log.handlers[:]: # remove all old handlers
log.removeHandler(hdlr)
log.addHandler(fileh) # set the new handler
Python Logging HOWTO。の ロギングの設定の章 を参照してください。
上記の「受け入れられた」答えよりも簡単な方法を見つけました。ハンドラーへの参照がある場合は、close()メソッドを呼び出してからbaseFilenameプロパティを設定するだけです。 baseFilenameを割り当てるときは、必ずos.path.abspath()を使用してください。ライブラリソースには、必要であることを示すコメントがあります。私は設定項目をグローバルdict()に保持しているため、FileHandler参照オブジェクトを簡単に保持できます。以下に示すように、ハンドラーのログファイル名をオンザフライで変更するのに必要なコードは2行だけです。
import logging
def setup_logging():
global config
if config['LOGGING_SET']:
config['LOG_FILE_HDL'].close()
config['LOG_FILE_HDL'].baseFilename = os.path.abspath(config['LOG_FILE'])
config['DEBUG_LOG_HDL'].close()
config['DEBUG_LOG_HDL'].baseFilename = os.path.abspath(config['DEBUG_LOG'])
else:
format_str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
formatter = logging.Formatter(format_str)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
# add file mode="w" to overwrite
config['LOG_FILE_HDL'] = logging.FileHandler(config['LOG_FILE'], mode='a')
config['LOG_FILE_HDL'].setLevel(logging.INFO)
config['LOG_FILE_HDL'].setFormatter(formatter)
log.addHandler(config['LOG_FILE_HDL'])
# the delay=1 should prevent the file from being opened until used.
config['DEBUG_LOG_HDL'] = logging.FileHandler(config['DEBUG_LOG'], mode='a', delay=1)
config['DEBUG_LOG_HDL'].setLevel(logging.DEBUG)
config['DEBUG_LOG_HDL'].setFormatter(formatter)
log.addHandler(config['DEBUG_LOG_HDL'])
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
log.addHandler(ch)
config['LOGGING_SET'] = True
@Martijn Pietersが提供する答えはうまくいきます。ただし、コードスニッパーはすべてのハンドラーを削除し、ファイルハンドラーのみを戻します。アプリケーションに他のモジュールによって追加されたハンドラーがある場合、これは面倒です。
したがって、以下のスニペットは、ファイルハンドラーのみを置き換えるように設計されています。
行if isinstance(hdlr,log.FileHander)
がキーです。
import logging
filehandler = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s')
filehandler.setFormatter(formatter)
log = logging.getLogger() # root logger - Good to get it only once.
for hdlr in log.handlers[:]: # remove the existing file handlers
if isinstance(hdlr,log.FileHander):
log.removeHandler(hdlr)
log.addHandler(filehandler) # set the new handler
# set the log level to INFO, DEBUG as the default is ERROR
logging.setLevel(log.DEBUG)
このページの提案を、@ Arun Thundyill Saseendranと組み合わせた@Martijn Pietersから実装しようとしました。私はあまりにも新しいのでコメントできませんので、調整済みの回答を投稿する必要があります。 isinstance呼び出しでは、型にアクセスするために「ログ」ではなく「ログ」を使用する必要があり(ログはインスタンスでした)、「FileHander」は「FileHandler」になります。私はPython 3.6。
import logging
filehandler = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s')
filehandler.setFormatter(formatter)
log = logging.getLogger() # root logger - Good to get it only once.
for hdlr in log.handlers[:]: # remove the existing file handlers
if isinstance(hdlr,logging.FileHandler): #fixed two typos here
log.removeHandler(hdlr)
log.addHandler(filehandler) # set the new handler
# set the log level to INFO, DEBUG as the default is ERROR
logging.setLevel(log.DEBUG)