2

I have a very large Python 3.x program running in Windows. It works great 99.9% of the time, but occasionally it crashes. I'm not sure what is causing the crash, it could be numerous things. Due to the fact that I have to run the program "compiled" .exe with an invisible console for security reasons (don't ask), I don't get to see any form of console readout when it dies. So obviously it would be great if I could have it output the crash traceback as a text file instead.

I'm familiar with try/except in Python but the piece of code that's causing the issue could be anywhere and I don't want to have to write an individual try/except around every single line of the literally thousands of lines of code. Is there a way that I can get the program to always output any program-stopping error as a text file, no matter what line of code is causing the problem, or what the error might be?

츄 plus
  • 488
  • 1
  • 7
  • 20
  • 2
    Does this answer your question? [How to write to a file, using the logging Python module?](https://stackoverflow.com/questions/6386698/how-to-write-to-a-file-using-the-logging-python-module) – PeptideWitch Jan 29 '20 at 23:19
  • No quite, no - but it's a start. How would I integrate that into a program to specifically log errors. Also, that thread is rather old, would it work in Python 3.x? – 츄 plus Jan 29 '20 at 23:24
  • "*would it work in Python 3.x*": The [logging](https://docs.python.org/3/howto/logging.html) module is still available and working as of Python 3.8. – Gino Mempin Jan 30 '20 at 00:11

4 Answers4

7

Somewhere in your code you must have a single entry-point into the code that might be crashing (in the main script, at a minimum). You can wrap that in a try/except pair and then use functions from the traceback module to print the exception to a file when it happens:

Change:

if __name__ == "__main__":
    do_stuff()

To:

import traceback

if __name__ == "__main__":
    try:
        do_stuff()
    except:
        with open("exceptions.log", "a") as logfile:
            traceback.print_exc(file=logfile)
        raise

If you want to, you could add some extra code to write extra output to the file, with a time/date stamp or whatever other information you think might be useful. You may want to add additional try/except blocks, more or less like the one above, if you want to give special scrutiny to certain parts of your code. For instance, you could put a block in a loop, where you can print out the loop value if an exception occurs:

for x in some_iterable:
    try:
        do_something_with(x)
    except:
        with open("exceptions.log", "a") as logfile:
            print("Got an exception while handling {!r} in the loop:".format(x)
            traceback.print_exc(file=logfile)
        raise   # you could omit this line to suppress the exception and keep going in the loop

You could also use the logging module, if you want a more configurable system for the file writing end of the issue. The logging.debug and logging.exception functions both read the same exception information used by the traceback module, but with many more options for formatting things yourself (if you want that). Note that setting up logging is a bit more involved than just opening a file manually.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • The main body of the code is one huge "while True:" loop. However there are already several try/excepts within various parts of that loop, just as part of the program's normal operation (these exceptions don't stop the program but instead produce different outputs). However something else is failing within the program and I don't know where, other than it's somewhere within this massive while loop. I don't want the normal try/excepts to be logged, I only want to see the traceback as a logfile if the program stops running because it hits an error that isn't already handled by a try/except. – 츄 plus Jan 30 '20 at 00:04
  • I did try wrapping this try/except scenario around the entire loop and it didn't produce a logfile. – 츄 plus Jan 30 '20 at 00:33
  • Oh wait... yes it did! The file just wasn't where I expected because there's a os.chdir() in the program somewhere. Thank you! <3 – 츄 plus Jan 30 '20 at 00:44
1

sometimes you cant use try/except or > in terminal.

you can use sys excepthook. add this to beginning:

import sys
import traceback


def excepthook(exctype, value, tb):
    with open("mylog.txt", "w") as mylog:
        traceback.print_exception(exctype, value, tb, file=mylog)


sys.excepthook = excepthook
##########
# your code

after that, all traceback will be print to mylog.txt.

matan h
  • 900
  • 1
  • 10
  • 19
0

I ended up writing my own logging function

# Takes two inputs - logfile (path to desired .csv), and data to be written
# Writes "Y-M-D|H:M:S, data\n"
    f = open(logfile, 'a+')
    currentdate = time.strftime('%Y-%m-%d|%H:%M:%S')
    f.write(currentdate + ',' + data +'\n')
    f.close()

it requires time or datetime, I'm not sure which. Also you need to make sure that the log file exists.

Then I would just plop it wherever I needed, eg: logger(ERRLOG, "OCR didn't find poop. Check {}".format(ocr_outfilepath))

stygarfield
  • 107
  • 9
0

I'm not sure what kind of program this is or how you are running it, but you could try running your Python program and redirecting all its output (or all errors) to a file.

For example, if I have a very-contrived sample Python script like this

def do_stuff():
    s = [1, 2, 3, 4, 5]
    print(s[6])

if __name__ == "__main__":
    do_stuff()

which is deliberately going to raise an IndexError exception.

You could run it like this:

$ python test.py &> mylogs.txt

$ cat mylogs.txt 
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    do_stuff()
  File "test.py", line 4, in do_stuff
    print(s[6])
IndexError: list index out of range

which redirects all output and errors to a file.

Or, if you can have it displayed on a console and also redirect it to a file:

$ python test.py 2>&1 | tee mylogs.txt
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    do_stuff()
  File "test.py", line 4, in do_stuff
    print(s[6])
IndexError: list index out of range

$ cat mylogs.txt 
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    do_stuff()
  File "test.py", line 4, in do_stuff
    print(s[6])
IndexError: list index out of range

This way, you don't need to modify anything with the code.

Note that this solution is for Linux or Mac systems.
See other StackOverflow posts for redirecting Python output to a file.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
  • Sorry, forgot to mention I'm on Windows. Will edit the question. – 츄 plus Jan 30 '20 at 00:31
  • @KimJiwoo I'm sure Windows [also has output redirection mechanisms](https://stackoverflow.com/search?q=windows+redirect+output+to+file). But I can't test them since I don't have/use a Windows machine at the moment. – Gino Mempin Jan 30 '20 at 00:34