日志包有两个作用,一是帮助作者生成日志,二是帮助用户消费日志。你可能会同时扮演这两个角色,但将它们分开考虑有助于编写干净、易懂的代码。
作者关注点
作者应该在正确的级别上实例化记录器:
Package logger should go in the packages __init__
file. Note the use of __name__
, it'll resolve to SomePackage
:
import logging
package_logger = logging.getLogger(__name__)
Module logger at the top of your module. Note the power of __name__
! Here it'll resolve to SomePackage.SomeModule
.
import logging
module_logger = logging.getLogger(__name__)
Class level logger could go at the top of the class definition. Note the awesome power of __name__
enhanced with getLogger and __qualname__
! The loggers name will be SomePackage.SomeModule.SomeClass
. Also, note the underscore in _class_logger
to signal that it is for internal use.:
class SomeClass:
_class_logger = logging.getLogger(__name__).getChild(__qualname__)
Instance logger in the classes __init__
. Use ID to produce a unique identifier. Note the stupend... you get the idea. Logger name will be SomePackage.SomeModule.SomeClass.<large_unique_number>
:
class SomeClass:
def __init__(self):
self._instance_logger = logging.getLogger(__name__).getChild(self.__class__.__name__).getChild(str(id(self)))
这些名称可能不适合您的应用程序。例如,您可能希望从其实例化参数中派生一个实例记录器。但是,您仍应该在正确的级别上把握好您的记录器。
用户关注点
配置处理程序是用户的工作。通常,作者会确保默认情况下没有处理程序处于活动状态。logging.basicConfig
将所有警告级别及以上的日志记录转储到stderr。
import SomePackage
import logging
logging.basicConfig()
记住你可以使用logging.getLogger()来访问作者定义的相同记录器。
from SomePackage import SomeModule
import logging
"""
module_logger debug to a file. Will capture all
child loggers as well if used i.e class_logger and
instance_logger
"""
h = logging.FileHandler('debug')
h.setLevel('DEBUG')
SomeModule.module_logger.addHandler(h)
"""
class_logger warning to stderr. Will capture all child loggers
as well if used i.e instance_logger Note: No need to import
SomeClass to access it's logger as Logger keeps track of them in
a dictionary. Typically the prefered approach if your not
actually using the class.
"""
h = logging.StreamHandler()
getLogger('SomePackage.SomeModule.SomeClass').addHandler(h)
如果您正在直接调用自己的模块进行调试,那么您可能有一个def main()
函数,应该将它们放在里面。这可以确保包用户不会收到意外的日志文件或控制台消息。
额外的标记
如果在多个级别上使用记录器,则派生自现有记录器更具Python特色。
module_logger = logging.getLogger(__name__)
class SomeClass:
_class_logger = module_logger.getChild(__qualname__)
def __init__(self):
self._instance_logger = self._class_logger.getChild(str(id(self)))
def main()
的函数中使用,在这个函数下面我配置了日志记录器。对于一个多次调用main()
的脚本,有什么最佳实践呢? - Eney