如何使用不同的类和导入动态地使用Python日志记录来更改文件句柄

xki*_*ill 42 python configuration logging

我无法执行即时记录文件手柄更改.

例如,我有3个班级

one.py

import logging
class One():
    def __init__(self,txt="?"):
        logging.debug("Hey, I'm the class One and I say: %s" % txt)
Run Code Online (Sandbox Code Playgroud)

two.py

import logging
class Two():
    def __init__(self,txt="?"):
        logging.debug("Hey, I'm the class Two and I say: %s" % txt)
Run Code Online (Sandbox Code Playgroud)

config.py

import logging
class Config():
    def __init__(self,logfile=None):
        logging.debug("Reading config")
        self.logfile(logfile)
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

如果我再试loggin.basicConfig()一次,它就不起作用了.

Mar*_*ers 57

事实上,logging.basicConfig什么,如果处理程序已经成立已:

如果根记录器已经为其配置了处理程序,则此函数不执行任何操作.

您需要替换根记录器上的当前处理程序:

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
Run Code Online (Sandbox Code Playgroud)

请参阅Python Logging HOWTO中的" 配置日志记录"一章.


小智 7

我找到了一种比上面"接受"的答案更简单的方法.如果您有对处理程序的引用,那么您需要做的就是调用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
Run Code Online (Sandbox Code Playgroud)

  • @user2179204 你悲伤“更容易”并写了四倍的代码行 - 这不是Python的方式。 (3认同)
  • 即使您不保存对处理程序的引用,如果您的记录器中只有一个处理程序,您也可以直接引用它并使用相同的技术:`mylogger = logging.getLogger('mylogger') # get logger` 然后`mylogger.handlers[0].close() mylogger.handlers[0].baseFilename = os.path.abspath('newfilename.log')` (2认同)

T. *_*gis 6

我尝试结合 @Martijn Pieters 和 @Arun Thundyill Saseendran 实施此页面上的建议。我太新了,无法发表评论,所以我必须发布调整后的答案。在 isinstance 调用中,我必须使用“logging”而不是“log”来访问类型(log 是一个实例),然后“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)      
Run Code Online (Sandbox Code Playgroud)


Aru*_*ran 5

@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)      
Run Code Online (Sandbox Code Playgroud)