Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make Python output exceptions in one line / via logging?

I am using AWS and use AWS cloudwatch to view logs. While things should not break on AWS, they could. I just had such a case. Then I searched for Traceback and just got the lines

Traceback (most recent call last):

without the actual traceback. I have a working structured logging setup (see other question) and I would like to get tracebacks in a similar way.

So instead of:

Traceback (most recent call last):
  File "/home/math/Desktop/test.py", line 32, in <module>
    adf
NameError: name 'adf' is not defined

something like

{"message": "Traceback (most recent call last):\n      File \"/home/math/Desktop/test.py\", line 32, in <module>\n        adf\n    NameError: name 'adf' is not defined", "lineno": 35, "pathname": "/home/math/Desktop/test.py"}

or even better also with the string in a JSON format.

The only way to achieve this I can think of is a giant try-except block. Pokemon-style. Is there a better solution?

like image 698
Martin Thoma Avatar asked Feb 06 '18 11:02

Martin Thoma


People also ask

How do I log exceptions in python logging?

To log an exception in Python we can use logging module and through that we can log the error. Logging an exception in python with an error can be done in the logging. exception() method. This function logs a message with level ERROR on this logger.

Does logger exception raise an exception?

It depends on the situation, but logging and then raising an exception is generally considered an antipattern. It's redundant and clutters logs. Unless you're expecting something to catch that exception and suppress the message, don't log. Pythonic is not really a look as it is the formatting of code.

Does logging error stop execution?

With respect to logging vs. throwing, they're two separate concerns. Throwing an exception will interrupt your execution, prevent any further work, perhaps rollback database commits etc. Logging will simply dump info to the log file (or elsewhere).


2 Answers

You can use sys.excepthook. It is invoked whenever an exception occurs in your script.

import logging
import sys
import traceback

def exception_logging(exctype, value, tb):
    """
    Log exception by using the root logger.

    Parameters
    ----------
    exctype : type
    value : NameError
    tb : traceback
    """
    write_val = {'exception_type': str(exctype),
                 'message': str(traceback.format_tb(tb, 10))}
    logging.exception(str(write_val))

Then in your script you have to override the value of sys.excepthook.

sys.excepthook = exception_logging

Now whenever an exception occurs it will be logged with your logger handler.

Note: Don't forget to setup logger before running this

like image 103
Arpit Solanki Avatar answered Oct 30 '22 01:10

Arpit Solanki


In case somebody wants the exception logged in its default format, but in one line (for any reason), based on the accepted answer:

def exception_logging(exctype, value, tb):
    """
    Log exception in one line by using the root logger.

    Parameters
    ----------
    exctype : exception type
    value : seems to be the Exception object (with its message)
    tb : traceback
    """
    logging.error(''.join(traceback.format_exception(exctype, value, tb)))

Please also note, that it uses logging.error() instead of logging.exception() which also printed some extra "NoneType: None" line.
Also note that it only seems to work with uncaught exceptions.
For logging caught exceptions, visit How do I can format exception stacktraces in Python logging? and see also my answer.

like image 39
Attila123 Avatar answered Oct 29 '22 23:10

Attila123