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

前端 未结 8 1680
你的背包
你的背包 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:39

    Thanks to @glglgl I could come up with ad advanced findCaller

    Please note the initialization of _logging_srcfile and _this_srcfile - inspired from the python logging source code

    Of course you can put your own rules in the findCaller() - here i'm just excluding everything from the file where the custom logger is, EXCEPT the test_logging function.

    IMPORTANT the custom logger is only retrieved when passing a name to the getLogger(name) factory. If you simply do logging.getLogger() you will get the RootLogger which is NOT your logger.

    import sys
    import os
    import logging
    # from inspect import currentframe
    currentframe = lambda: sys._getframe(3)
    _logging_srcfile = os.path.normcase(logging.addLevelName.__code__.co_filename)
    _this_srcfile = __file__
    
    
    def test_logging():
        logger = logging.getLogger('test')
        handler = logging.StreamHandler(sys.stderr)
        handler.setFormatter(logging.Formatter('%(funcName)s: %(message)s'))
        handler.setLevel(11)
        logger.addHandler(handler)
        logger.debug('Will not print')
        logger.your_function('Test Me')
    
    
    class CustomLogger(logging.getLoggerClass()):
        def __init__(self, name, level=logging.NOTSET):
            super(CustomLogger, self).__init__(name, level)
    
        def your_function(self, msg, *args, **kwargs):
            # whatever you want to do here...
            self._log(12, msg, args, **kwargs)
    
        def findCaller(self):
            """
            Find the stack frame of the caller so that we can note the source
            file name, line number and function name.
    
            This function comes straight from the original python one
            """
            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
            rv = "(unknown file)", 0, "(unknown function)"
            while hasattr(f, "f_code"):
                co = f.f_code
                filename = os.path.normcase(co.co_filename)
                ## original condition
                # if filename == _logging_srcfile:
                ## PUT HERE YOUR CUSTOM CONDITION, eg:
                ## skip also this file, except the test_logging method which is used for debug
                if co.co_name != 'test_logging' and filename in [_logging_srcfile, _this_srcfile]:
                    f = f.f_back
                    continue
                rv = (co.co_filename, f.f_lineno, co.co_name)
                break
            return rv
    
    logging.setLoggerClass(CustomLogger)
    

提交回复
热议问题