为每个异步函数调用创建一个新的记录器,好主意与否?

twi*_*dor 5 python logging python-asyncio

在编写 Python 异步程序时,通常会有一个异步函数同时运行许多调用。我想为这个函数添加一些日志记录,但是来自不同调用的日志记录输出将交错,使其难以跟踪。我目前的解决方案是以某种方式为每次调用创建一个唯一的名称,并每次记录该名称,如下所示:

async def make_request(args):
    logger = logging.getLogger('myscript.request')
    log_name = unique_name()
    logger.debug('[%s] making request with args %r', log_name, args)
    response = await request(args)
    logger.debug('[%s] response: %r', log_name, response)
Run Code Online (Sandbox Code Playgroud)

但是,必须log_name输入每个日志记录调用会很快变得很累。为了保存这些击键,我想出了一个不同的解决方案,为每次调用创建一个具有唯一名称的新记录器:

async def make_request(args):
    logger = logging.getLogger(f'myscript.request.{unique_name()}')
    logger.debug('making request with args %r', args)
    response = await request(args)
    logger.debug('response: %r', response)
Run Code Online (Sandbox Code Playgroud)

这种方法有什么缺点吗?我唯一能想到的是创建一个新的记录器可能很昂贵,但事实真的如此吗?有什么我没有看到的陷阱吗?

twi*_*dor 0

为了解决这个老问题,在遵循Vinay Sajip 对 的评论LoggerAdapter之后,我实际上在文档中找到了我想要的内容。引用文档

如果您需要不同的方法,例如,如果您想将上下文信息添加到消息字符串中,则只需子类化 LoggerAdapter并重写process()即可执行您需要的操作。这是一个简单的例子:

class CustomAdapter(logging.LoggerAdapter):
    """
    This example adapter expects the passed in dict-like object to have a
    'connid' key, whose value in brackets is prepended to the log message.
    """
    def process(self, msg, kwargs):
        return '[%s] %s' % (self.extra['connid'], msg), kwargs
Run Code Online (Sandbox Code Playgroud)

你可以这样使用:

logger = logging.getLogger(__name__)
adapter = CustomAdapter(logger, {'connid': some_conn_id})
Run Code Online (Sandbox Code Playgroud)

然后,您记录到适配器的任何事件都将在日志消息中添加 some_conn_id 的值。