docs: def context_logger(context_func, func, parent=None):
      """
      The results of context_func will be executed and applied to a ContextLogger
      instance for the execution of func. The resulting ContextLogger instance will be
      available on parent.logger for the duration of func.
  
      :param context_func: callable which provides dictionary-like context information
      :param func: the function to wrap
      :param parent: object to attach the context logger to, if None, defaults to func.__self__
      """
      if parent is None:
          parent = func.__self__
  
      def wrapped(*args, **kwargs):
          parent.logger = ContextLogger(
              getattr(parent, 'logger', getLogger(parent.__class__.__name__)),
              context_func(*args, **kwargs) or dict(),
          )
          try:
              result = func(*args, **kwargs)
              return result
          finally:
              parent.logger = parent.logger.logger
      return wrapped