我有一个用于处理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应该是怎样的。我想出了一个解决方法,为每个请求使用单独的进程,然后在每个进程中设置根记录器将完全符合我的要求。有没有办法让这项工作不被迫使用多处理?
谢谢!
答案 0 :(得分:1)
我正在使用自定义格式化程序和threadlocal存储执行此操作:
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
的应用程序的不同部分使用不同的格式化程序。