我有一个用于处理 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。
