896
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

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Hellnar
  • 62,315
  • 79
  • 204
  • 279
  • 3
    Your indentation is broken. And omit the `,` after `except`. – Sven Marnach Jan 14 '11 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. – Val Nov 18 '13 at 11:11
  • 20
    @Val: Should be `except Exception as e` or `except Exception, e`, depending on Python version. – Sven Marnach Nov 19 '13 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. –  Aug 24 '18 at 17:13
  • You can do it like UnitTests in requests package do https://fixexception.com/requests/expected-exception/ – Ivan Borshchov Jun 03 '21 at 07:37

15 Answers15

1191

You have to define which type of exception you want to catch. So write except Exception, e: instead of except, e: for a general exception (that will be logged anyway).

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, e: # work on python 2.x
    logger.error('Failed to upload to ftp: '+ str(e))

in Python 3.x and modern versions of Python 2.x use except Exception as e instead of except Exception, e:

try:
    with open(filepath,'rb') as f:
        con.storbinary('STOR '+ filepath, f)
    logger.info('File successfully uploaded to '+ FTPADDR)
except Exception as e: # work on python 3.x
    logger.error('Failed to upload to ftp: '+ str(e))
Baris Senyerli
  • 642
  • 7
  • 13
eumiro
  • 207,213
  • 34
  • 299
  • 261
  • 248
    repr(e) gives you the exception(and the message string); str(e) only gives the message string. – whitebeard Jul 30 '16 at 11:28
  • @whitebeard. Thanks for diffusing the clickbait, especially since it is misleading (you probably do want to use `str`). – Mad Physicist Aug 17 '16 at 17:41
  • 19
    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. – mbdevpl Aug 31 '16 at 09:50
  • 1
    @mbdevpl this doesn't seem to be true. It appears to call str() on the exception: http://ideone.com/OaCOpO – KevinOrr Oct 04 '16 at 20:08
  • 9
    `except Exception, e:` throws a Syntax error to me in python 3. Is this expected? – Charlie Parker Nov 01 '17 at 04:12
  • 35
    @CharlieParker in Python3 write `except Exception as e:` – eumiro Nov 01 '17 at 05:38
  • 1
    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. – Alex Dec 22 '20 at 15:23
381

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))
sjtaheri
  • 4,409
  • 3
  • 19
  • 15
  • 2
    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 Feb 24 '16 at 23:19
  • 11
    @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. –  Jul 11 '16 at 23:29
  • 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. – avyfain Jul 12 '16 at 03:56
  • 1
    You can verify in a python REPL (here with Python 3.5.2 and ipython): [see my gist here](https://gist.github.com/influenza/e28ffc405f6a53f3689d5ce7c70bca91) –  Jul 12 '16 at 15:27
  • 4
    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. – mbdevpl Aug 31 '16 at 09:51
  • "*The syntax is no longer supported in python 3.*" What syntax are you referring to? – Stevoisiak Feb 21 '18 at 17:42
  • 2
    I think he/she meant "except Exception, e:" – Roy Mar 13 '18 at 18:34
  • 18
    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](https://docs.python.org/3/library/exceptions.html#exception-hierarchy) for the hierarchy of exceptions. – jeannej Jun 18 '18 at 21:52
92

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 .

ziedaniel1
  • 351
  • 1
  • 9
Kavindu Dodanduwa
  • 12,193
  • 3
  • 33
  • 46
  • 6
    Using `e.__class__.__name__ ` can return the exception class as well. – kenorb Jun 14 '18 at 20:13
  • 1
    Thanks for the info, finally decide to use `self.logger.info("{} - {}".format(type(error).__name__, str(error)))`, works like a charm. – MadHatter Aug 12 '22 at 07:25
65

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)
Slipstream
  • 13,455
  • 3
  • 59
  • 45
  • 65
    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 Apr 19 '17 at 18:28
  • @epalm What if you catch the IOError before Exception? – Herii Jan 12 '20 at 14:21
  • 2
    @HeribertoJuárez Why catch special cases while you can simply cast it to string? – HosseyNJF Apr 19 '20 at 18:13
53

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.

berniey
  • 2,772
  • 1
  • 18
  • 8
  • 3
    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. – sulimmesh Mar 30 '16 at 18:31
  • 3
    You don't need to 'import traceback' in the second example, right? – starikoff Oct 12 '18 at 13:13
24

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

try:
    #your code
except Exception as e:
    logger.exception('Failed: ' + str(e))
Peter
  • 609
  • 1
  • 8
  • 15
22

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)
jdhao
  • 24,001
  • 18
  • 134
  • 273
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}")
Chuan Ma
  • 9,754
  • 2
  • 45
  • 37
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))
Heini Høgnason
  • 667
  • 4
  • 10
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.

starriet
  • 2,565
  • 22
  • 23
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)
syter
  • 135
  • 2
  • 10
4

Use str(ex) to print execption

try:
   #your code
except ex:
   print(str(ex))
Niraj Trivedi
  • 2,370
  • 22
  • 24
4

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'

Illegal Operator
  • 656
  • 6
  • 14
3

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

Evgeniy Blinov
  • 351
  • 3
  • 3