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