docs: def logged_api_call(func):
      """
      Function decorator that causes the decorated API function or method to log
      calls to itself to a logger.
  
      The logger's name is the dotted module name of the module defining the
      decorated function (e.g. 'zhmcclient._cpc').
  
      Parameters:
  
        func (function object): The original function being decorated.
  
      Returns:
  
        function object: The function wrappering the original function being
          decorated.
  
      Raises:
  
        TypeError: The @logged_api_call decorator must be used on a function or
          method (and not on top of the @property decorator).
      """
  
      # Note that in this decorator function, we are in a module loading context,
      # where the decorated functions are being defined. When this decorator
      # function is called, its call stack represents the definition of the
      # decorated functions. Not all global definitions in the module have been
      # defined yet, and methods of classes that are decorated with this
      # decorator are still functions at this point (and not yet methods).
  
      module = inspect.getmodule(func)
      if not inspect.isfunction(func) or not hasattr(module, '__name__'):
          raise TypeError("The @logged_api_call decorator must be used on a "
                          "function or method (and not on top of the @property "
                          "decorator)")
  
      try:
          # We avoid the use of inspect.getouterframes() because it is slow,
          # and use the pointers up the stack frame, instead.
  
          this_frame = inspect.currentframe()  # this decorator function here
          apifunc_frame = this_frame.f_back  # the decorated API function
  
          apifunc_owner = inspect.getframeinfo(apifunc_frame)[2]
  
      finally:
          # Recommended way to deal with frame objects to avoid ref cycles
          del this_frame
          del apifunc_frame
  
      # TODO: For inner functions, show all outer levels instead of just one.
  
      if apifunc_owner == '<module>':
          # The decorated API function is defined globally (at module level)
          apifunc_str = '{func}()'.format(func=func.__name__)
      else:
          # The decorated API function is defined in a class or in a function
          apifunc_str = '{owner}.{func}()'.format(owner=apifunc_owner,
                                                  func=func.__name__)
  
      logger = get_logger(API_LOGGER_NAME)
  
      def is_external_call():
          """
          Return a boolean indicating whether the call to the decorated API
          function is an external call (vs. b eing an internal call).
          """
          try:
              # We avoid the use of inspect.getouterframes() because it is slow,
              # and use the pointers up the stack frame, instead.
  
              log_it_frame = inspect.currentframe()  # this log_it() function
              log_api_call_frame = log_it_frame.f_back  # the log_api_call() func
              apifunc_frame = log_api_call_frame.f_back  # the decorated API func
              apicaller_frame = apifunc_frame.f_back  # caller of API function
              apicaller_module = inspect.getmodule(apicaller_frame)
              if apicaller_module is None:
                  apicaller_module_name = "<unknown>"
              else:
                  apicaller_module_name = apicaller_module.__name__
          finally:
              # Recommended way to deal with frame objects to avoid ref cycles
              del log_it_frame
              del log_api_call_frame
              del apifunc_frame
              del apicaller_frame
              del apicaller_module
  
          # Log only if the caller is not from the zhmcclient package
          return apicaller_module_name.split('.')[0] != 'zhmcclient'
  
      def log_api_call(func, *args, **kwargs):
          """
          Log entry to and exit from the decorated function, at the debug level.
  
          Note that this wrapper function is called every time the decorated
          function/method is called, but that the log message only needs to be
          constructed when logging for this logger and for this log level is
          turned on. Therefore, we do as much as possible in the decorator
          function, plus we use %-formatting and lazy interpolation provided by
          the log functions, in order to save resources in this function here.
  
          Parameters:
  
            func (function object): The decorated function.
  
            *args: Any positional arguments for the decorated function.
  
            **kwargs: Any keyword arguments for the decorated function.
          """
  
          # Note that in this function, we are in the context where the
          # decorated function is actually called.
  
          _log_it = is_external_call() and logger.isEnabledFor(logging.DEBUG)
  
          if _log_it:
              logger.debug("Called: {}, args: {:.500}, kwargs: {:.500}".
                           format(apifunc_str, log_escaped(repr(args)),
                                  log_escaped(repr(kwargs))))
  
          result = func(*args, **kwargs)
  
          if _log_it:
              logger.debug("Return: {}, result: {:.1000}".
                           format(apifunc_str, log_escaped(repr(result))))
  
          return result
  
      if 'decorate' in globals():
          return decorate(func, log_api_call)
      else:
          return decorator(log_api_call, func)