ionelmc / python-hunter

Hunter is a flexible code tracing toolkit.
https://python-hunter.readthedocs.io/
BSD 2-Clause "Simplified" License
794 stars 46 forks source link

How to save result in file #73

Closed mirecl closed 4 years ago

mirecl commented 4 years ago

Hi, guys! How to save result trace in file?

ionelmc commented 4 years ago

All the actions support a steam argument, eg: CallPrinter(stream=open("/tmp/foobar", "w"))

See: https://python-hunter.readthedocs.io/en/latest/reference.html#actions

mirecl commented 4 years ago

thanks!

mirecl commented 4 years ago

@ionelmc my code: hunter.trace(hunter.Q(module='foo', action=hunter.VarsPrinter('z','res',"koef")) )

and result in stderr: [...]foo.py:1 call => myfunc(x=10, y=5, l=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

[...]foo.py:2 line res = x + y + 100 [...]foo.py:4 line [res => 115] [...]foo.py:4 line if res > 140: [...]foo.py:7 line [res => 115] [...]foo.py:7 line result = False [...]foo.py:9 line [res => 115] [...]foo.py:9 line if result: [...]foo.py:12 line [res => 115] [...]foo.py:12 line koef = 3.4 [...]foo.py:13 line [res => 115] ... [koef => 3.4] [...]foo.py:13 line l.append(y) [...]foo.py:15 line [res => 115] ... [koef => 3.4] [...]foo.py:15 line cnt = get_count(l) [...]foo.py:23 call => get_count(i=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 5]) [...]foo.py:24 line count = lens(i) [...]foo.py:28 call => lens(i=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 5]) [...]foo.py:29 line return len(i) [...]foo.py:29 return <= lens: 11 [...]foo.py:25 line return count + 2 [...]foo.py:25 return <= get_count: 13 [...]foo.py:21 line [res => 115] ... [koef => 3.4] [...]foo.py:21 line return koef * cnt [...]foo.py:21 return [res => 115] ... [koef => 3.4] [...]foo.py:21 return <= myfunc: 44.199999999999996

But i save result in file: hunter.trace(hunter.Q(module='foo', action=hunter.VarsPrinter('z','res',"koef",stream=open("foo.log", "w"))) ) Save only var: [...]557938/project/backend/trace/foo.py:4 line [res => 115] [...]557938/project/backend/trace/foo.py:7 line [res => 115] [...]557938/project/backend/trace/foo.py:9 line [res => 115] [...]557938/project/backend/trace/foo.py:12 line [res => 115] [...]557938/project/backend/trace/foo.py:13 line [res => 115] ... [koef => 3.4] [...]557938/project/backend/trace/foo.py:15 line [res => 115] ... [koef => 3.4] [...]557938/project/backend/trace/foo.py:21 line [res => 115] ... [koef => 3.4] [...]557938/project/backend/trace/foo.py:21 return [res => 115] ... [koef => 3.4] and other trace write in stderr.

How to save full trace in file?

ionelmc commented 4 years ago

Ah. Looks like you have found hunter's problem of being too flexible in the query DSL. Just to explain what actually happens in there:

