970
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

5
  • 3
    Your indentation is broken. And omit the , after except. Commented Jan 14, 2011 at 11:35
  • 4
    @SvenMarnach, if you omit the , after except, you'll get global name 'e' is not defined, which is not much better than wrong syntax. Commented Nov 18, 2013 at 11:11
  • 22
    @Val: Should be except Exception as e or except Exception, e, depending on Python version. Commented Nov 19, 2013 at 13:03
  • 1
    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. Commented Aug 24, 2018 at 17:13
  • You can do it like UnitTests in requests package do fixexception.com/requests/expected-exception Commented Jun 3, 2021 at 7:37

16 Answers 16

1282

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))
Sign up to request clarification or add additional context in comments.

7 Comments

repr(e) gives you the exception(and the message string); str(e) only gives the message string.
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.
except Exception, e: throws a Syntax error to me in python 3. Is this expected?
@CharlieParker in Python3 write except Exception as e:
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.
|
403

The syntax except, e: is no longer supported in python 3. Use the following instead.

try:
    do_something()
except BaseException as e:
    logger.error('Failed to do something: %s', str(e))

8 Comments

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.
@avyfain - 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.
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.
I think he/she meant "except Exception, e:"
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.
|
104

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 .

3 Comments

Using e.__class__.__name__ can return the exception class as well.
Thanks for the info, finally decide to use self.logger.info("{} - {}".format(type(error).__name__, str(error))), works like a charm.
woah, what a mess... so much work to just get error stack trace...
71

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)

3 Comments

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.
@epalm What if you catch the IOError before Exception?
@HeribertoJuárez Why catch special cases while you can simply cast it to string?
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.

2 Comments

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.
You don't need to 'import traceback' in the second example, right?
27

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)

Comments

24

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

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))

2 Comments

Coincidently, e.msg is the string representation of Exception class.
Or simply logger.exception(e).
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}")

Comments

14

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.

Comments

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))

Comments

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)

Comments

7

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'

Comments

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

Comments

5

Use str(ex) to print execption

try:
   #your code
except ex:
   print(str(ex))

Comments

0

There were already useful answers provided. Just a small additional hint located between proposals to use sys.exc_info() and to use traceback.print_exc() :

There is a way to capture easily the original exception trace inside the script if saving to log-file is not needed (or before saving to file):

import traceback

try:
    do_something # your code, which could cause exception
except Exception as e:
    exception_details_list = traceback.format_exc()

    print(exception_details_list) # just to show the retrieved exception_details_list

Note: there are also further useful functions available by traceback (e.g. to capture only limited information about exception).

Comments

-1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.