-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add sample code for setting and reading error details #506
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Setting and Reading Error Details | ||
|
||
gRPC servers return a single error value in response to client requests. | ||
The error value contains an error code and a description. In some cases more | ||
details regarding the error are required in order to take action. The recommended | ||
way to specify error details is by attaching metadata in the HTTP/2 trailers | ||
on the server and reading that metadata from the client. | ||
|
||
The examples in this directory demonstrate how to set and read error details using | ||
metadata attached in HTTP/2 trailers. | ||
|
||
## Background | ||
|
||
For this sample, we've already generated the server and client stubs from [helloworld.proto](helloworld/helloworld.proto). | ||
|
||
## Install | ||
|
||
``` | ||
$ go get -u google.golang.org/grpc/examples/error_metadata/greeter_client | ||
$ go get -u google.golang.org/grpc/examples/error_metadata/greeter_server | ||
``` | ||
|
||
## Try It! | ||
|
||
Run the server | ||
|
||
``` | ||
$ greeter_server & | ||
``` | ||
|
||
Run the client | ||
|
||
``` | ||
$ greeter_client | ||
``` | ||
|
||
``` | ||
Greeting: Hello world | ||
``` | ||
|
||
Run the client again | ||
|
||
``` | ||
$ greeter_client | ||
``` | ||
|
||
``` | ||
Could not greet: rpc error: code = 8 desc = "Request limit exceeded." | ||
Error details: | ||
count: 2 | ||
message: Limit one greeting per person. | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* | ||
* Copyright 2016, Google Inc. | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following disclaimer | ||
* in the documentation and/or other materials provided with the | ||
* distribution. | ||
* * Neither the name of Google Inc. nor the names of its | ||
* contributors may be used to endorse or promote products derived from | ||
* this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
*/ | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
|
||
pb "google.golang.org/grpc/examples/error_metadata/helloworld" | ||
|
||
"golang.org/x/net/context" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/metadata" | ||
) | ||
|
||
const ( | ||
address = "localhost:50051" | ||
defaultName = "world" | ||
) | ||
|
||
func main() { | ||
// Set up a connection to the server. | ||
conn, err := grpc.Dial(address, grpc.WithInsecure()) | ||
if err != nil { | ||
log.Fatalf("did not connect: %v", err) | ||
} | ||
defer conn.Close() | ||
c := pb.NewGreeterClient(conn) | ||
|
||
// Contact the server and print out its response. | ||
name := defaultName | ||
if len(os.Args) > 1 { | ||
name = os.Args[1] | ||
} | ||
|
||
// Set up md to hold the metadata returned from the server. | ||
md := metadata.Pairs() | ||
|
||
// Contact the server and capture the trailer metadata in md using a call option. | ||
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name}, grpc.Trailer(&md)) | ||
if err != nil { | ||
fmt.Printf("Could not greet: %v\n", err) | ||
|
||
// Print the error details returned in response trailers. | ||
fmt.Println("Error details:") | ||
for k, v := range md { | ||
fmt.Printf(" %s: %s\n", k, v[0]) | ||
} | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Printf("Greeting: %s\n", r.Message) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* | ||
* Copyright 2016, Google Inc. | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following disclaimer | ||
* in the documentation and/or other materials provided with the | ||
* distribution. | ||
* * Neither the name of Google Inc. nor the names of its | ||
* contributors may be used to endorse or promote products derived from | ||
* this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
*/ | ||
|
||
package main | ||
|
||
import ( | ||
"log" | ||
"net" | ||
"strconv" | ||
|
||
pb "google.golang.org/grpc/examples/error_metadata/helloworld" | ||
|
||
"golang.org/x/net/context" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/metadata" | ||
) | ||
|
||
const ( | ||
port = ":50051" | ||
) | ||
|
||
// server is used to implement helloworld.GreeterServer. | ||
type server struct { | ||
count map[string]int | ||
} | ||
|
||
// SayHello implements helloworld.GreeterServer | ||
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { | ||
// Track the number of times the user has been greeted. | ||
s.count[in.Name] += 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the goal of this example is to demonstrate how to set and read error details. I am wondering if involving metadata handling makes it over complicated. BTW, you need mutex to guard the access of s.count. It is racy if you have multiple concurrent clients. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re: metadata, see grpc/grpc#4543, whose Go version this PR is trying to solve. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Then I need think through how this can be achieved in a nice way. |
||
|
||
// Return an error with details using the response trailer. | ||
if s.count[in.Name] > 1 { | ||
m := make(map[string]string) | ||
m["message"] = "Limit one greeting per person." | ||
m["count"] = strconv.Itoa(s.count[in.Name]) | ||
md := metadata.New(m) | ||
grpc.SetTrailer(ctx, md) | ||
|
||
return nil, grpc.Errorf(codes.ResourceExhausted, "Request limit exceeded.") | ||
} | ||
|
||
return &pb.HelloReply{Message: "Hello " + in.Name}, nil | ||
} | ||
|
||
func main() { | ||
lis, err := net.Listen("tcp", port) | ||
if err != nil { | ||
log.Fatalf("failed to listen: %v", err) | ||
} | ||
s := grpc.NewServer() | ||
|
||
cm := make(map[string]int) | ||
pb.RegisterGreeterServer(s, &server{cm}) | ||
s.Serve(lis) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one thing I was trying to figure out is that:
is this error a rpc error from server side or this is a client-side/network error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the best way to check that would be to test the error code:
From the docs:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what I am doing. However, in the doc it also says https://github.com/grpc/grpc-go/blob/master/codes/codes.go#L53.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Network errors should be
Unavailable
IIRC.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
checking error code is not right way to differentiate client and server side errors. The common practice is that the server application need pack a bit more info into the error description (e.g., serialized error protobuf).