Home > front end >  How to collect all the print content and save them in a txt in Python?
How to collect all the print content and save them in a txt in Python?

Time:01-12

I want to collect all of the print content and save them in a txt file. I use this answer's method to generate and collect logs. Also I use a threading because I may have to collect the first 5 seconds' logs for instance.

import sys
import io
import time
import threading
import traceback

class MyThread(threading.Thread):
    def __init__(self, func, args):
        super(MyThread, self).__init__()
        self.func = func
        self.args = args

    def run(self):
        try:
            self.result = self.func(*self.args)
        except Exception as e:
            f = traceback.format_exc()
            print(f'{f}')
            
    def get_result(self):
        try:
            return self.result
        except Exception:
            return None

def make_logs(delay):
    for i in range(100):
        print(i)
        print("\n")
        time.sleep(delay)


def get_logs(t1):
    if t1.is_alive():
        sys.stdout = old_stdout
        whatWasPrinted = buffer.getvalue()
        with open("output.txt", "w") as text_file:
            text_file.write(whatWasPrinted)
        time.sleep(1)
        get_logs(t1)
    

def do_it():
    t1 = MyThread(make_logs, args=(1,))
    t2 = MyThread(get_logs, args=(t1,))
    t1.start(), t2.start()
    t1.join(), t2.join()


old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
do_it()
    

However, as I execute this code, I can only write the first elment(0) to txt file. Anyone knows why? Thanks.

CodePudding user response:

You don't need two threads to capture the first N seconds – you can write a filelike object that stops writing to whatever backing object (here it just derives from io.StringIO but could wrap another IO) when it has had enough.

import contextlib
import io
import threading
import time


def make_logs(n, delay):
    for i in range(n):
        print(i)
        print("\n")
        time.sleep(delay)


class StdoutCapturer(io.StringIO):
    def __init__(self, time_limit):
        super().__init__()
        self.time_limit = time_limit
        # This could be initialized later, at the first write:
        self.start_time = time.time()

    def write(self, s: str) -> int:
        elapsed = time.time() - self.start_time
        if elapsed < self.time_limit:
            return super().write(s)
        return 0


if __name__ == "__main__":
    sio = StdoutCapturer(time_limit=3.1)
    with contextlib.redirect_stdout(sio):
        t = threading.Thread(target=make_logs, args=(5, 1))
        t.start()
        t.join()
    print(repr(sio.getvalue()))

This prints out

'0\n\n\n1\n\n\n2\n\n\n3\n\n\n'

CodePudding user response:

you can use sys:

import sys
sys.stdout = open(PATH_TO_LOG_FILE, "w")
do_it()
sys.stdout.close()

you can also use contextlib.redirect_stdout: (works for python 3.4 )

from contextlib import redirect_stdout

with open('help.txt', 'w') as f:
    with redirect_stdout(f):
        print('it now prints to `help.text`')
  •  Tags:  
  • Related