python exception message capturing
Asked Answered
C

15

929
import ftplib
import urllib2
import os
import logging
logger = logging.getLogger('ftpuploader')
hdlr = logging.FileHandler('ftplog.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)
FTPADDR = "some ftp address"

def upload_to_ftp(con, filepath):
    try:
        f = open(filepath,'rb')                # file to send
        con.storbinary('STOR '+ filepath, f)         # Send the file
        f.close()                                # Close file and FTP
        logger.info('File successfully uploaded to '+ FTPADDR)
    except, e:
        logger.error('Failed to upload to ftp: '+ str(e))

This doesn't seem to work, I get syntax error, what is the proper way of doing this for logging all kind of exceptions to a file

Cuxhaven answered 14/1, 2011 at 11:33 Comment(5)
Your indentation is broken. And omit the , after except.Basaltware
@SvenMarnach, if you omit the , after except, you'll get global name 'e' is not defined, which is not much better than wrong syntax.Wretch
@Val: Should be except Exception as e or except Exception, e, depending on Python version.Basaltware
Probably it's somewhere around those 8 answers, but when you open a file, close part should never be inside the try statement, but either in a finally statement or wrapped by a with statement.Acetic
You can do it like UnitTests in requests package do fixexception.com/requests/expected-exceptionTwentieth
O
1222

You have to define which type of exception you want to catch. So write except Exception as e: instead of except, e: for a general exception.

Other possibility is to write your whole try/except code this way:

try:
    with open(filepath,'rb') as f:
        con.storbinary('STOR '+ filepath, f)
    logger.info('File successfully uploaded to '+ FTPADDR)
except Exception as e:      # works on python 3.x
    logger.error('Failed to upload to ftp: %s', repr(e))

In older versions of Python 2.x, use except Exception, e instead of except Exception as e:

try:
    with open(filepath,'rb') as f:
        con.storbinary('STOR '+ filepath, f)
    logger.info('File successfully uploaded to %s', FTPADDR)
except Exception, e:        # works on python 2.x
    logger.error('Failed to upload to ftp: %s', repr(e))
Onehorse answered 14/1, 2011 at 11:40 Comment(7)
repr(e) gives you the exception(and the message string); str(e) only gives the message string.Periscope
@whitebeard. Thanks for diffusing the clickbait, especially since it is misleading (you probably do want to use str).Peroxidize
As an alternative for logging exception you could use logger.exception(e) instead. It will log the exception with traceback at the same logging.ERROR level.Nudibranch
@Nudibranch this doesn't seem to be true. It appears to call str() on the exception: ideone.com/OaCOpOKovach
except Exception, e: throws a Syntax error to me in python 3. Is this expected?Claver
@CharlieParker in Python3 write except Exception as e:Onehorse
This is a bit misleading in 2020 because nobody has a Python version anymore that would require your first way (nobody uses Python <2.7), yet your answer makes this seem like the default way to go in Python 2, even though the second way is virtually always better. You should just remove the first way and thereby make the answer clearer.Vardon
C
386

The syntax is no longer supported in python 3. Use the following instead.

try:
    do_something()
except BaseException as e:
    logger.error('Failed to do something: ' + str(e))
Cephalochordate answered 25/1, 2013 at 20:2 Comment(8)
Actually, you should use logger.error('Failed to do something: %s', str(e)) That way, if your logger level is above error it doesn't do the string interpolation.Hygienic
@Hygienic - You are incorrect. The statement logging.error('foo %s', str(e)) will always convert e to a string. To achieve what you are afterm you would use logging.error('foo %s', e) - thereby allowing the logging framework to do (or not do) the conversion.Gastronomy
Are you sure about that @RonDahlgren? I was under the impression that logging.error('message %s', expression) was lazily evaluated regardless of the expression, and only interpolates the string if the log is actually going to be output anywhere.Hygienic
You can verify in a python REPL (here with Python 3.5.2 and ipython): see my gist hereGastronomy
As an alternative for logging exception you could use logger.exception(e) instead. It will log the exception with traceback at the same logging.ERROR level.Nudibranch
"The syntax is no longer supported in python 3." What syntax are you referring to?Conflux
I think he/she meant "except Exception, e:"Weikert
Beware that except BaseException and except Exception are not on the same level. except Exception does work in Python3, but it won't catch KeyboardInterrupt for instance (which can be very convenient if you want to be able to interrupt your code!), whereas BaseException catches any exception. See this link for the hierarchy of exceptions.Ingate
L
97

If you want the error class, error message, and stack trace, use sys.exc_info().

Minimal working code with some formatting:

import sys
import traceback

try:
    ans = 1/0
except BaseException as ex:
    # Get current system exception
    ex_type, ex_value, ex_traceback = sys.exc_info()

    # Extract unformatter stack traces as tuples
    trace_back = traceback.extract_tb(ex_traceback)

    # Format stacktrace
    stack_trace = list()

    for trace in trace_back:
        stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3]))

    print("Exception type : %s " % ex_type.__name__)
    print("Exception message : %s" %ex_value)
    print("Stack trace : %s" %stack_trace)

Which gives the following output:

Exception type : ZeroDivisionError
Exception message : division by zero
Stack trace : ['File : .\\test.py , Line : 5, Func.Name : <module>, Message : ans = 1/0']

