项目作者: visiperf

项目描述 :
Golang gRPC helpers, middlewares ...
高级语言: Go
项目地址: git://github.com/visiperf/visigrpc.git
创建时间: 2020-01-22T10:53:52Z
项目社区:https://github.com/visiperf/visigrpc

开源协议:

下载


gRPC helpers, middlewares … for Golang

Package visigrpc provide some functions to help you making a gRPC server. Errors logged on Sentry, Panic interceptor, HTTP status to gRPC code, … Everything is made to assist you :)

Table of contents

Install

Use go get to install this package.

  1. go get github.com/visiperf/visigrpc

Usage

Status

Error

The Error(code codes.Code, msg string) error function is used to return a gRPC error and log it into Sentry.

  1. type server struct { }
  2. func main() {
  3. // init Sentry config
  4. if err := sentry.Init(sentry.ClientOptions{
  5. Dsn: SENTRY_DSN,
  6. Environment: SENTRY_ENV,
  7. Transport: sentry.NewHTTPSyncTransport(),
  8. }); err != nil {
  9. ...
  10. }
  11. // gRPC server
  12. lis, err := net.Listen("tcp", ":9090")
  13. if err != nil {
  14. ...
  15. }
  16. s := grpc.NewServer()
  17. RegisterServiceServer(s, &server{})
  18. if err := s.Serve(lis); err != nil {
  19. ...
  20. }
  21. }
  22. func (s *server) Get(ctx context.Context, in *GetRequest) (*GetResponse, error) {
  23. return nil, status.Error(codes.Unimplemented, "implement me")
  24. }
IMPORTANT : Only Unknown, Internal and DataLoss errors will be reported in Sentry !

New

The New(code codes.Code, msg string) *spb.Status function has same process as Error(...) error function, but returns a *spb.Status instance instead of error.

  1. type server struct { }
  2. func main() {
  3. // init Sentry config
  4. if err := sentry.Init(sentry.ClientOptions{
  5. Dsn: SENTRY_DSN,
  6. Environment: SENTRY_ENV,
  7. Transport: sentry.NewHTTPSyncTransport(),
  8. }); err != nil {
  9. ...
  10. }
  11. // gRPC server
  12. lis, err := net.Listen("tcp", ":9090")
  13. if err != nil {
  14. ...
  15. }
  16. s := grpc.NewServer()
  17. RegisterServiceServer(s, &server{})
  18. if err := s.Serve(lis); err != nil {
  19. ...
  20. }
  21. }
  22. func (s *server) Get(ctx context.Context, in *GetRequest) (*GetResponse, error) {
  23. st := status.New(codes.Internal, "Oups, an error !")
  24. // st.Code -> codes.Internal
  25. // st.Message -> "Oups, an error !"
  26. ...
  27. return nil, status.Error(codes.Unimplemented, "implement me")
  28. }

From Error

If you receive a gRPC error (made with status.Error(…)), you can decode it with FromError(err error) *spb.Status to retrieve the gRPC code and message.

  1. type server struct { }
  2. func main() {
  3. // init Sentry config
  4. if err := sentry.Init(sentry.ClientOptions{
  5. Dsn: SENTRY_DSN,
  6. Environment: SENTRY_ENV,
  7. Transport: sentry.NewHTTPSyncTransport(),
  8. }); err != nil {
  9. ...
  10. }
  11. // gRPC server
  12. lis, err := net.Listen("tcp", ":9090")
  13. if err != nil {
  14. ...
  15. }
  16. s := grpc.NewServer()
  17. RegisterServiceServer(s, &server{})
  18. if err := s.Serve(lis); err != nil {
  19. ...
  20. }
  21. }
  22. func (s *server) Get(ctx context.Context, in *GetRequest) (*GetResponse, error) {
  23. return nil, status.Error(codes.Unimplemented, "implement me")
  24. }
  25. func (s *server) Create(ctx context.Context, in *CreateRequest) (*CreateResponse, error) {
  26. resp, err := s.Get(ctx, &GetRequest{}) // just for example, never directly call self functions with `s *server` !
  27. if err != nil {
  28. st := status.FromError(err)
  29. // st.Code -> codes.Unimplemented
  30. // st.Message -> "implement me"
  31. ...
  32. }
  33. return nil, status.Error(codes.Unimplemented, "implement me")
  34. }

gRPC code from HTTP status

If you make an HTTP request, you can use the GrpcCodeFromHttpStatus(status int) codes.Code func to convert HTTP status code in response to gRPC code.

  1. code := status.GrpcCodeFromHttpStatus(http.StatusForbidden) // http status -> 403 (Forbidden)
  2. // code -> 7 (codes.PermissionDenied)

Panic interceptor

Visigrpc also provide a RecoveryHandler to capture and log panics for Unary and Stream functions.

  1. type server struct { }
  2. func main() {
  3. // init Sentry config
  4. if err := sentry.Init(sentry.ClientOptions{
  5. Dsn: SENTRY_DSN,
  6. Environment: SENTRY_ENV,
  7. Transport: sentry.NewHTTPSyncTransport(),
  8. }); err != nil {
  9. ...
  10. }
  11. // gRPC server
  12. lis, err := net.Listen("tcp", ":9090")
  13. if err != nil {
  14. ...
  15. }
  16. var opts = []grpc_recovery.Option{
  17. grpc_recovery.WithRecoveryHandler(visigrpc.RecoveryHandler),
  18. }
  19. s := grpc.NewServer(
  20. grpc_middleware.WithUnaryServerChain(
  21. grpc_recovery.UnaryServerInterceptor(opts...),
  22. ),
  23. grpc_middleware.WithStreamServerChain(
  24. grpc_recovery.StreamServerInterceptor(opts...),
  25. ),
  26. )
  27. RegisterServiceServer(s, &server{})
  28. if err := s.Serve(lis); err != nil {
  29. ...
  30. }
  31. }
  32. func (s *server) Get(ctx context.Context, in *GetRequest) (*GetResponse, error) {
  33. panic("implement me") // will return codes.Unknown with message "implement me" and log error on Sentry
  34. }

References