-2

I have a program that's running a separate thread, which contains three execfile() statements running external Python scripts. Without changing these scripts, is there a way to have the print() statements within them print their commands out to a log file? From my code below, I need the print commands from within File1, File2, and File3 to go into a log file, without being able to change those files. Is this possible?

Code:

MyThread.py

import threading

class MyThread(threading.Thread):
    def run(self):
        execfile('File1.py')
        execfile('File2.py')
        execfile('File3.py')

Program.py

from MyThread import *

MyThread().start()

I've seen the Q/A posted here (redirect prints to log file) and tried this solution, but the print() statements from the external files aren't added to the log file:

import threading, sys

class MyThread(threading.Thread):
    def run(self):
        old_stdout = sys.stdout
        output_file = open('output.log', 'w')
        sys.stdout = output_file

        execfile('File1.py')
        execfile('File2.py')
        execfile('File3.py')

        sys.stdout = old_stdout
        output_file.close()
  • 3
    Possible duplicate of [redirect prints to log file](https://stackoverflow.com/questions/2513479/redirect-prints-to-log-file) – Cory Madden Jul 26 '17 at 22:47
  • `~$ ./Program.py > output.log`? – wbadart Jul 26 '17 at 22:48
  • @wilusdaman but how to do it within the Program.py file, not in Command Line? – CodersinSpace Jul 26 '17 at 23:16
  • @CodersinSpace provide the code that you tried following the example I linked. I've tested it and it works fine. I even just tested it on a `Thread`. *Why* do you want to do this? Why don't you just write a function that prints to stdout and logs it to a file? – Cory Madden Jul 26 '17 at 23:26
  • Or just write to the log file and skip using the `print` function. – Cory Madden Jul 26 '17 at 23:32
  • @CoryMadden the three external files (File1, File2, File3) are not my code, but code that must be executed as a part of my program. One possible option would be to change all the print statements within those files (by the writer), but this is not a great option. – CodersinSpace Jul 26 '17 at 23:35
  • Ok, that was not very clear from your question. Yes, the stdout method won't work that way, it needs to be within the scope of the thread. Since you're using execfile you could always inject the code at the beginning of the file before starting the threads. That *may* work. I'm going to test it out now. – Cory Madden Jul 26 '17 at 23:38

2 Answers2

0

OK, so this was...fun. What I did is I took the print->file method frm here and prepended it to the file I want to run.

my_thread.py

import threading

def prepend_stdout(filename):
        with open(filename, 'r+') as f:
            std_out = 'import sys\nold_stdout = sys.stdout\nlog_file = open("message.log","w")\nsys.stdout = log_file\n'
            content = f.read()
            return std_out + content


class MyThread(threading.Thread):
    def run(self):
        content = prepend_stdout("test.py")
        exec(content)


MyThread().start()

test.py

print("whatever, man")

I then ran python my_thread.py and the output in "message.log" was

whatever, man
Cory Madden
  • 5,026
  • 24
  • 37
  • This almost worked for me, but didn't print anything after the `exec()` call to the file as well (nor before). I actually figured out a simpler solution that's working well so far. – CodersinSpace Jul 28 '17 at 21:05
  • @CodersinSpace glad you got it working. I wonder why my version didn't work for you. I admit it was a bit strange, but it did work for me. – Cory Madden Jul 28 '17 at 21:19
0

I tried the solution posted my Cory Madden, which worked until the exec() call (nothing printed after this, from print() calls within the thread itself). Then I went back to the suggested answer originally given (redirect prints to log file) and did a few things differently, solving the problem. By adding the line output_file.flush() after each execfile() statement, the print() commands from within the execfile() scripts now print out to the external log file. Thus:

...
def run(self):
    old_stdout = sys.stdout
    output_file = open('path/to/file.log', 'w')
    sys.stdout = output_file

    execfile('File1.py')
    output_file.flush()
    execfile('File2.py')
    output_file.flush()
    execfile('File3.py')
    output_file.flush()

    output_file.close()
    sys.stdout = old_stdout

now works for my instance.