使 logging.LoggerAdapter 可用于其他模块的优雅方式
Elegant way to make logging.LoggerAdapter available to other modules
我使用 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,如 [=19= 打印的那样]?
或者,您可以实现自定义记录器,并将其设为日志记录模块中的默认记录器。
示例如下:
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
我认为你需要覆盖 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
我遇到了类似的问题。我的解决方案可能比 .
更通用一些
我也使用了自定义记录器 class,但我做了一个通用扩展,允许我在实例化后注册适配器。
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)
为了使您的记录器使用 class,您必须在将其用于其他地方之前对其进行实例化。例如使用:
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()
.
兼容的签名的过程方法即可
我使用 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,如 [=19= 打印的那样]?
或者,您可以实现自定义记录器,并将其设为日志记录模块中的默认记录器。
示例如下:
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
我认为你需要覆盖 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
我遇到了类似的问题。我的解决方案可能比
我也使用了自定义记录器 class,但我做了一个通用扩展,允许我在实例化后注册适配器。
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)
为了使您的记录器使用 class,您必须在将其用于其他地方之前对其进行实例化。例如使用:
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()
.