Skip to main content
 首页 » 编程设计

python之为每个线程定义一个记录器

2025年05月04日11mengfanrong

我有一个用于处理 XMLRPC 请求的服务器应用程序。每个连接都创建自己的线程。我想设置日志记录,以便某些线程/连接特定信息进入日志。我可以做类似的事情:

import logging 
 
@add_unique_request_id 
def thread_top(request_id): 
    logging.info('thread %d says: hello'%request_id) 
    logging.error('thread %d says: darn!!'%request_id) 

并按照我的意愿设置全局根记录器,但我不喜欢这个解决方案。我想要以下内容:

import logging 
 
@setup_logger 
def thread_top(): 
    logging.info('hello') 
    logging.error('darn!!') 

但我不知道 setup_logger deco 应该是什么样子。我想出了一个解决方法,为每个请求使用单独的进程,然后在每个进程中设置根记录器将完全按照我的要求进行。有没有什么方法可以在不被迫使用多处理的情况下完成这项工作?

谢谢!

请您参考如下方法:

我正在使用自定义格式化程序和线程本地存储来执行此操作:

from collections import defaultdict 
import logging 
import threading 
 
class ContextAwareFormatter(logging.Formatter): 
    """ 
    Makes use of get_context() to populate the record attributes. 
    """ 
 
    def format(self, record): 
        # Using defaultdict to avoid KeyErrorS when a key is not in the context. 
        def factory(): 
            return "" 
        record.__dict__ = defaultdict(factory, record.__dict__) 
 
        for k, v in get_context().iteritems(): 
            if not hasattr(record, k): 
                setattr(record, k, v) 
        return logging.Formatter.format(self, record) 
 
THREADLOCAL_ATTR = "logging_context" 
_threadlocal = threading.local() 
 
def get_context(): 
    result = getattr(_threadlocal, THREADLOCAL_ATTR, None) 
    if result is None: 
        result = {} 
        setattr(_threadlocal, THREADLOCAL_ATTR, result) 
    return result 
 
def set_context(**context): 
    c = get_context() 
    c.clear() 
    c.update(**context) 
    return c 
 
def update_context(**context): 
    c = get_context() 
    c.update(**context) 
    return c 

然后在记录器配置中:

"formatters": { 
    "default": { 
        "()": "log.ContextAwareFormatter", 
        "format": "%(asctime)s %(levelname)s [%(request_id)s] %(message)s (%(module)s:%(lineno)d)", 
    }, 
} 

在记录上下文之前填充:

update_context(request_id=request_id) 

您可能希望对应用程序的不同部分使用不同的格式化程序,您可能不需要在日志记录中使用 request_id。