-1

I'd like to log to a file the traceback of any error in the exact same form as the standard Python traceback display, plus the datetime.

This nearly works:

import sys, traceback, time
    
def exc_handler(ex_cls, ex, tb):
    with open('mylog.log', 'a') as f:
        dt = time.strftime('%Y-%m-%d %H:%M:%S')
        f.write(f"{dt}\n")
        traceback.print_tb(tb, file=f)
        # traceback.print_exception(ex, tb=None, value="", file=f)  # another approach, doesn't work either
        f.write(f"{dt}\n")

sys.excepthook = exc_handler

def function1():
    1/0

def function2():
    function1()

function2()

except that the exception name is not displayed, and other similar little differences ("Traceback..." is not written).

How to have the exact same format as the default Python exception traceback display?

Example:

2022-10-19 11:19:18
  File "D:\main.py", line 18, in <module>
    function2()
  File "D:\main.py", line 16, in function2
    function1()
  File "D:\main.py", line 13, in function1
    1/0
2022-10-19 11:19:18

Here is how it should be logged:

2022-10-19 11:19:18
Traceback (most recent call last):
  File "D:\main.py", line 18, in <module>
    function2()
  File "D:\main.py", line 16, in function2
    function1()
  File "D:\main.py", line 13, in function1
    1/0
ZeroDivisionError: division by zero
2022-10-19 11:19:18

Notes:

  • if possible, I don't want to include my whole code in a global big try: except: block, I prefer an exception handler on top, and then the usual code without a big try: except: block.

  • I've already read How to log error to file, and not fail on exception and similar questions, but here it's not the exact same display as usual traceback display

Basj
  • 41,386
  • 99
  • 383
  • 673
  • The timestamp doesn't seem to be in your second example at all. What output do you want? Do you just want to [print the whole exception](https://docs.python.org/3/library/traceback.html#traceback.print_exception) instead of the traceback? – jonrsharpe Oct 19 '22 at 09:28
  • @jonrsharpe I updated. I would like to log in the file the exact same thing (traceback etc.) you would see usually displayed + datetimes. – Basj Oct 19 '22 at 09:30
  • So did you try using `print_exception` instead of the method that just gives you the traceback part? – jonrsharpe Oct 19 '22 at 09:33
  • @jonrsharpe with `traceback.print_exception(ex, tb=None, value="", file=f)` instead of mine it doesn't work, it only prints "str". https://docs.python.org/3/library/traceback.html#traceback.print_exception – Basj Oct 19 '22 at 09:38
  • What do you mean? Give a [mre] of that. – jonrsharpe Oct 19 '22 at 09:41
  • @jonrsharpe The first code black of my question + the line 7 replaced by `traceback.print_exception(ex, tb=None, value="", file=f)`. Thanks! See my edited question's first code block. – Basj Oct 19 '22 at 09:43
  • No, don't just describe it - show the thing that _should_ work, not (or not _only_) the thing that's clearly not going to (or rather, the thing that's working as documented but doing something you say you don't want). – jonrsharpe Oct 19 '22 at 09:52
  • @jonrsharpe I don't understand your comment, I included this in my various code blocks. – Basj Oct 19 '22 at 09:54
  • @jonrsharpe I have a solution (https://stackoverflow.com/a/74123501/1422096) but maybe we can do nicer than `''.join(traceback.format_exception(exctype, value, tb))`. Any idea about this? – Basj Oct 19 '22 at 10:05

1 Answers1

1

I couldn't make it work with traceback.print_tb or traceback.print_exception, it was not exactly the same format.

This works (the datetime is only written once, this is ok):

import logging, sys, traceback

logging.basicConfig(filename='test.log', filemode='a', format='%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=logging.DEBUG)
logger = logging.getLogger('logger')
sys.excepthook = lambda exctype, value, tb: logging.error(''.join(traceback.format_exception(exctype, value, tb)))  # don't use logger.exception: see https://stackoverflow.com/a/28302786

# or, simpler, without the traceback module:
sys.excepthook = lambda exctype, value, tb: logging.error("", exc_info=(exctype, value, tb))

print("hello")

def function1():
    1/0

def function2():
    function1()

function2()

See also this precise answer: https://stackoverflow.com/a/36635362

Basj
  • 41,386
  • 99
  • 383
  • 673