diff --git a/EDMCLogging.py b/EDMCLogging.py
index 0b81f1d2..00cf504d 100644
--- a/EDMCLogging.py
+++ b/EDMCLogging.py
@@ -5,11 +5,14 @@ members on the logging.LogRecord instance for use in logging.Formatter()
 strings.
 """
 
-import sys
+from sys import _getframe as getframe
+import inspect
 import logging
-from typing import Tuple
+from typing import TYPE_CHECKING, Tuple
 
 
+# if TYPE_CHECKING:
+
 # TODO: Tests:
 #
 #       1. Call from bare function in file.
@@ -115,7 +118,8 @@ class EDMCContextFilter(logging.Filter):
 
         return True
 
-    def caller_class_and_qualname(self) -> Tuple[str, str]:
+    @classmethod
+    def caller_class_and_qualname(cls) -> Tuple[str, str]:
         """
         Figure out our caller's class name(s) and qualname
 
@@ -126,7 +130,7 @@ class EDMCContextFilter(logging.Filter):
         # Go up through stack frames until we find the first with a
         # type(f_locals.self) of logging.Logger.  This should be the start
         # of the frames internal to logging.
-        frame = sys._getframe(0)
+        frame: 'frameobject' = getframe(0)
         while frame:
             if isinstance(frame.f_locals.get('self'), logging.Logger):
                 frame = frame.f_back  # Want to start on the next frame below
@@ -143,20 +147,21 @@ class EDMCContextFilter(logging.Filter):
 
         caller_qualname = caller_class_names = ''
         if frame:
-            if frame.f_locals and 'self' in frame.f_locals:
+            # <https://stackoverflow.com/questions/2203424/python-how-to-retrieve-class-information-from-a-frame-object#2220759>
+            frame_info = inspect.getframeinfo(frame)
+            args, _, _, value_dict = inspect.getargvalues(frame)
+            if len(args) and args[0] == 'self':
+                frame_class = value_dict['self']
                 # Find __qualname__ of the caller
-                # Paranoia checks
-                if frame.f_code and frame.f_code.co_name:
-                    fn = getattr(frame.f_locals['self'], frame.f_code.co_name)
+                fn = getattr(frame_class, frame_info.function)
 
-                    if fn and fn.__qualname__:
-                        caller_qualname = fn.__qualname__
+                if fn and fn.__qualname__:
+                    caller_qualname = fn.__qualname__
 
                 # Find containing class name(s) of caller, if any
-                frame_class = frame.f_locals['self'].__class__
-                # Paranoia checks
                 if frame_class and frame_class.__qualname__:
                     caller_class_names = frame_class.__qualname__
+
             # If the frame caller is a bare function then there's no 'self'
             elif frame.f_code.co_name and frame.f_code.co_name in frame.f_globals:
                 fn = frame.f_globals[frame.f_code.co_name]
@@ -174,6 +179,9 @@ class EDMCContextFilter(logging.Filter):
                         # In case the condition above tests a tuple of values
                         caller_class_names = f'<{caller_class_names}>'
 
+            # https://docs.python.org/3.7/library/inspect.html#the-interpreter-stack
+            del frame
+
         if caller_qualname == '':
             print('ALERT!  Something went wrong with finding caller qualname for logging!')
             caller_qualname = '<ERROR in EDMCLogging.caller_class_and_qualname() for "qualname">'
@@ -182,4 +190,4 @@ class EDMCContextFilter(logging.Filter):
             print('ALERT!  Something went wrong with finding caller class name(s) for logging!')
             caller_class_names = '<ERROR in EDMCLogging.caller_class_and_qualname() for "class">'
 
-        return (caller_class_names, caller_qualname)
+        return caller_class_names, caller_qualname