Home > Enterprise >  Convenient way to log each line of a function without cluttering the code in Python
Convenient way to log each line of a function without cluttering the code in Python

Time:01-10

Let´s say I have an annoying function which has a lot of if-elses in it and this function has a bug which occurs randomly.

I can not reproduce or debug it and I want to add some logging to see which parts of the function have been executed when the error occurs again.

Now it would be possible to add a log before each line like this:

def my_annoying_function(self):
    logger.info("self._call_other_function()")
    self._call_other_function()
    logger.info("self.myvar = 5")
    self.myvar = 5
    logger.info("i = 4")
    i = 4
    logger.info("i = i   5")
    i = i   5
    if self.myothervar is True:
        logger.info("self.call_other_function2()")
        self.call_other_function2()
    ...

Does somebody know a way to acheive the same behaviour for the logging and log each statement before or after execution without cluttering the code?

CodePudding user response:

I think python -m trace --trace demo.py is worth to try.

# demo.py
def is_prime(n):
    if n == 1:
        return False
    for i in range(2, n):
        if n % i == 0:
            return False
    return True

def print_all_prime(_min, _max):
    for i in range(_min, _max 1):
        if is_prime(i):
            print(i)

if __name__ == '__main__':
    print_all_prime(1, 10)

the output of python -m trace --trace demo.py is

 --- modulename: demo, funcname: <module>
demo.py(1): def is_prime(n):
demo.py(9): def print_all_prime(_min, _max):
demo.py(14): if __name__ == '__main__':
demo.py(15):     print_all_prime(1, 10)
 --- modulename: demo, funcname: print_all_prime
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(3):         return False
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(7):     return True
demo.py(12):             print(i)
2
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(7):     return True
demo.py(12):             print(i)
3
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(6):             return False
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(7):     return True
demo.py(12):             print(i)
5
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(6):             return False
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(7):     return True
demo.py(12):             print(i)
7
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(6):             return False
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(6):             return False
demo.py(10):     for i in range(_min, _max 1):
demo.py(11):         if is_prime(i):
 --- modulename: demo, funcname: is_prime
demo.py(2):     if n == 1:
demo.py(4):     for i in range(2, n):
demo.py(5):         if n % i == 0:
demo.py(6):             return False
demo.py(10):     for i in range(_min, _max 1):

CodePudding user response:

To add detail to the other answer, you can turn on tracing programmatically as in this example:

import sys
import trace

def func3():
    pass

def func1():
    func3()

def func4():
    pass


def func2():
    func4()

def func(two):
    if two:
        func2()
    else:
        func1()

def func_call():
    func(False)
    func(True)

def main():
    print('Hello, world! This is Python %s' % sys.version)
    t = trace.Trace()
    t.run(func_call.__code__)

if __name__ == '__main__':
    main()

When run, this prints:

$ python main.py 
Hello, world! This is Python 3.11.0 (main, Oct 24 2022, 17:48:40) [GCC 11.3.0]
 --- modulename: main, funcname: func_call
main.py(29):     func(False)
 --- modulename: main, funcname: func
main.py(22):     if two:
main.py(25):         func1()
 --- modulename: main, funcname: func1
main.py(10):     func3()
 --- modulename: main, funcname: func3
main.py(6):     pass
main.py(30):     func(True)
 --- modulename: main, funcname: func
main.py(22):     if two:
main.py(23):         func2()
 --- modulename: main, funcname: func2
main.py(18):     func4()
 --- modulename: main, funcname: func4
main.py(14):     pass

So it traces inside the function you specify in Trace.run and all statements executed inside that call.

  • Related