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

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

    Someone has given the right answer. I will make a summary.

    logging.Logger.findCaller(), it filter stack frames by logging._srcfile in original logging package.

    So we do the same thing, filter our own logger wrapper my_log_module._srcfile. We replace the method logging.Logger.findCaller() of your logger instance dynamically.

    BTW, please don't create a subclass of logging.Logger, logging package has no design for OOP when findCaller, pitty...yes?

    # file: my_log_module.py, Python-2.7, define your logging wrapper here
    import sys
    import os
    import logging
    my_logger = logging.getLogger('my_log')
    
    if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)
    # done filching
    
    #
    # _srcfile is used when walking the stack to check when we've got the first
    # caller stack frame.
    #
    _srcfile = os.path.normcase(currentframe.__code__.co_filename)
    
    def findCallerPatch(self):
        """
        Find the stack frame of the caller so that we can note the source
        file name, line number and function name.
        """
        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)
            if filename == _srcfile:
                f = f.f_back
                continue
            rv = (co.co_filename, f.f_lineno, co.co_name)
            break
        return rv
    
    # DO patch
    my_logger.findCaller = findCallerPatch
    

    Ok, all ready. You can use your logger in other modules now, add your logging message format: lineno, path, method name, blablabla

    # file: app.py
    from my_log_module import my_logger
    my_logger.debug('I can check right caller now')
    

    Or you can use a elegant way, but don't use global logging.setLoggerClass

    # file: my_log_modue.py
    import logging
    my_logger = logging.getLogger('my_log')
    
    class MyLogger(logging.Logger):
        ...
    
    my_logger.__class__ = MyLogger
    

提交回复
热议问题