0

I'm running a python script that for some reason gets killed and because of it, the stdout is not printed. I know I can get the buffered stdout with sys.stdout.flush(). However, since I don't know when the script is killed, I can miss the time between the last flush and the actual process ending. For example, is the following code only "test 1" will be saved before the 60s sleep ends. If I kill the program before that my log file will contain only the "test 1" print.

import sys,time

sys.stdout = open('log', 'w')
print("test 1")
sys.stdout.flush()
print("test 2")
time.sleep(60) 

How can I catch the last stdout before the script is killed? How can I get the "test 2" print even if I kill the script before the 60s sleep ends?

Miguel
  • 2,738
  • 3
  • 35
  • 51
  • Take a look here: https://stackoverflow.com/questions/881696/unbuffered-stdout-in-python-as-in-python-u-from-within-the-program – tomer.z Oct 27 '18 at 09:43
  • How is your program killed? By `KeyboardInterrupt`? By `SystemExit`? Or something else? – N Chauhan Oct 27 '18 at 09:51
  • I don't know. I left it running and for some reason, it got killed. And is not the first time. – Miguel Oct 27 '18 at 10:13

2 Answers2

2

calling

sys.stdout.flush()

Will write whatever is in the buffer to the file. All print does is write objects to the output file stream that's provided so when forcibly ended the buffer may not have been flushed. should have a look at this for more info print function.

If you want it to flush the buffer with every print pass the flush param like this:

import sys,time

sys.stdout = open('log', 'w')
print("test 1", flush=True)
print("test 2", flush=True)
time.sleep(60) 
  • Maybe you could incorporate a wrapper that takes the arguments and adds `flush` implicitly. i.e. `flush = lambda *args: print(*args, flush=True)` – N Chauhan Oct 27 '18 at 09:55
  • Thanks but this only works with the prints. If I have anything else in the buffer I will miss it. – Miguel Oct 27 '18 at 10:14
0

You can use the flush=True parameter of print() function. Write a decorator to flush all the prints made inside the decorated function.

import functools

def flush_prints(f):
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        global print
        # Flush calls made to print(...)
        print = functools.partial(print, flush=True)
        f_returns = f(*args, **kwargs)
        # Restore back
        print = functools.partial(print, flush=False)
        return f_returns
    return decorated

So decorating a function like this, will flush all the prints made inside the function:

@flush_prints
def test():
    print("test 1")
    time.sleep(10)
    print("test 2")
    time.sleep(10)

test()
Deepak Saini
  • 2,810
  • 1
  • 19
  • 26