Skip to main content
 首页 » 编程设计

python之Python 中跨记录器的嵌套前缀

2025年05月04日16unruledboy

我目前正在从事一个使用单根记录器的项目。我从阅读有关日志记录的文章中了解到这是一件坏事,但我正在努力寻找一个好的解决方案来为我们带来好处。

我们做的事情(部分是为了避免没有不同的记录器,但部分是为了给我们一个很好的特性)是有一个 log_prefix 装饰器。

例如

@log_prefix("Download") 
def download_file(): 
    logging.info("Downloading file..") 
    connection = get_connection("127.0.0.1") 
    //Do other stuff 
    return file 
 
@log_prefix("GetConnection") 
def get_connection(url): 
    logging.info("Making connection") 
    //Do other stuff 
    logging.info("Finished making connection") 
    return connection 

这为我们提供了一些格式良好的日志,可能如下所示:

Download:Downloading file.. 
Download:GetConnection:Making Connection 
Download:GetConnection:Other stuff 
Download:GetConnection:Finished making connection 
Download:Other stuff 

这也意味着如果我们有

@log_prefix("StartTelnetSession") 
logging.info("Starting telnet session..") 
connection = get_connection("127.0.0.1") 

我们在最后得到相同的前缀:

StartTelnetSession:Starting telnet session.. 
StartTelnetSession:GetConnection:Making Connection 
StartTelnetSession:GetConnection:Other stuff 
StartTelnetSession:GetConnection:Finished making connection 

事实证明,这对开发和支持非常有用。

我可以看到很多情况,实际上只需为操作使用一个单独的记录器就可以解决我们的问题,但我也可以看到丢弃我们现有的嵌套会使事情变得更糟的情况。

嵌套记录器是否有任何模式或常见用途?即

logging.getLogger("Download").getLogger("MakingConnection") 

还是我在这里遗漏了什么?

请您参考如下方法:

你可以使用 LoggerAdapter添加额外的上下文信息:

utils_logging.py:

import functools 
 
def log_prefix(logger, label, prefix=list()): 
    def decorator(func): 
        @functools.wraps(func) 
        def wrapper(*args, **kwargs): 
            prefix.append(label) 
            logger.extra['prefix'] = ':'.join(prefix) 
            result = func(*args, **kwargs) 
            prefix.pop() 
            logger.extra['prefix'] = ':'.join(prefix) 
            return result 
        return wrapper 
    return decorator 

foo.py:

import logging 
import utils_logging as UL 
import bar 
 
logger = logging.LoggerAdapter(logging.getLogger(__name__), {'prefix':''}) 
@UL.log_prefix(logger, "Download") 
def download_file(): 
    logger.info("Downloading file..") 
    connection = bar.get_connection("127.0.0.1") 
 
if __name__ == '__main__': 
    logging.basicConfig( 
        level=logging.INFO, 
        format='%(prefix)s %(name)s %(levelname)s %(message)s') 
 
    download_file() 
    bar.get_connection('foo') 

bar.py:

import logging 
import utils_logging as UL 
logger = logging.LoggerAdapter(logging.getLogger(__name__), {'prefix':''}) 
 
@UL.log_prefix(logger, "GetConnection") 
def get_connection(url): 
    logger.info("Making connection") 
    logger.info("Finished making connection") 

产量

Download __main__ INFO Downloading file.. 
Download:GetConnection bar INFO Making connection 
Download:GetConnection bar INFO Finished making connection 
GetConnection bar INFO Making connection 
GetConnection bar INFO Finished making connection 

注意:我不认为为每个对象创建一个新的 Logger 实例是个好主意 前缀因为these instances are not garbage collected .全部 你需要的是一些 prefix 变量取不同的值取决于 语境。你不需要一个新的 Logger 实例——一个 LoggerAdapter 会 做。