记录器应该是参数还是全局变量?

时间:2018-05-27 21:16:31

标签: python logging conventions

在阅读Python代码时,我经常会看到这两个约定之一:

def something(logger):
  logger.info('doing something')

或:

LOGGER = logging.getLogger(__NAME__)
def something():
  LOGGER.info('doing something')

前者是否有任何优点,即线程安全,而另一个不是?或者它纯粹是一种风格差异?

1 个答案:

答案 0 :(得分:1)

如果要使用固定的记录器,请使用全局记录器:

LOGGER = logging.getLogger('stuff.do')

# logger depends on what we are
def do_stuff(operation: Callable):
    LOGGER.info('will do stuff')
    operation()
    LOGGER.info('just did stuff')

do_stuff(add_things)
do_stuff(query_things)

通常在记录共享操作以进行诊断时使用。例如,Web服务器将记录创建和销毁线程的日志。

如果要更改记录器,请使用记录器参数:

# logger depends on what we do
def do_stuff(operation: Callable, logger: Logger):
    logger.info('will do stuff')
    operation()
    logger.info('just did stuff')

do_stuff(add_things, logging.getLogger('add'))
do_stuff(query_things, logging.getLogger('query'))

通常在出于会计目的记录可配置操作时使用。例如,Web服务器将记录不同种类的请求及其结果。


使用哪种记录器完全取决于记录器的选择取决于全局还是本地数据。

如果可以全局决定记录器的选择,则这样做可以避免因记录器传递而污染功能签名。这样可以提高模块化,因为您可以添加/删除logging调用而无需更改其他代码。使用日志记录查找错误时,您可能希望将日志记录添加到可疑的代码节,并将其从经过验证的代码节中删除。

如果记录器的选择取决于本地状态,则传递记录器或其名称通常是唯一的选择。使用日志记录正在发生的事情时,您有时有时希望稍后再添加新的操作主题。


使用任何一种方法都没有运行时或安全性优势,除了避免操作将事情四处传递。 logging模块被设计为线程安全的:

  

Thread Safety

     

日志模块旨在实现线程安全,而无需   客户需要完成的任何特殊工作。它实现了   尽管使用了线程锁;有一个锁可以序列化对   模块的共享数据,并且每个处理程序还会创建一个锁   序列化对其底层I / O的访问。

完全等同于为同一记录器创建一个新的“实例”,或为同一记录器创建一个别名:

>>> a = logging.getLogger('demo')
>>> b = a
>>> c = logging.getLogger('demo')
>>> a is b is c
True