8.1 Using LoggerAdapters to impart contextual information An easy way in which you can pass contextual information to be output along with logging event information is to use the$_{LoggerAdapter}$ class. This class is designed to look like a$_{Logger}$   so that you can call$_{debug()}$   info()  $_{warning()}$  $_{error()}$  $_{exception()}$  $_{critical()}$ and$_{log()}$ . These methods have the same signatures as their counterparts in Logger   so you can use the two types of instances interchangeably. When you create an instance of LoggerAdapter   you pass it a Logger instance and a dict-like object which con- tains your contextual information. When you call one of the logging methods on an instance of LoggerAdapter   it delegates the call to the underlying instance of Logger passed to its constructor  and arranges to pass the contextual information in the delegated call. Here’s a snippet from the code of$_{LoggerAdapter}$: The process() method of LoggerAdapter is where the contextual information is added to the logging output. It’s passed the message and keyword arguments of the logging call  and it passes back (potentially) modified versions of these to use in the call to the underlying logger. The default implementation of this method leaves the message alone  but inserts an ‘extra’ key in the keyword argument whose value is the dict-like object passed to the constructor. Of course  if you had passed an ‘extra’ keyword argument in the call to the adapter  it will be silently overwritten. The advantage of using ‘extra’ is that the values in the dict-like object are merged into the$_{LogRecord}$ instance’s __dict__  allowing you to use customized strings with your$_{Formatter}$ instances which know about the keys of the dict-like object. If you need a different method  e.g. if you want to prepend or append the contextual information to the message string  you just need to subclass$_{LoggerAdapter}$ and override$_{process()}$ to do what you need. Here is a simple example: which you can use like this: logger=logging.getLogger(__name__ ) adapter =CustomAdapter(logger  { 'connid': some_conn_id}) Then any events that you log to the adapter will have the value of$_{some_conn_id}$ prepended to the log messages. You don’t need to pass an actual dict to a$_{LoggerAdapter}$ - you could pass an instance of a class which implements __getitem__ and$_{__iter__}$ so that it looks like a dict to logging. This would be useful if you want to generate values dynamically (whereas the values in a dict would be constant). 11 Using objects other than dicts to pass contextual information classCustomAdapter (logging .LoggerAdapter): """ This example adapter expects the passed in dict-like object to have a 'connid' key  whose value in brackets is prepended to the log message. """ def process(self  msg  kwargs): return '[ %s ] %s '%(self.extra['connid']  msg)  kwargs def debug(self  msg / *args **kwargs): """ Delegate a debug call to the underlying logger  after adding contextual information from this adapter instance. """ msg  kwargs=self.process(msg  kwargs) self.logger.debug(msg  *args **kwargs)