优雅的方式使logging.LoggerAdapter可用于其他模块

时间:2015-01-20 16:30:47

标签: python logging module

我使用LoggerAdapter让我的python日志记录输出Linux TID而不是长唯一ID。但是这样我就不会修改现有的logger,但我会创建一个新对象:

    new_logger = logging.LoggerAdapter(
                    logger=logging.getLogger('mylogger'), 
                    extra=my_tid_extractor())

现在我希望某些模块可以使用LoggerAdapter。只要我知道一个全局变量被用作记录器,我就可以这样做:

    somemodule.logger = new_logger

但这并不好 - 它仅适用于几种情况,您需要知道模块使用的记录器变量。

您是否知道在全球范围内提供LoggerAdapter的方法,例如通过呼叫s.th.像

    logging.setLogger('mylogger', new_logger)

或者:还有其他方法可以让Python logging输出由ps打印的Linux线程ID吗?

3 个答案:

答案 0 :(得分:12)

或者,您可以实现自定义记录器,并将其设置为记录模块中的默认值。

以下是示例:

import logging
import ctypes

SYS_gettid = 186
libc = ctypes.cdll.LoadLibrary('libc.so.6')

FORMAT = '%(asctime)-15s [thread=%(tid)s] %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)

def my_tid_extractor():
    tid = libc.syscall(SYS_gettid)
    return {'tid': tid}

class CustomLogger(logging.Logger):

    def _log(self, level, msg, args, exc_info=None, extra=None):
        if extra is None:
            extra = my_tid_extractor()
        super(CustomLogger, self)._log(level, msg, args, exc_info, extra)

logging.setLoggerClass(CustomLogger)


logger = logging.getLogger('test')
logger.debug('test')

输出样本:

2015-01-20 19:24:09,782 [thread=5017] test

答案 1 :(得分:1)

我认为你需要覆盖LoggerAdapter.process()方法 因为默认的LoggerAdapter.process方法什么都不做,所以这是示例:

import logging
import random
L=logging.getLogger('name')

class myLogger(logging.LoggerAdapter):
    def process(self,msg,kwargs):
        return '(%d),%s' % (self.extra['name1'](1,1000),msg)  ,kwargs

#put the randint function object  
LA=myLogger(L,{'name1':random.randint})

#now,do some logging
LA.debug('some_loging_messsage')

out>>DEBUG:name:(167),some_loging_messsage 

答案 2 :(得分:0)

我遇到了类似的问题。我的解决方案可能比 accepted one 更通用。

我还使用了自定义记录器类,但我做了一个通用扩展,允许我在实例化后注册适配器。

class AdaptedLogger(logging.Logger):
    """A logger that allows you to register adapters on a instance."""

    def __init__(self, name):
        """Create a new logger instance."""
        super().__init__(name)
        self.adapters = []

    def _log(self, level, msg, *args, **kwargs):
        """Let adapters modify the message and keyword arguments."""
        for adapter in self.adapters:
            msg, kwargs = adapter.process(msg, kwargs)
        return super()._log(level, msg, *args, **kwargs)

为了让您使用 logger 类,您必须先实例化它,然后才能在其他地方使用它。例如使用:

original_class = logging.getLoggerClass()
logging.setLoggerClass(AdaptedLogger)
logcrm_logger = logging.getLogger("test")
logging.setLoggerClass(original_class)

然后您可以随时在实例上注册适配器。

logger = logging.getLogger("test")
adapter = logging.LoggerAdapter(logger, extra=my_tid_extractor())
logger.adapters.append(adapter)

实际上,“适配器”现在可以是任何对象,只要它们具有签名与 logging.LoggingAdapter.process() 兼容的进程方法即可。