Skip to content

Commit

Permalink
Fix: grpc status
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenceLiZhixin committed Mar 16, 2022
1 parent cc345b1 commit 4678adc
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
64 changes: 57 additions & 7 deletions internal/status/status.go
Expand Up @@ -30,12 +30,14 @@ package status
import (
"errors"
"fmt"
"runtime"
"strings"
)

import (
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
perrors "github.com/pkg/errors"

"google.golang.org/genproto/googleapis/rpc/errdetails"
spb "google.golang.org/genproto/googleapis/rpc/status"
Expand All @@ -48,20 +50,27 @@ import (
// Status represents an RPC status code, message, and details. It is immutable
// and should be created with New, Newf, or FromProto.
type Status struct {
s *spb.Status
s *spb.Status
stack *stack
}

// New returns a Status representing c and msg.
// New returns a Status representing c and msg, with user-made error as stack
func New(c codes.Code, msg string) *Status {
return &Status{s: &spb.Status{Code: int32(c), Message: msg}}
newStatus := &Status{s: &spb.Status{Code: int32(c), Message: msg}}
newStatusWithDetail, _ := newStatus.WithDetails(&errdetails.DebugInfo{
StackEntries: []string{
fmt.Sprintf("%+v", callers().StackTrace()), // use e.String() as triple stack
},
})
return newStatusWithDetail
}

// New returns a Status representing c and msg.
func NewWithStacks(c codes.Code, e error) *Status {
// New returns a Status representing c and msg. with e.String() as triple stack field
func NewWithoutStacks(c codes.Code, e error) *Status {
newStatus := &Status{s: &spb.Status{Code: int32(c), Message: e.Error()}}
newStatusWithDetail, _ := newStatus.WithDetails(&errdetails.DebugInfo{
StackEntries: []string{
fmt.Sprintf("%+v", e),
fmt.Sprintf("%+v", e), // use e.String() as triple stack
},
})
return newStatusWithDetail
Expand Down Expand Up @@ -162,13 +171,22 @@ func (s *Status) String() string {
// Error wraps a pointer of a status proto. It implements error and Status,
// and a nil *Error should never be returned by this package.
type Error struct {
s *Status
s *Status
stack stack
}

func (e *Error) Error() string {
return e.s.String()
}

func (e *Error) Message() string {
return e.s.String()
}

func (e *Error) Code() codes.Code {
return e.s.Code()
}

// GRPCStatus returns the Status represented by se.
func (e *Error) GRPCStatus() *Status {
return e.s
Expand Down Expand Up @@ -196,3 +214,35 @@ func (e *Error) Is(target error) bool {
}
return proto.Equal(e.s.s, tse.s.s)
}

// stack represents a stack of program counters.
type stack []uintptr

func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := perrors.Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}

func (s *stack) StackTrace() perrors.StackTrace {
f := make([]perrors.Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = perrors.Frame((*s)[i])
}
return f
}

func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(5, pcs[:])
var st stack = pcs[0:n]
return &st
}
2 changes: 1 addition & 1 deletion server.go
Expand Up @@ -1300,7 +1300,7 @@ func (s *Server) processUnaryRPC(method string, t transport.ServerTransport, str
appStatus, ok := status.FromError(appErr)
if !ok {
// Convert appErr if it is not a grpc status error.
appStatus = status.ErrorWithStacks(codes.Unknown, appErr)
appStatus = status.ErrorWithoutStacks(appStatus.Code(), appErr)
}
if trInfo != nil {
trInfo.tr.LazyLog(stringer(appStatus.Message()), true)
Expand Down
6 changes: 3 additions & 3 deletions status/status.go
Expand Up @@ -63,13 +63,13 @@ func Error(c codes.Code, msg string) error {
}

// Error returns an error representing c and msg. If c is OK, returns nil.
func ErrorWithStacks(c codes.Code, e error) *Status {
return status.NewWithStacks(c, e)
func ErrorWithoutStacks(c codes.Code, e error) *Status {
return status.NewWithoutStacks(c, e)
}

// Errorf returns Error(c, fmt.Sprintf(format, a...)).
func Errorf(c codes.Code, format string, a ...interface{}) error {
return Error(c, fmt.Sprintf(format, a...))
return New(c, fmt.Sprintf(format, a...)).Err()
}

// ErrorProto returns an error representing s. If s.Code is OK, returns nil.
Expand Down

0 comments on commit 4678adc

Please sign in to comment.