The function sys.exc_info() gives you details about the most recent exception. It returns a tuple of (type, value, traceback).

traceback is an instance of traceback object. You can format the trace with the methods provided. More can be found in the traceback documentation .

Lemal answered 2/4, 2018 at 14:55 Comment(3)
Using e.__class__.__name__ can return the exception class as well.Arapaho
Thanks for the info, finally decide to use self.logger.info("{} - {}".format(type(error).__name__, str(error))), works like a charm.Yalu
woah, what a mess... so much work to just get error stack trace...Jefe
L
67

There are some cases where you can use the e.message or e.messages.. But it does not work in all cases. Anyway the more safe is to use the str(e)

try:
  ...
except Exception as e:
  print(e.message)
Lincoln answered 17/4, 2017 at 14:43 Comment(3)
The problem with this is, for example, if you except Exception as e, and e is an IOError, you get e.errno, e.filename, and e.strerror, but apparently no e.message (at least in Python 2.7.12). If you want to capture the error message, use str(e), as in the other answers.Unblown
@Unblown What if you catch the IOError before Exception?Allier
@HeribertoJuárez Why catch special cases while you can simply cast it to string?Desultory
R
55

Updating this to something simpler for logger (works for both python 2 and 3). You do not need traceback module.

import logging

logger = logging.Logger('catch_all')

def catchEverythingInLog():
    try:
        ... do something ...
    except Exception as e:
        logger.error(e, exc_info=True)
        ... exception handling ...

This is now the old way (though still works):

import sys, traceback

def catchEverything():
    try:
        ... some operation(s) ...
    except:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        ... exception handling ...

exc_value is the error message.

Rangefinder answered 30/9, 2013 at 18:58 Comment(2)
This would be my preferred method. Just printing the string is useful for logging I suppose, but if I need to do anything with that information I need more than just a string.Oenone
You don't need to 'import traceback' in the second example, right?Enrichetta
M
24

You can use logger.exception("msg") for logging exception with traceback:

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))
Muniments answered 10/2, 2015 at 12:9 Comment(2)
Coincidently, e.msg is the string representation of Exception class.Lucania
Or simply logger.exception(e).Nudibranch
A
24

Using str(e) or repr(e) to represent the exception, you won't get the actual stack trace, so it is not helpful to find where the exception is.

After reading other answers and the logging package doc, the following two ways works great to print the actual stack trace for easier debugging:

use logger.debug() with parameter exc_info

try:
    # my code
except SomeError as e:
    logger.debug(e, exc_info=True)

use logger.exception()

or we can directly use logger.exception() to print the exception.

try:
    # my code
except SomeError as e:
    logger.exception(e)
Ahithophel answered 26/4, 2020 at 13:34 Comment(0)
K
21

After python 3.6, you can use formatted string literal. It's neat! (https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-pep498)

try
 ...
except Exception as e:
    logger.error(f"Failed to upload to ftp: {e}")
Kura answered 6/9, 2018 at 14:16 Comment(0)
M
13

You can try specifying the BaseException type explicitly. However, this will only catch derivatives of BaseException. While this includes all implementation-provided exceptions, it is also possibly to raise arbitrary old-style classes.

try:
  do_something()
except BaseException, e:
  logger.error('Failed to do something: ' + str(e))
Misogynist answered 14/1, 2011 at 11:40 Comment(0)
B
13

If you want to see the original error message, (file & line number)

import traceback
try:
    print(3/0)
except Exception as e:    
    traceback.print_exc() 

This will show you the same error message as if you didn't use try-except.

Betook answered 16/12, 2021 at 10:22 Comment(0)
S
7

for the future strugglers, in python 3.8.2(and maybe a few versions before that), the syntax is

except Attribute as e:
    print(e)
Schermerhorn answered 21/3, 2020 at 21:0 Comment(0)
M
6

In Python 3, str(ex) gives us the error message. You could use repr(ex) to get the full text, including the name of the exception raised.

arr = ["a", "b", "c"]

try:
    print(arr[5])
except IndexError as ex:
    print(repr(ex)) # IndexError: list index out of range
    print(str(ex)) # list index out of range
Mok answered 25/1, 2023 at 0:51 Comment(0)
S
6

There is also a way to get the raw values passed to the exception class without having to change the content type.

For e.g I raise type codes with error messages in one of my frameworks.

try:
    # TODO: Your exceptional code here 
    raise Exception((1, "Your code wants the program to exit"))

except Exception as e:
    print("Exception Type:", e.args[0][0], "Message:", e.args[0][1])

Output

Exception Type: 1 Message: 'Your code wants the program to exit'

Serology answered 28/1, 2023 at 17:44 Comment(0)
D
5

Use str(ex) to print execption

try:
   #your code
except ex:
   print(str(ex))
Dendrite answered 29/5, 2018 at 12:42 Comment(0)
S
0

The easiest way to do this is available through the Polog library. Import it:

$ pip install polog

And use:

from polog import log, config, file_writer


config.add_handlers(file_writer('file.log'))

with log('message').suppress():
    do_something()

Note how much less space the code has taken up vertically: only 2 lines.

Stonehenge answered 26/10, 2022 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.