github.com/bazelbuild/remote-apis-sdks@v0.0.0-20240425170053-8a36686a6350/go/pkg/client/status.go (about) 1 package client 2 3 import ( 4 "fmt" 5 "strings" 6 7 "google.golang.org/grpc/status" 8 "google.golang.org/protobuf/encoding/prototext" 9 "google.golang.org/protobuf/proto" 10 11 _ "google.golang.org/genproto/googleapis/rpc/errdetails" // the proto needs to be compiled in for unmarshalling of status details. 12 ) 13 14 // StatusError is the same as status.Error except it includes the error details in the error message. 15 type StatusError struct { 16 st *status.Status 17 details string 18 } 19 20 // StatusDetailedError creates a StatusError from Status, which is the same as st.Err() except it includes the error details in the error message. 21 func StatusDetailedError(st *status.Status) *StatusError { 22 var details []string 23 for _, d := range st.Details() { 24 s := fmt.Sprintf("%+v", d) 25 if pb, ok := d.(proto.Message); ok { 26 s = prototext.Format(pb) 27 } 28 details = append(details, s) 29 } 30 return &StatusError{st, strings.Join(details, "; ")} 31 } 32 33 func (e *StatusError) Error() string { 34 msg := fmt.Sprintf("rpc error: code = %s desc = %s", e.st.Code(), e.st.Message()) 35 if e.details != "" { 36 msg += " details = " + e.details 37 } 38 return msg 39 } 40 41 // GRPCStatus returns the Status represented by e. 42 func (e *StatusError) GRPCStatus() *status.Status { 43 return e.st 44 } 45 46 // Is implements error.Is functionality. 47 // A StatusError is equivalent if the code and message are identical. 48 func (e *StatusError) Is(target error) bool { 49 if tse, ok := target.(*StatusError); ok { 50 return proto.Equal(e.st.Proto(), tse.st.Proto()) 51 } 52 if tst, ok := status.FromError(target); ok { 53 return proto.Equal(e.st.Proto(), tst.Proto()) 54 } 55 return false 56 }