2009-10-15 2 views
1

Стандартные библиотеки (xmlrpclib + SimpleXMLRPCServer в Python 2 и xmlrpc.server в Python 3) сообщают обо всех ошибках (включая ошибки использования) как исключения python, которые не подходят для служб общего пользования: строки исключений часто не являются легко понятны без знаний python и могут выставить некоторую конфиденциальную информацию. Нетрудно это исправить, но я предпочитаю не изобретать колесо. Есть ли сторонняя библиотека с лучшими сообщениями об ошибках? Я заинтересован в хороших сообщениях об ошибках для всех ошибок использования и скрытия внутренних компонентов при представлении внутренних ошибок (это лучше сделать с протоколированием).XML-RPC-сервер с лучшей отчетностью об ошибках

xmlrpclib уже есть константы для таких ошибок: NOT_WELLFORMED_ERROR, UNSUPPORTED_ENCODING, INVALID_ENCODING_CHAR, INVALID_XMLRPC, METHOD_NOT_FOUND, INVALID_METHOD_PARAMS, INTERNAL_ERROR.

ответ

1

Он похож не готова библиотеки с моими требованиями, поэтому в конечном итоге с собственной реализацией:

class ApplicationError(Fault): 

    def __init__(self, exc_info): 
     Fault.__init__(self, xmlrpclib.APPLICATION_ERROR, 
         u'Application internal error') 


class NotWellformedError(Fault): 

    def __init__(self, exc): 
     Fault.__init__(self, xmlrpclib.NOT_WELLFORMED_ERROR, str(exc)) 


class UnsupportedEncoding(Fault): 

    def __init__(self, exc): 
     Fault.__init__(self, xmlrpclib.UNSUPPORTED_ENCODING, str(exc)) 


# XXX INVALID_ENCODING_CHAR is masked by xmlrpclib, so the error code will be 
# INVALID_XMLRPC. 
class InvalidRequest(Fault): 

    def __init__(self, message): 
     ault.__init__(self, xmlrpclib.INVALID_XMLRPC, message) 


class MethodNotFound(Fault): 

    def __init__(self, name): 
     Fault.__init__(self, xmlrpclib.METHOD_NOT_FOUND, 
         u'Method %r is not supported' % name) 


class WrongMethodUsage(Fault): 

    def __init__(self, message): 
     Fault.__init__(self, xmlrpclib.INVALID_METHOD_PARAMS, message) 


class WrongType(Fault): 

    def __init__(self, arg_name, type_name): 
     Fault.__init__(self, xmlrpclib.INVALID_METHOD_PARAMS, 
         u'Parameter %s must be %s' % (arg_name, type_name)) 


class XMLRPCDispatcher(SimpleXMLRPCDispatcher, XMLRPCDocGenerator): 

    server_name = server_title = 'Personalization center RPC interface' 
    server_documentation = 'Available methods' 

    def __init__(self, methods): 
     SimpleXMLRPCDispatcher.__init__(self, allow_none=True, encoding=None) 
     self.register_instance(methods) 
     self.register_multicall_functions() 
     #self.register_introspection_functions() 

    def _dispatch(self, method_name, args): 
     if self.funcs.has_key(method_name): 
      method = self.funcs[method_name] 
     else: 
      method = self.instance._getMethod(method_name) 
     arg_names, args_name, kwargs_name, defaults = \ 
               inspect.getargspec(method) 
     assert arg_names[0]=='self' 
     arg_names = arg_names[1:] 
     n_args = len(args) 
     if not (args_name or defaults): 
      if n_args!=len(arg_names): 
       raise WrongMethodUsage(
        u'Method %s takes exactly %d parameters (%d given)' % \ 
           (method_name, len(arg_names), n_args)) 
     else: 
      min_args = len(arg_names)-len(defaults) 
      if len(args)<min_args: 
       raise WrongMethodUsage(
        u'Method %s requires at least %d parameters (%d given)' % \ 
           (method_name, min_args, n_args)) 
      if not args_name and n_args>len(arg_names): 
       raise WrongMethodUsage(
        u'Method %s requires at most %d parameters (%d given)' % \ 
           (method_name, len(arg_names), n_args)) 
     try: 
      return method(*args) 
     except Fault: 
      raise 
     except: 
      logger.exception('Application internal error for %s%r', 
          method_name, args) 
      raise ApplicationError(sys.exc_info()) 

    def dispatch(self, data): 
     try: 
      try: 
       args, method_name = xmlrpclib.loads(data) 
      except ExpatError, exc: 
       raise NotWellformedError(exc) 
      except LookupError, exc: 
       raise UnsupportedEncoding(exc) 
      except xmlrpclib.ResponseError: 
       raise InvalidRequest('Request structure is invalid') 
      method_name = method_name.encode('ascii', 'replace') 
      result = self._dispatch(method_name, args) 
     except Fault, exc: 
      logger.warning('Fault %s: %s', exc.faultCode, exc.faultString) 
      return xmlrpclib.dumps(exc) 
     else: 
      try: 
       return xmlrpclib.dumps((result,), methodresponse=1) 
      except: 
       logger.exception('Application internal error when marshalling'\ 
           ' result for %s%r', method_name, args) 
       return xmlrpclib.dumps(ApplicationError(sys.exc_info())) 


class InterfaceMethods: 

    def _getMethod(self, name): 
     if name.startswith('_'): 
      raise MethodNotFound(name) 
     try: 
      method = getattr(self, name) 
     except AttributeError: 
      raise MethodNotFound(name) 
     if not inspect.ismethod(method): 
      raise MethodNotFound(name) 
     return method 
1

Я не думаю, что у вас есть конкретная проблема с библиотекой. При использовании любой библиотеки или фреймворка вы, как правило, хотите уловить все ошибки, зарегистрировать их где-нибудь и выбросить «Упс, у нас проблемы. Вы можете связаться с нами по адресу [email protected] с номером ошибки 100 и сообщить нам, что ты сделал." Так обернуть failable точку входа в Try/уловах, создать общий регистратор и ступайте ...

+1

Затем они попытаются описать что-то, потерпят неудачу, и вы, наконец, закончите с возможностью ведения журнала (возможно, огромных запросов), чтобы увидеть, что они на самом деле делают. Представьте себе сотни таких клиентов. Некоторые из них будут развиваться шаг за шагом, преодолевая все ошибки, которые вы можете себе представить, и даже больше. –