code: def _wrap_function(
      class_name: str, function_name: str, func: Callable, logger: Any
  ) -> Callable:
      signature = inspect.signature(func)
  
      @functools.wraps(func)
      def wrapper(*args: Any, **kwargs: Any) -> Any:
          if hasattr(_local, "logging") and _local.logging:
              # no need to log since this should be internal call.
              return func(*args, **kwargs)
          _local.logging = True
          try:
              start = time.perf_counter()
              try:
                  res = func(*args, **kwargs)
                  logger.log_success(
                      class_name,
                      function_name,
                      time.perf_counter() - start,
                      signature,
                  )
                  return res
              except Exception as ex:
                  logger.log_failure(
                      class_name,
                      function_name,
                      ex,
                      time.perf_counter() - start,
                      signature,
                  )
                  raise
          finally:
              _local.logging = False
  
      return wrapper
  
file_path: spark/python/pyspark/instrumentation_utils.py
imports: import functools
  import inspect
  import threading
  import importlib
  import time
  from types import ModuleType
  from typing import Tuple, Union, List, Callable, Any, Type
label_desc: Use image node_id 1 for calling a global function with example usage: _wrap_function(class_name, function_name, func, logger) and returns: wrapper, func, res