err := status.Error(codes.NotFound, "id was not found")
return nil, err
st, ok := status.FromError(err)
if !ok {
//不含状态码的错误处理
}
//使用st.Message(),和st.Code()方法分别读取错误信息和错误码
st := status.New(code.NotFound, "id was not found")
d := &errdetails.LocalizedMessage{
Locale: "en-US",
Message: fmt.Sprintf("we couldn't find a user with the email address: %s", id),
}
var err error
st, err = st.WithDetails(d)
if err != nil {
panic(fmt.Sprintf("Unexpected error attaching metadata: %v", err))
}
return st.Err()
st := status.Convert(err)
for _, detail := range st.Details() {
switch t := detail.(type) {
case *errdetails.LocalizedMessage:
//将t.Message发送给用户
}
}
proglog/api/v1/error.go
package log_v1
import (
"fmt"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/status"
)
type ErrOutOfRange struct {
Offset uint64
}
func (e ErrOutOfRange) GRPCStatus() *status.Status {
st := status.New(
404,
fmt.Sprintf("offset out of range: %d", e.Offset),
)
msg := fmt.Sprintf("the request offset is outside the log's range: %d", e.Offset)
d := &errdetails.LocalizedMessage{
Locale: "en-US",
Message: msg,
}
std, err := st.WithDetails(d)
if err != nil {
return st
}
return std
}
func (e ErrOutOfRange) Error() string {
return e.GRPCStatus().Err().Error()
}
if s == nil || s.nextOffset < off {
return nil, fmt.Error("offset out of range: "%d", off)
}
将返回错误更新如下:
if s == nil || s.nextOffset < off {return nil, api.ErrOutOfRange{Offset: off}
}
return s.Read(off)
func testOutOfRangeErr(t *testing.T, log *Log) {
read, err := log.Read(1)
require.Nil(t, read)
apiError := err.(api.ErrOutOfRange)
require.Equal(t, uint64(1), apiError.Offset)
}
func (s *grpcServer) ConsumeStream(req *api.ConsumeRequest, stream api.Log_ConsumeStreamServer) error {
for {
select {
case <-stream.Context().Done():
return nil
default:
res, err := s.Consume(stream.Context(), req)
switch err.(type) {
case nil:
case api.ErrOutOfRange:
continue
default:
return err
}
if err = stream.Send(res); err != nil {
return err
}
eq.Offset++
}
}
}