I cannot perform an on-the-fly logging fileHandle change.
我无法执行即时记录文件手柄更改。
For example, I have 3 classes
例如,我有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")
If I try loggin.basicConfig()
again, it doesn't work.
如果我再次尝试loggin.basicConfig(),它不起作用。
3 个解决方案
#1
38
Indeed, logging.basicConfig
does nothing if a handler has been set up already:
实际上,如果已经设置了处理程序,logging.basicConfig什么都不做:
This function does nothing if the root logger already has handlers configured for it.
如果根记录器已经为其配置了处理程序,则此函数不执行任何操作。
You'll need to replace the current handler on the root logger:
您需要替换根记录器上的当前处理程序:
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
See the Configuring Logging chapter in the Python Logging HOWTO.
请参阅Python Logging HOWTO中的“配置日志记录”一章。
#2
6
I found an easier way than the above 'accepted' answer. If you have a reference to the handler, all you need to do is call the close() method and then set the baseFilename property. When you assign baseFilename, be sure to use os.path.abspath(). There's a comment in the library source that indicates it's needed. I keep my configuration stuff in a global dict() so it's easy to keep the FileHandler reference objects. As you can see below, it only takes 2 lines of code to change a log filename for a handler on the fly.
我找到了一个比上面“接受”的答案更简单的方法。如果您有对处理程序的引用,那么您需要做的就是调用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
#3
2
The answer provided by @Martijn Pieters works good. However, the code snipper removes all handlers and placed only the file handler back. This will be troublesome if your application has handlers added by other modules.
@Martijn Pieters提供的答案很好。但是,代码片段会删除所有处理程序并仅放回文件处理程序。如果您的应用程序有其他模块添加的处理程序,这将很麻烦。
Hence, the below snippet is designed in such a way to replace only the file handler.
因此,下面的代码片段设计为仅替换文件处理程序。
The line if isinstance(hdlr,log.FileHander)
is the key.
如果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)
#1
38
Indeed, logging.basicConfig
does nothing if a handler has been set up already:
实际上,如果已经设置了处理程序,logging.basicConfig什么都不做:
This function does nothing if the root logger already has handlers configured for it.
如果根记录器已经为其配置了处理程序,则此函数不执行任何操作。
You'll need to replace the current handler on the root logger:
您需要替换根记录器上的当前处理程序:
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
See the Configuring Logging chapter in the Python Logging HOWTO.
请参阅Python Logging HOWTO中的“配置日志记录”一章。
#2
6
I found an easier way than the above 'accepted' answer. If you have a reference to the handler, all you need to do is call the close() method and then set the baseFilename property. When you assign baseFilename, be sure to use os.path.abspath(). There's a comment in the library source that indicates it's needed. I keep my configuration stuff in a global dict() so it's easy to keep the FileHandler reference objects. As you can see below, it only takes 2 lines of code to change a log filename for a handler on the fly.
我找到了一个比上面“接受”的答案更简单的方法。如果您有对处理程序的引用,那么您需要做的就是调用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
#3
2
The answer provided by @Martijn Pieters works good. However, the code snipper removes all handlers and placed only the file handler back. This will be troublesome if your application has handlers added by other modules.
@Martijn Pieters提供的答案很好。但是,代码片段会删除所有处理程序并仅放回文件处理程序。如果您的应用程序有其他模块添加的处理程序,这将很麻烦。
Hence, the below snippet is designed in such a way to replace only the file handler.
因此,下面的代码片段设计为仅替换文件处理程序。
The line if isinstance(hdlr,log.FileHander)
is the key.
如果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)