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.