trace(Q(module='foo', action=VarsPrinter(stuff))) is equivalent to trace(When(When(Query(module='foo'), VarsPrinter(stuff)), CallPrinter()) (because CallPrinter is the default root action.

You could have used trace(module='foo', actions=[CallPrinter, VarsPrinter(stuff)]) just as well.

Anyway ... because configuring multiple actions is so tendentious I have added support for global configuration. Eg: you can have this in your shell environment: PYTHONHUNTERCONFIG='stream=open("foo.log", "w")' and avoid all the repetition. Details: https://github.com/ionelmc/python-hunter#environment-variable-configuration (I'll add some section in the docs too, looks like I forgot).

For example I have this in my .zshrc: PYTHONHUNTERCONFIG=force_colors=True (because I use redirections/containers without tty a lot).

mirecl commented 4 years ago

I'm used code activation trace: hunter.trace(module='foo', actions=[hunter.CallPrinter, hunter.VarsPrinter("res")]) and set env export PYTHONHUNTERCONFIG='stream=open("foo.log", "w")', but in foo.log i see:

[...]557938/project/backend/trace/foo.py:1     call      => myfunc(x=10, y=5, l=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
[...]557938/project/backend/trace/foo.py:2     line         res = x + y + 100
[...]557938/project/backend/trace/foo.py:4     line         if res > 140:
[...]557938/project/backend/trace/foo.py:7     line         result = False
[...]557938/project/backend/trace/foo.py:9     line         if result:
[...]557938/project/backend/trace/foo.py:12    line         koef = 3.4
[...]557938/project/backend/trace/foo.py:13    line         l.append(y)
[...]557938/project/backend/trace/foo.py:15    line         cnt = get_count(l)
[...]557938/project/backend/trace/foo.py:23    call         => get_count(i=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 5])
[...]557938/project/backend/trace/foo.py:24    line            count = lens(i)
[...]557938/project/backend/trace/foo.py:28    call            => lens(i=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 5])
[...]557938/project/backend/trace/foo.py:29    line               return len(i)
[...]557938/project/backend/trace/foo.py:29    return          <= lens: 11
[...]557938/project/backend/trace/foo.py:25    line            return count + 2
[...]557938/project/backend/trace/foo.py:25    return       <= get_count: 13
[...]557938/project/backend/trace/foo.py:21    line         return koef * cnt
[...]557938/project/backend/trace/foo.py:21    return    <= myfunc: 44.199999999999996

and in std:

[...]557938/project/backend/trace/foo.py:4     line      [res => 115]
[...]557938/project/backend/trace/foo.py:7     line      [res => 115]
[...]557938/project/backend/trace/foo.py:9     line      [res => 115]
[...]557938/project/backend/trace/foo.py:12    line      [res => 115]
[...]557938/project/backend/trace/foo.py:13    line      [res => 115]
[...]557938/project/backend/trace/foo.py:15    line      [res => 115]
[...]557938/project/backend/trace/foo.py:21    line      [res => 115]
[...]557938/project/backend/trace/foo.py:21    return    [res => 115]

Today i can't get full trace in foo.log?

ionelmc commented 4 years ago

Oooof. It's a bug, lemme check.

ionelmc commented 4 years ago

Looks like the configuration is loaded too late. Just manually specify stream for each action for now. Next release will have a fix.

mirecl commented 4 years ago

if i add specify stream for each action: hunter.trace(module='foo', actions=[hunter.CallPrinter(stream=open("foo.log", "w")), hunter.VarsPrinter("res",stream=open("foo.log", "w"))])

In file log: [...]557938/project/backend/trace/foo.py:1 call => myfunc(x=10, y=5, l=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) [...]557938/project/backend/trace/foo.py:2 line res = x + y + 100 [...]557938/project/backend/trace/foo.py:4 line if res > 140: [...]557938/project/backend/trace/foo.py:7 line result = False [...]557938/project/backend/trace/foo.py:9 line if result: [...]557938/project/backend/trace/foo.py:12 line koef = 3.4 [...]557938/project/backend/trace/foo.py:13 line l.append(y) [...]557938/project/backend/trace/foo.py:15 line cnt = get_count(l) [...]557938/project/backend/trace/foo.py:23 call => get_count(i=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 5]) [...]557938/project/backend/trace/foo.py:24 line count = lens(i) [...]557938/project/backend/trace/foo.py:28 call => lens(i=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 5]) [...]557938/project/backend/trace/foo.py:29 line return len(i) [...]557938/project/backend/trace/foo.py:29 return <= lens: 11 [...]557938/project/backend/trace/foo.py:25 line return count + 2 [...]557938/project/backend/trace/foo.py:25 return <= get_count: 13 [...]557938/project/backend/trace/foo.py:21 line return koef * cnt [...]557938/project/backend/trace/foo.py:21 return <= myfunc: 44.199999999999996

but var not write in log

ionelmc commented 4 years ago

That's because you override your file by opening it two times. Use a single file handle, eg:

log = open("foo.log", "w")
hunter.trace(module='foo', actions=[hunter.CallPrinter(stream=log), hunter.VarsPrinter("res",stream=log)])
mirecl commented 4 years ago

Thank's