status.go (4549B)
1 /* 2 * 3 * Copyright 2017 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package status implements errors returned by gRPC. These errors are 20 // serialized and transmitted on the wire between server and client, and allow 21 // for additional data to be transmitted via the Details field in the status 22 // proto. gRPC service handlers should return an error created by this 23 // package, and gRPC clients should expect a corresponding error to be 24 // returned from the RPC call. 25 // 26 // This package upholds the invariants that a non-nil error may not 27 // contain an OK code, and an OK code must result in a nil error. 28 package status 29 30 import ( 31 "context" 32 "errors" 33 "fmt" 34 35 spb "google.golang.org/genproto/googleapis/rpc/status" 36 37 "google.golang.org/grpc/codes" 38 "google.golang.org/grpc/internal/status" 39 ) 40 41 // Status references google.golang.org/grpc/internal/status. It represents an 42 // RPC status code, message, and details. It is immutable and should be 43 // created with New, Newf, or FromProto. 44 // https://godoc.org/google.golang.org/grpc/internal/status 45 type Status = status.Status 46 47 // New returns a Status representing c and msg. 48 func New(c codes.Code, msg string) *Status { 49 return status.New(c, msg) 50 } 51 52 // Newf returns New(c, fmt.Sprintf(format, a...)). 53 func Newf(c codes.Code, format string, a ...interface{}) *Status { 54 return New(c, fmt.Sprintf(format, a...)) 55 } 56 57 // Error returns an error representing c and msg. If c is OK, returns nil. 58 func Error(c codes.Code, msg string) error { 59 return New(c, msg).Err() 60 } 61 62 // Errorf returns Error(c, fmt.Sprintf(format, a...)). 63 func Errorf(c codes.Code, format string, a ...interface{}) error { 64 return Error(c, fmt.Sprintf(format, a...)) 65 } 66 67 // ErrorProto returns an error representing s. If s.Code is OK, returns nil. 68 func ErrorProto(s *spb.Status) error { 69 return FromProto(s).Err() 70 } 71 72 // FromProto returns a Status representing s. 73 func FromProto(s *spb.Status) *Status { 74 return status.FromProto(s) 75 } 76 77 // FromError returns a Status representation of err. 78 // 79 // - If err was produced by this package or implements the method `GRPCStatus() 80 // *Status`, or if err wraps a type satisfying this, the appropriate Status is 81 // returned. For wrapped errors, the message returned contains the entire 82 // err.Error() text and not just the wrapped status. 83 // 84 // - If err is nil, a Status is returned with codes.OK and no message. 85 // 86 // - Otherwise, err is an error not compatible with this package. In this 87 // case, a Status is returned with codes.Unknown and err's Error() message, 88 // and ok is false. 89 func FromError(err error) (s *Status, ok bool) { 90 if err == nil { 91 return nil, true 92 } 93 type grpcstatus interface{ GRPCStatus() *Status } 94 if gs, ok := err.(grpcstatus); ok { 95 return gs.GRPCStatus(), true 96 } 97 var gs grpcstatus 98 if errors.As(err, &gs) { 99 p := gs.GRPCStatus().Proto() 100 p.Message = err.Error() 101 return status.FromProto(p), true 102 } 103 return New(codes.Unknown, err.Error()), false 104 } 105 106 // Convert is a convenience function which removes the need to handle the 107 // boolean return value from FromError. 108 func Convert(err error) *Status { 109 s, _ := FromError(err) 110 return s 111 } 112 113 // Code returns the Code of the error if it is a Status error or if it wraps a 114 // Status error. If that is not the case, it returns codes.OK if err is nil, or 115 // codes.Unknown otherwise. 116 func Code(err error) codes.Code { 117 // Don't use FromError to avoid allocation of OK status. 118 if err == nil { 119 return codes.OK 120 } 121 122 return Convert(err).Code() 123 } 124 125 // FromContextError converts a context error or wrapped context error into a 126 // Status. It returns a Status with codes.OK if err is nil, or a Status with 127 // codes.Unknown if err is non-nil and not a context error. 128 func FromContextError(err error) *Status { 129 if err == nil { 130 return nil 131 } 132 if errors.Is(err, context.DeadlineExceeded) { 133 return New(codes.DeadlineExceeded, err.Error()) 134 } 135 if errors.Is(err, context.Canceled) { 136 return New(codes.Canceled, err.Error()) 137 } 138 return New(codes.Unknown, err.Error()) 139 }