Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize an Exception

When I try to serialize an exception using json.dump, I get errors like

TypeError: IOError('socket error', error(61, 'Connection refused')) is not JSON serializable

and

TypeError: error(61, 'Connection refused') is not JSON serializable

The __dict__ field of exceptions is {} (this is why How to make a class JSON serializable does not help me: the answers there assume that __dict__ contains all the necessary information, they also assume that I have control over the class to be serialized).

Is there something more intelligent that saving str(exn)?

I would prefer a human-readable text representation (not pickle).

PS. Here is what I came up with:

def exception_as_dict(ex):
    return dict(type=ex.__class__.__name__,
                errno=ex.errno, message=ex.message,
                strerror=exception_as_dict(ex.strerror)
                if isinstance(ex.strerror,Exception) else ex.strerror)

json.dumps(exception_as_dict(err),indent=2)
{
  "errno": "socket error", 
  "type": "IOError", 
  "strerror": {
    "errno": 61, 
    "type": "error", 
    "strerror": "Connection refused"
  }
}
like image 378
sds Avatar asked Jul 21 '17 14:07

sds


People also ask

What is a serialization exception?

SerializationException(String, Exception) Initializes a new instance of the SerializationException class with a specified error message and a reference to the inner exception that is the cause of this exception.

How do you serialize an exception object in C#?

If you're trying to serialize the exception for a log, it might be better to do a . ToString(), and then serialize that to your log. But here's an article about how to do it, and why. Basically, you need to implement ISerializable on your exception.

Do exceptions need to be serializable?

All exceptions by default are serializable and that's a language design decision because the authors wanted exceptions to be capable of being sent across the wire without any special configuration.


2 Answers

You can use exc_info with traceback as below:

import traceback
import sys
try:
    raise KeyError('aaa!!!')
except Exception as e:
    exc_info = sys.exc_info()
    print(''.join(traceback.format_exception(*exc_info)))
like image 75
David Weinberg Avatar answered Oct 14 '22 20:10

David Weinberg


Exceptions can not be pickled (by default), you have two options:

  1. Use Python's built in format_exc() and serialize the formatted string.

  2. Use tblib

With the latter, you can pass wrapped exceptions and also reraise them later.

import tblib.pickling_support
tblib.pickling_support.install()
import pickle, sys 

def inner_0():
    raise Exception('fail')

def inner_1():
    inner_0()

def inner_2():
    inner_1()

try:
    inner_2()
except:
    s1 = pickle.dumps(sys.exc_info())
like image 40
knipknap Avatar answered Oct 14 '22 19:10

knipknap