Python Logging (function name, file name, line number) using a single file

后端 未结 3 1939
日久生厌
日久生厌 2020-12-04 05:04

I am trying to learn how an application works. And for this I am inserting debug commands as the first line of each function\'s body with the goal of logging the function\'s

相关标签:
3条回答
  • 2020-12-04 05:39

    funcname, linename and lineno provide information about the last function that did the logging.

    If you have wrapper of logger (e.g singleton logger), then @synthesizerpatel's answer might not work for you.

    To find out the other callers in the call stack you can do:

    import logging
    import inspect
    
    class Singleton(type):
        _instances = {}
    
        def __call__(cls, *args, **kwargs):
            if cls not in cls._instances:
                cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
            return cls._instances[cls]
    
    class MyLogger(metaclass=Singleton):
        logger = None
    
        def __init__(self):
            logging.basicConfig(
                level=logging.INFO,
                format="%(asctime)s - %(threadName)s - %(message)s",
                handlers=[
                    logging.StreamHandler()
                ])
    
            self.logger = logging.getLogger(__name__ + '.logger')
    
        @staticmethod
        def __get_call_info():
            stack = inspect.stack()
    
            # stack[1] gives previous function ('info' in our case)
            # stack[2] gives before previous function and so on
    
            fn = stack[2][1]
            ln = stack[2][2]
            func = stack[2][3]
    
            return fn, func, ln
    
        def info(self, message, *args):
            message = "{} - {} at line {}: {}".format(*self.__get_call_info(), message)
            self.logger.info(message, *args)
    
    0 讨论(0)
  • 2020-12-04 05:41

    The correct answer for this is to use the already provided funcName variable

    import logging
    logger = logging.getLogger('root')
    FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s"
    logging.basicConfig(format=FORMAT)
    logger.setLevel(logging.DEBUG)
    

    Then anywhere you want, just add:

    logger.debug('your message') 
    

    Example output from a script I'm working on right now:

    [invRegex.py:150 -          handleRange() ] ['[A-Z]']
    [invRegex.py:155 -     handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03050>, '{', '1', '}']]
    [invRegex.py:197 -          handleMacro() ] ['\\d']
    [invRegex.py:155 -     handleRepetition() ] [[<__main__.CharacterRangeEmitter object at 0x10ba03950>, '{', '1', '}']]
    [invRegex.py:210 -       handleSequence() ] [[<__main__.GroupEmitter object at 0x10b9fedd0>, <__main__.GroupEmitter object at 0x10ba03ad0>]]
    
    0 讨论(0)
  • 2020-12-04 05:58

    You have a few marginally related questions here.

    I'll start with the easiest: (3). Using logging you can aggregate all calls to a single log file or other output target: they will be in the order they occurred in the process.

    Next up: (2). locals() provides a dict of the current scope. Thus, in a method that has no other arguments, you have self in scope, which contains a reference to the current instance. The trick being used that is stumping you is the string formatting using a dict as the RHS of the % operator. "%(foo)s" % bar will be replaced by whatever the value of bar["foo"] is.

    Finally, you can use some introspection tricks, similar to those used by pdb that can log more info:

    def autolog(message):
        "Automatically log the current function details."
        import inspect, logging
        # Get the previous frame in the stack, otherwise it would
        # be this function!!!
        func = inspect.currentframe().f_back.f_code
        # Dump the message + the name of this function to the log.
        logging.debug("%s: %s in %s:%i" % (
            message, 
            func.co_name, 
            func.co_filename, 
            func.co_firstlineno
        ))
    

    This will log the message passed in, plus the (original) function name, the filename in which the definition appears, and the line in that file. Have a look at inspect - Inspect live objects for more details.

    As I mentioned in my comment earlier, you can also drop into a pdb interactive debugging prompt at any time by inserting the line import pdb; pdb.set_trace() in, and re-running your program. This enables you to step through the code, inspecting data as you choose.

    0 讨论(0)
提交回复
热议问题