Showing the right funcName when wrapping logger functionality in a custom class

前端 未结 8 1836
你的背包
你的背包 2021-02-01 16:31

This is the formatting string that I am using for logging:

\'%(asctime)s - %(levelname)-10s - %(funcName)s - %(message)s\'

But to show the logg

8条回答
  •  我在风中等你
    2021-02-01 16:56

    Thanks to @cygnusb and the others who already provided useful pointers. I chose to use the Python 3.4 Logger.findCaller method as my starting point. The following solution has been tested with Python 2.7.9 and 3.4.2. This code is meant to be placed in its own module. It produces the correct answer with only one iteration of the loop.

    import io
    import sys
    
    def _DummyFn(*args, **kwargs):
        """Placeholder function.
    
        Raises:
            NotImplementedError
        """
        _, _ = args, kwargs
        raise NotImplementedError()
    
    # _srcfile is used when walking the stack to check when we've got the first
    # caller stack frame, by skipping frames whose filename is that of this
    # module's source. It therefore should contain the filename of this module's
    # source file.
    _srcfile = os.path.normcase(_DummyFn.__code__.co_filename)
    if hasattr(sys, '_getframe'):
        def currentframe():
            return sys._getframe(3)
    else:  # pragma: no cover
        def currentframe():
            """Return the frame object for the caller's stack frame."""
            try:
                raise Exception
            except Exception:
                return sys.exc_info()[2].tb_frame.f_back
    
    class WrappedLogger(logging.Logger):
        """Report context of the caller of the function that issues a logging call.
    
        That is, if
    
            A() -> B() -> logging.info()
    
        Then references to "%(funcName)s", for example, will use A's context
        rather than B's context.
    
        Usage:
            logging.setLoggerClass(WrappedLogger)
            wrapped_logging = logging.getLogger("wrapped_logging")
        """
        def findCaller(self, stack_info=False):
            """Return the context of the caller's parent.
    
            Find the stack frame of the caller so that we can note the source
            file name, line number and function name.
    
            This is based on the standard python 3.4 Logger.findCaller method.
            """
            sinfo = None
            f = currentframe()
            # On some versions of IronPython, currentframe() returns None if
            # IronPython isn't run with -X:Frames.
            if f is not None:
                f = f.f_back
    
            if sys.version_info.major == 2:
                rv = "(unknown file)", 0, "(unknown function)"
            else:
                rv = "(unknown file)", 0, "(unknown function)", sinfo
    
            while hasattr(f, "f_code"):
                co = f.f_code
                filename = os.path.normcase(co.co_filename)
                if filename == _srcfile or filename == logging._srcfile:
                    f = f.f_back
                    continue
                # We want the frame of the caller of the wrapped logging function.
                # So jump back one more frame.
                f = f.f_back
                co = f.f_code
                if sys.version_info.major == 2:
                rv = "(unknown file)", 0, "(unknown function)"
            else:
                rv = "(unknown file)", 0, "(unknown function)", sinfo
    
            while hasattr(f, "f_code"):
                co = f.f_code
                filename = os.path.normcase(co.co_filename)
                if filename == _srcfile or filename == logging._srcfile:
                    f = f.f_back
                    continue
                # We want the frame of the caller of the wrapped logging function.
                # So jump back one more frame.
                f = f.f_back
                co = f.f_code
                if sys.version_info.major == 2:
                    rv = co.co_filename, f.f_lineno, co.co_name
                else:
                    if stack_info:
                        sio = io.StringIO()
                        sio.write('Stack (most recent call last):\n')
                        traceback.print_stack(f, file=sio)
                        sinfo = sio.getvalue()
                        if sinfo[-1] == '\n':
                            sinfo = sinfo[:-1]
                        sio.close()
                    rv = co.co_filename, f.f_lineno, co.co_name, sinfo
                break
    
            return rv
    

提交回复
热议问题