go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/grpc/appstatus/status.go (about) 1 // Copyright 2019 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package appstatus 16 17 import ( 18 "google.golang.org/grpc/codes" 19 "google.golang.org/grpc/status" 20 21 "go.chromium.org/luci/common/errors" 22 ) 23 24 var appStatusTagKey = errors.NewTagKey("application-specific response status") 25 26 // ToError converts an application-specific status to an error. 27 func ToError(s *status.Status) error { 28 return Attach(s.Err(), s) 29 } 30 31 // Error returns an error with an application-specific status. 32 // The message will be shared with the RPC client as is. 33 func Error(code codes.Code, msg string) error { 34 return ToError(status.New(code, msg)) 35 } 36 37 // Errorf returns an error with an application-specific status. 38 // The message will be shared with the RPC client as is. 39 func Errorf(code codes.Code, format string, args ...any) error { 40 return ToError(status.Newf(code, format, args...)) 41 } 42 43 // Attach attaches an application-specific status to the error. 44 // The status will be shared with the RPC client as is. 45 // If err already has an application-specific status attached, panics. 46 func Attach(err error, status *status.Status) error { 47 if status.Code() == codes.OK { 48 panic("cannot attach an OK status") 49 } 50 51 if _, ok := Get(err); ok { 52 panic("err already has an application-specific status") 53 } 54 55 tag := errors.TagValue{ 56 Key: appStatusTagKey, 57 Value: status, 58 } 59 return errors.Annotate(err, "attaching a status").Tag(tag).Err() 60 } 61 62 // Attachf is a shortcut for Attach(err, status.Newf(...)) 63 func Attachf(err error, code codes.Code, format string, args ...any) error { 64 return Attach(err, status.Newf(code, format, args...)) 65 } 66 67 // Get returns an application-specific Status attached to err using this 68 // package. If not explicitly set or if err is nil, then ok is false. 69 func Get(err error) (st *status.Status, ok bool) { 70 v, ok := errors.TagValueIn(appStatusTagKey, err) 71 if !ok { 72 return nil, false 73 } 74 75 return v.(*status.Status), true 76 }