如何在gRPC python中定义全局错误处理程序

时间:2018-10-02 12:37:01

标签: python error-handling interceptor grpc-python

我正在尝试捕获任何服务程序中引发的任何异常,因此我可以确保只传播已知的异常,而不传播诸如ValueError,TypeError等意外的异常。

我希望能够捕获任何引发的错误,并对它们进行格式化或将其转换为其他错误,以便更好地控制所公开的信息。

我不想用try / except包围每个服务程序方法。

我尝试使用拦截器,但是我无法在那里捕获错误。

是否可以为grpc服务器指定错误处理程序?像您对Flask或其他任何HTTP服务器所做的事情一样?

3 个答案:

答案 0 :(得分:2)

也许这会帮助您:)

def _wrap_rpc_behavior(handler, fn):
    if handler is None:
        return None

    if handler.request_streaming and handler.response_streaming:
        behavior_fn = handler.stream_stream
        handler_factory = grpc.stream_stream_rpc_method_handler
    elif handler.request_streaming and not handler.response_streaming:
        behavior_fn = handler.stream_unary
        handler_factory = grpc.stream_unary_rpc_method_handler
    elif not handler.request_streaming and handler.response_streaming:
        behavior_fn = handler.unary_stream
        handler_factory = grpc.unary_stream_rpc_method_handler
    else:
        behavior_fn = handler.unary_unary
        handler_factory = grpc.unary_unary_rpc_method_handler

    return handler_factory(fn(behavior_fn,
                              handler.request_streaming,
                              handler.response_streaming),
                           request_deserializer=handler.request_deserializer,
                           response_serializer=handler.response_serializer)


class TracebackLoggerInterceptor(grpc.ServerInterceptor):

    def intercept_service(self, continuation, handler_call_details):
        def latency_wrapper(behavior, request_streaming, response_streaming):

            def new_behavior(request_or_iterator, servicer_context):
                try:
                    return behavior(request_or_iterator, servicer_context)
                except Exception as err:
                    logger.exception(err, exc_info=True)
            return new_behavior

        return _wrap_rpc_behavior(continuation(handler_call_details),    latency_wrapper)

答案 1 :(得分:1)

正如前面的一些评论所建议的那样,我尝试了效果很好的元类方法。

附加是一个简单的示例,用于演示如何拦截grpc调用。 您可以通过为元类提供装饰器列表来扩展此功能,并将其应用于每个函数。

此外,明智的做法是对应用包装程序的方法进行更多选择。一个不错的选择是列出自动生成的基类的方法,然后只包装这些方法。

from types import FunctionType
from functools import wraps


def wrapper(method):
    @wraps(method)
    def wrapped(*args, **kwargs):
        # do stuff here
        return method(*args, **kwargs)

    return wrapped


class ServicerMiddlewareClass(type):
    def __new__(meta, classname, bases, class_dict):
        new_class_dict = {}

        for attribute_name, attribute in class_dict.items():
            if isinstance(attribute, FunctionType):
                # replace it with a wrapped version
                attribute = wrapper(attribute)

            new_class_dict[attribute_name] = attribute

        return type.__new__(meta, classname, bases, new_class_dict)


# In order to use
class MyGrpcService(grpc.MyGrpcServicer, metaclass=ServicerMiddlewareClass):
   ...

答案 2 :(得分:0)

gRPC Python当前不支持服务器端全局错误处理程序。拦截器不会在intercept_service函数内执行服务器处理程序,因此无法尝试/例外。

此外,我发现gRPC Python服务器拦截器实现不同于他们在L13-Python-Interceptors.md#server-interceptors上提出的原始实现。如果实现坚持原始设计,则可以通过handlerrequest / request_iterator轻松地将拦截器用作全局错误处理程序。

# Current Implementation
intercept_service(self, continuation, handler_call_details)

# Original Design
intercept_unary_unary_handler(self, handler, method, request, servicer_context)
intercept_unary_stream_handler(self, handler, method, request, servicer_context)
intercept_stream_unary_handler(self, handler, method, request_iterator, servicer_context)
intercept_stream_stream_handler(self, handler, method, request_iterator, servicer_context)

请向https://github.com/grpc/grpc/issues提交功能请求问题。