error_catch.py 6.5 KB
Newer Older
F
felixhjh 已提交
1 2 3 4 5
import sys 
import enum 
import os 
import logging 
import traceback
6
#from paddle_serving_server.pipeline import ResponseOp
F
felixhjh 已提交
7 8 9 10 11 12
import threading
import inspect
import traceback
import functools
import re
from .proto import pipeline_service_pb2_grpc, pipeline_service_pb2
F
felixhjh 已提交
13
from .util import ThreadIdGenerator
F
felixhjh 已提交
14 15 16 17 18 19

_LOGGER = logging.getLogger(__name__) 

class CustomExceptionCode(enum.Enum): 
    """
    Add new Exception
F
felixhjh 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
    
    0           Success
    50 ~ 99     Product error
    3000 ~ 3999 Internal service error
    4000 ~ 4999 Conf error 
    5000 ~ 5999 User input error
    6000 ~ 6999 Timeout error
    7000 ~ 7999 Type Check error
    8000 ~ 8999 Internal communication error
    9000 ~ 9999 Inference error
    10000       Other error
    """
    OK = 0
    PRODUCT_ERROR = 50

    NOT_IMPLEMENTED = 3000
    CLOSED_ERROR = 3001
    NO_SERVICE = 3002
    INIT_ERROR = 3003
    CONF_ERROR = 4000
    INPUT_PARAMS_ERROR = 5000
    TIMEOUT = 6000
    TYPE_ERROR = 7000
    RPC_PACKAGE_ERROR = 8000 
    CLIENT_ERROR = 9000
    UNKNOW = 10000


class ProductErrCode(enum.Enum):
    """
    ProductErrCode is a base class for recording business error code. 
    product developers inherit this class and extend more error codes. 
F
felixhjh 已提交
52
    """
F
felixhjh 已提交
53 54
    pass

F
felixhjh 已提交
55 56

class CustomException(Exception):
57
    def __init__(self, exceptionCode, errorMsg, isSendToUser=False):
F
felixhjh 已提交
58 59 60
        super().__init__(self)
        self.error_info = "\n\texception_code: {}\n"\
                          "\texception_type: {}\n"\
61
                          "\terror_msg: {}\n"\
F
felixhjh 已提交
62 63
                          "\tis_send_to_user: {}".format(exceptionCode.value,
                          CustomExceptionCode(exceptionCode).name, errorMsg, isSendToUser)
F
felixhjh 已提交
64 65 66 67
    
    def __str__(self):
        return self.error_info

F
felixhjh 已提交
68 69


F
felixhjh 已提交
70
class ErrorCatch():
F
felixhjh 已提交
71 72 73 74 75 76
    def __init__(self):
        self._id_generator = ThreadIdGenerator(
                     max_id=1000000000000000000,
                     base_counter=0,
                     step=1)

F
felixhjh 已提交
77 78 79 80 81
    def __call__(self, func):
        if inspect.isfunction(func) or inspect.ismethod(func):
            @functools.wraps(func)
            def wrapper(*args, **kw):
                try:
82
                    res = func(*args, **kw)
F
felixhjh 已提交
83 84
                except CustomException as e:
                    log_id = self._id_generator.next()
85
                    resp = pipeline_service_pb2.Response()
F
felixhjh 已提交
86
                    _LOGGER.error("\nLog_id: {}\n{}Classname: {}\nFunctionName:{}\nArgs:{}".format(log_id, traceback.format_exc(), func.__qualname__, func.__name__, args))
F
felixhjh 已提交
87
                    split_list = re.split("\n|\t|:", str(e))
88
                    resp.err_no = int(split_list[3])
F
felixhjh 已提交
89 90 91
                    resp.err_msg = "Log_id: {}  ErrNo: {}  Error_msg: {}  ClassName: {}  FunctionName: {}".format(log_id, resp.err_no, split_list[9], func.__qualname__ ,func.__name__ )
                    is_send_to_user = split_list[-1].replace(" ", "")
                    if is_send_to_user == "True":
92
                         return (None, resp)
F
felixhjh 已提交
93
                    else:
F
felixhjh 已提交
94
                        raise SystemExit("init server error occur")
95
                except Exception as e:
F
felixhjh 已提交
96
                    log_id = self._id_generator.next()
97
                    resp = pipeline_service_pb2.Response()
F
felixhjh 已提交
98 99 100
                    _LOGGER.error("\nLog_id: {}\n{}Classname: {}\nFunctionName: {}\nArgs: {}".format(log_id, traceback.format_exc(), func.__qualname__, func.__name__, args))
                    resp.err_no = CustomExceptionCode.UNKNOW.value
                    resp.err_msg = "Log_id: {}  ErrNo: {}  Error_msg: {}  ClassName: {}  FunctionName: {}".format(log_id, resp.err_no, str(e).replace("\'", ""), func.__qualname__ ,func.__name__ )
101 102 103 104
                    return (None, resp)
                    # other exception won't be sent to users.
                else:
                    resp = pipeline_service_pb2.Response()
F
felixhjh 已提交
105
                    resp.err_no = CustomExceptionCode.OK.value
106 107
                    resp.err_msg = ""
                    return (res, resp)
F
felixhjh 已提交
108

F
felixhjh 已提交
109 110
            return wrapper

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
def ParamChecker(function):
    @functools.wraps(function)
    def wrapper(*args, **kwargs):
        # fetch the argument name list.
        parameters = inspect.signature(function).parameters
        argument_list = list(parameters.keys())

        # fetch the argument checker list.
        checker_list = [parameters[argument].annotation for argument in argument_list]

        # fetch the value list.
        value_list =  [inspect.getcallargs(function, *args, **kwargs)[argument] for argument in inspect.getfullargspec(function).args]

        # initialize the result dictionary, where key is argument, value is the checker result.
        result_dictionary = dict()
        for argument, value, checker in zip(argument_list, value_list, checker_list):
            result_dictionary[argument] = check(argument, value, checker, function)

        # fetch the invalid argument list.
        invalid_argument_list = [key for key in argument_list if not result_dictionary[key]]

        # if there are invalid arguments, raise the error.
        if len(invalid_argument_list) > 0:
F
felixhjh 已提交
134
            raise CustomException(CustomExceptionCode.INPUT_PARAMS_ERROR, "invalid arg list: {}".format(invalid_argument_list))
135 136 137 138 139

        # check the result.
        result = function(*args, **kwargs)
        checker = inspect.signature(function).return_annotation
        if not check('return', result, checker, function):
F
felixhjh 已提交
140
            raise CustomException(CustomExceptionCode.INPUT_PARAMS_ERROR, "invalid return type")
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178

        # return the result.
        return result
    return wrapper


def check(name, value, checker, function):
    if isinstance(checker, (tuple, list, set)):
        return True in [check(name, value, sub_checker, function) for sub_checker in checker]
    elif checker is inspect._empty:
        return True
    elif checker is None:
        return value is None
    elif isinstance(checker, type):
        return isinstance(value, checker)
    elif callable(checker):
        result = checker(value)
        return result

class ParamVerify(object):
    @staticmethod
    def int_check(c, lower_bound=None, upper_bound=None):
        if not isinstance(c, int):
            return False
        if isinstance(lower_bound, int) and isinstance(upper_bound, int):
            return c >= lower_bound and c <= upper_bound
        return True

    @staticmethod
    def file_check(f):
        if not isinstance(f, str):
            return False
        if os.path.exist(f):
            return True
        else:

            return False

F
felixhjh 已提交
179
ErrorCatch = ErrorCatch()