私はこれをカスタムフォーマッターとスレッドローカルストレージで行っています:
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
ログレコードで必要とされない可能性のあるアプリケーションのさまざまな部分に、さまざまなフォーマッタを使用することをお勧めします。