【问题标题】:Elegant way to make logging.LoggerAdapter available to other modules使 logging.LoggerAdapter 可用于其他模块的优雅方式
【发布时间】:2015-03-18 23:35:08
【问题描述】:

我使用 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 输出 Linux 线程 ID,如 ps 打印的那样?

【问题讨论】:

    标签: python logging module


    【解决方案1】:

    我遇到了类似的问题。我的解决方案可能比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)
    

    为了让你记录器使用这个类,你必须先实例化它,然后才能在其他地方使用它。例如使用:

    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() 兼容的签名的过程方法。

    【讨论】:

      【解决方案2】:

      我认为你需要重写 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 
      

      【讨论】:

        【解决方案3】:

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

        示例如下:

        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
        

        【讨论】:

          猜你喜欢
          • 2013-11-14
          • 1970-01-01
          • 1970-01-01
          • 2018-04-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-09
          相关资源
          最近更新 更多