templates/python/facebook_business/crashreporter.py (93 lines of code) (raw):
import sys
import traceback
import inspect
import json
import logging
from enum import Enum
from facebook_business.api import FacebookRequest
from facebook_business.session import FacebookSession
from facebook_business.api import FacebookAdsApi
from facebook_business.exceptions import FacebookError
from facebook_business.exceptions import FacebookRequestError
class Reasons(Enum):
API = 'API'
SDK = 'SDK'
class CrashReporter(object):
reporter_instance = None
logger = None
def __init__(self, app_id, excepthook):
self.__app_id = app_id
self.__excepthook = excepthook
@classmethod
def enable(cls):
if cls.reporter_instance == None:
api = FacebookAdsApi.get_default_api()
cls.reporter_instance = cls(api._session.app_id, sys.excepthook)
sys.excepthook = cls.reporter_instance.__exception_handler
cls.logging('Enabled')
@classmethod
def disable(cls):
if cls.reporter_instance != None:
# Restore the original excepthook
sys.excepthook = cls.reporter_instance.__excepthook
cls.reporter_instance = None
cls.logging('Disabled')
@classmethod
def enableLogging(cls):
if cls.logger == None:
logging.basicConfig()
cls.logger = logging.getLogger(__name__)
cls.logger.setLevel(logging.INFO)
@classmethod
def disableLogging(cls):
if cls.logger != None:
cls.logger = None
@classmethod
def logging(cls, info):
if cls.logger != None:
cls.logger.info(info)
def __exception_handler(self, etype, evalue, tb):
params = self.__build_param(etype, tb)
if params:
CrashReporter.logging('Crash detected!')
self.__send_report(params)
else:
CrashReporter.logging('No crash detected.')
self.__forward_exception(etype, evalue, tb)
def __forward_exception(self, etype, evalue, tb):
self.__excepthook(etype, evalue, tb)
def __build_param(self, etype, tb):
if not etype:
return None
fb_request_errors = [cls.__name__ for cls in FacebookError.__subclasses__()]
reason = None
if etype.__name__ == FacebookRequestError.__name__:
reason = Reasons.API
elif etype.__name__ in fb_request_errors:
reason = Reasons.SDK
if reason is None:
extracted_tb = traceback.extract_tb(tb, limit=100)
for ii, (filename, line, funcname, code) in enumerate(extracted_tb):
if filename.find('facebook_business') != -1:
reason = Reasons.SDK
if reason is None:
return None
return {
'reason': "{} : {}".format(reason.value, etype.__name__),
'callstack': traceback.format_tb(tb),
'platform': sys.version
};
def __send_report(self, payload):
try:
anonymous = FacebookSession()
api = FacebookAdsApi(anonymous)
request = FacebookRequest(
node_id=self.__app_id,
method='POST',
endpoint='/instruments',
api=api,
)
request.add_params({'bizsdk_crash_report':payload})
request.execute()
CrashReporter.logging('Succeed to Send Crash Report.')
except Exception as e:
CrashReporter.logging('Fail to Send Crash Report.')