我一直试图通过子类Logger
来创建一个新的logging.Logger
类。Python版本为3.5
我在我的应用程序中有几个模块,我只在主模块中配置日志记录,在这个模块中,我使用logging.setLoggerClass(...)
设置记录器类。
但是,当我从其他模块检索相同的Logger实例时,它仍然创建Logger
类的新实例,而不是我定义的子类实例。
例如,我的代码是:
# module 1
import logging
class MyLoggerClass(logging.getLoggerClass()):
def __init__(name):
super(MyLoggerClass, self).__init__(name)
def new_logger_method(...):
# some new functionality
if __name__ == "__main__":
logging.setLoggerClass(MyLoggerClass)
mylogger = logging.getLogger("mylogger")
# configuration of mylogger instance
# module 2
import logging
applogger = logging.getLogger("mylogger")
print(type(applogger))
def some_function():
applogger.debug("in module 2 some_function")
在执行此代码时,我希望模块2中的applogger
是MyLoggerClass
类型的。我打算将new_logger_method
用于一些新功能。
但是,由于applogger
的类型是logging.Logger
,所以当代码运行时,抛出Logger
没有名为new_logger_method
的属性。
有没有人面临过这个问题?
提前感谢您的帮助!普拉纳夫
发布于 2018-05-17 14:28:50
如果您希望模块能够很好地处理任何环境,而不是试图通过更改默认的记录器工厂来影响全局logger
,您应该只为模块(及其子模块)定义一个记录器,并将其用作模块结构中其他更深层次的所有内容的主记录器。问题在于,您显式地希望使用与默认/全局定义的类不同的logging.Logger
类,而logging
模块并不提供一种轻松的方法来进行基于上下文的工厂切换,因此您必须自己完成。
有很多方法可以做到这一点,但我个人的偏好是尽可能明确地定义自己的logger
模块,然后在您需要获得自定义记录器时将其导入包中的其他模块中。在您的示例中,您可以在包的根部创建logger.py
,并执行如下操作:
import logging
class CustomLogger(logging.Logger):
def __init__(self, name):
super(CustomLogger, self).__init__(name)
def new_logger_method(self, caller=None):
self.info("new_logger_method() called from: {}.".format(caller))
def getLogger(name=None, custom_logger=True):
if not custom_logger:
return logging.getLogger(name)
logging_class = logging.getLoggerClass() # store the current logger factory for later
logging._acquireLock() # use the global logging lock for thread safety
try:
logging.setLoggerClass(CustomLogger) # temporarily change the logger factory
logger = logging.getLogger(name)
logging.setLoggerClass(logging_class) # be nice, revert the logger factory change
return logger
finally:
logging._releaseLock()
如果您愿意的话,可以随意地在其中包含其他自定义日志初始化逻辑。然后,从您的其他模块(和子包)中,您可以导入这个记录器,并使用它的getLogger()
获得一个本地的、自定义的记录器。例如,在module1.py
中您所需要的就是:
from . import logger # or `from package import logger` for external/non-relative use
log = logger.getLogger(__name__) # obtain a main logger for this module
def test(): # lets define a function we can later call for testing
log.new_logger_method("Module 1")
这包括内部使用--只要在所有模块/子模块中坚持这种模式,您就可以访问自定义记录器。
当涉及到外部使用时,您可以编写一个简单的测试,以表明您的自定义记录器被创建了和,它不会干扰日志系统的其他部分,因此您的包/模块可以被宣布为一个好公民。假设您的module1.py
位于一个名为package
的包中,并且希望从外部对其进行整体测试:
import logging # NOTE: we're importing the global, standard `logging` module
import package.module1
logging.basicConfig() # initialize the most rudimentary root logger
root_logger = logging.getLogger() # obtain the root logger
root_logger.setLevel(logging.DEBUG) # set root log level to DEBUG
# lets see the difference in Logger types:
print(root_logger.__class__) # <class 'logging.RootLogger'>
print(package.module1.log.__class__) # <class 'package.logger.CustomLogger'>
# you can also obtain the logger by name to make sure it's in the hierarchy
# NOTE: we'll be getting it from the standard logging module so outsiders need
# not to know that we manage our logging internally
print(logging.getLogger("package.module1").__class__) # <class 'package.logger.CustomLogger'>
# and we can test that it indeed has the custom method:
logging.getLogger("package.module1").new_logger_method("root!")
# INFO:package.module1:new_logger_method() called from: root!.
package.module1.test() # lets call the test method within the module
# INFO:package.module1:new_logger_method() called from: Module 1.
# however, this will not affect anything outside of your package/module, e.g.:
test_logger = logging.getLogger("test_logger")
print(test_logger.__class__) # <class 'logging.Logger'>
test_logger.info("I am a test logger!")
# INFO:test_logger:I am a test logger!
test_logger.new_logger_method("root - test")
# AttributeError: 'Logger' object has no attribute 'new_logger_method'
https://stackoverflow.com/questions/50398444
复制