diff --git a/examples/features/debugging/README.md b/examples/features/debugging/README.md new file mode 100644 index 00000000..00898993 --- /dev/null +++ b/examples/features/debugging/README.md @@ -0,0 +1,29 @@ +# Debugging + +Currently, grpc provides two major tools to help user debug issues, which are logging and channelz. + +## Logs +gRPC has put substantial logging instruments on critical paths of gRPC to help users debug issues. +The [Log Levels](https://github.com/grpc/grpc-go/blob/master/Documentation/log_levels.md) doc describes +what each log level means in the gRPC context. + +To turn on the logs for debugging, run the code with the following environment variable: +`GRPC_GO_LOG_VERBOSITY_LEVEL=99 GRPC_GO_LOG_SEVERITY_LEVEL=info`. + +## Channelz +We also provides a runtime debugging tool, Channelz, to help users with live debugging. + +See the channelz blog post here ([link](https://grpc.io/blog/a_short_introduction_to_channelz)) for +details about how to use channelz service to debug live program. + +## Try it +The example is able to showcase how logging and channelz can help with debugging. See the channelz +blog post linked above for full explanation. + +``` +go run server/main.go +``` + +``` +go run client/main.go +``` \ No newline at end of file diff --git a/examples/features/debugging/client/main.go b/examples/features/debugging/client/main.go new file mode 100644 index 00000000..9ecb30ee --- /dev/null +++ b/examples/features/debugging/client/main.go @@ -0,0 +1,89 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Binary client is an example client. +package main + +import ( + "log" + "net" + "os" + "time" + + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/channelz/service" + pb "google.golang.org/grpc/examples/helloworld/helloworld" + "google.golang.org/grpc/resolver" + "google.golang.org/grpc/resolver/manual" +) + +const ( + defaultName = "world" +) + +func main() { + /***** Set up the server serving channelz service. *****/ + lis, err := net.Listen("tcp", ":50052") + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + defer lis.Close() + s := grpc.NewServer() + service.RegisterChannelzServiceToServer(s) + go s.Serve(lis) + defer s.Stop() + + /***** Initialize manual resolver and Dial *****/ + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + // Set up a connection to the server. + conn, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + // Manually provide resolved addresses for the target. + r.NewAddress([]resolver.Address{{Addr: ":10001"}, {Addr: ":10002"}, {Addr: ":10003"}}) + + c := pb.NewGreeterClient(conn) + + // Contact the server and print out its response. + name := defaultName + if len(os.Args) > 1 { + name = os.Args[1] + } + + /***** Make 100 SayHello RPCs *****/ + for i := 0; i < 100; i++ { + // Setting a 150ms timeout on the RPC. + ctx, cancel := context.WithTimeout(context.Background(), 150*time.Millisecond) + defer cancel() + r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) + if err != nil { + log.Printf("could not greet: %v", err) + } else { + log.Printf("Greeting: %s", r.Message) + } + } + + /***** Wait for user exiting the program *****/ + // Unless you exit the program (e.g. CTRL+C), channelz data will be available for querying. + // Users can take time to examine and learn about the info provided by channelz. + select {} +} diff --git a/examples/features/debugging/server/main.go b/examples/features/debugging/server/main.go new file mode 100644 index 00000000..8dab454d --- /dev/null +++ b/examples/features/debugging/server/main.go @@ -0,0 +1,86 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Binary server is an example server. +package main + +import ( + "log" + "net" + "time" + + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/channelz/service" + pb "google.golang.org/grpc/examples/helloworld/helloworld" + "google.golang.org/grpc/internal/grpcrand" +) + +var ( + ports = []string{":10001", ":10002", ":10003"} +) + +// server is used to implement helloworld.GreeterServer. +type server struct{} + +// SayHello implements helloworld.GreeterServer +func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + return &pb.HelloReply{Message: "Hello " + in.Name}, nil +} + +// slow server is used to simulate a server that has a variable delay in its response. +type slowServer struct{} + +// SayHello implements helloworld.GreeterServer +func (s *slowServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + // Delay 100ms ~ 200ms before replying + time.Sleep(time.Duration(100+grpcrand.Intn(100)) * time.Millisecond) + return &pb.HelloReply{Message: "Hello " + in.Name}, nil +} + +func main() { + /***** Set up the server serving channelz service. *****/ + lis, err := net.Listen("tcp", ":50051") + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + defer lis.Close() + s := grpc.NewServer() + service.RegisterChannelzServiceToServer(s) + go s.Serve(lis) + defer s.Stop() + + /***** Start three GreeterServers(with one of them to be the slowServer). *****/ + for i := 0; i < 3; i++ { + lis, err := net.Listen("tcp", ports[i]) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + defer lis.Close() + s := grpc.NewServer() + if i == 2 { + pb.RegisterGreeterServer(s, &slowServer{}) + } else { + pb.RegisterGreeterServer(s, &server{}) + } + go s.Serve(lis) + } + + /***** Wait for user exiting the program *****/ + select {} +}